diff --git a/.markdown-link-check.json b/.markdown-link-check.json index c93c6753..5d6c8770 100644 --- a/.markdown-link-check.json +++ b/.markdown-link-check.json @@ -1,5 +1,22 @@ { "projectBaseUrl": ".", + "ignorePatterns": [ + { + "pattern": "^https://dev\\.mysql\\.com/" + }, + { + "pattern": "^https://stackoverflow\\.com/" + }, + { + "pattern": "^https://security\\.stackexchange\\.com/" + }, + { + "pattern": "^https://code\\.tutsplus\\.com/" + }, + { + "pattern": "^https://yiiframework\\.ru/" + } + ], "replacementPatterns": [ { "pattern": "^/", diff --git a/_translations/po/es/cookbook_organizing-code_service.md.po b/_translations/po/es/cookbook_organizing-code_service.md.po index 35a3a188..7ac57ac6 100644 --- a/_translations/po/es/cookbook_organizing-code_service.md.po +++ b/_translations/po/es/cookbook_organizing-code_service.md.po @@ -17,15 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. type: Bullet: '- ' -#: ../src/cookbook/organizing-code/domain.md -#: ../src/cookbook/organizing-code/service.md +#: ../src/cookbook/organizing-code/domain.md ../src/cookbook/organizing-code/service.md #, no-wrap msgid "Entity" msgstr "" #. type: Title ## -#: ../src/cookbook/organizing-code/domain.md -#: ../src/cookbook/organizing-code/service.md ../src/guide/start/databases.md +#: ../src/cookbook/organizing-code/domain.md ../src/cookbook/organizing-code/service.md ../src/guide/start/databases.md #, no-wrap msgid "Repository" msgstr "" @@ -267,5 +265,5 @@ msgstr "" #. type: Bullet: '- ' #: ../src/cookbook/organizing-code/service.md -msgid "[Middleware](middleware.md)" +msgid "[Middleware](../../guide/structure/middleware.md)" msgstr "" diff --git a/_translations/po/es/guide_caching_data.md.po b/_translations/po/es/guide_caching_data.md.po index 9ef94778..6e75c07a 100644 --- a/_translations/po/es/guide_caching_data.md.po +++ b/_translations/po/es/guide_caching_data.md.po @@ -24,7 +24,7 @@ msgstr "" #. type: Plain text #: ../../guide/en/caching/data.md -msgid "Data caching is about storing some PHP variables in a cache and retrieving them later from the cache. It's also the foundation for more advanced caching features, such as [page caching](page.md)." +msgid "Data caching is about storing some PHP variables in a cache and retrieving them later from the cache. It's also the foundation for more advanced caching features, such as page caching." msgstr "" #. type: Plain text @@ -99,7 +99,7 @@ msgstr "" #. type: Bullet: '- ' #: ../../guide/en/caching/data.md -msgid "[APCu](https://github.com/yiisoft/cache-apcu) - uses a PHP [APC](https://secure.php.net/manual/en/book.apc.php) extension. You can consider this option as the fastest one when dealing with cache for a centralized thick application (e.g., one server, no dedicated load balancers, etc.)." +msgid "[APCu](https://github.com/yiisoft/cache-apcu) - uses a PHP [APC](https://www.php.net/manual/en/book.apcu.php) extension. You can consider this option as the fastest one when dealing with cache for a centralized thick application (e.g., one server, no dedicated load balancers, etc.)." msgstr "" #. type: Bullet: '- ' diff --git a/_translations/po/es/guide_caching_overview.md.po b/_translations/po/es/guide_caching_overview.md.po index ecb3f060..1fcf1ca5 100644 --- a/_translations/po/es/guide_caching_overview.md.po +++ b/_translations/po/es/guide_caching_overview.md.po @@ -44,15 +44,15 @@ msgstr "" #. type: Bullet: '* ' #: ../src/guide/caching/overview.md -msgid "[Fragment caching](fragment.md)" +msgid "Fragment caching" msgstr "" #. type: Bullet: '* ' #: ../src/guide/caching/overview.md -msgid "[Page caching](page.md)" +msgid "Page caching" msgstr "" #. type: Bullet: '* ' #: ../src/guide/caching/overview.md -msgid "[HTTP caching](http.md)" +msgid "HTTP caching" msgstr "" diff --git a/_translations/po/es/guide_glossary.md.po b/_translations/po/es/guide_glossary.md.po index 222be501..bf63cdbb 100644 --- a/_translations/po/es/guide_glossary.md.po +++ b/_translations/po/es/guide_glossary.md.po @@ -467,7 +467,7 @@ msgstr "" #. type: Plain text #: ../src/guide/glossary.md -msgid "Service is a focused object that performs application work or provides infrastructure behavior and is usually stored in the DI container. Read more in [\"Service components\"](structure/service.md)." +msgid "Service is a focused object that performs application work or provides infrastructure behavior and is usually stored in the DI container. Read more in [\"Service components\"](../cookbook/organizing-code/service.md)." msgstr "" #. type: Title ## diff --git a/_translations/po/es/guide_security_best-practices.md.po b/_translations/po/es/guide_security_best-practices.md.po index b7e0c224..7e559980 100644 --- a/_translations/po/es/guide_security_best-practices.md.po +++ b/_translations/po/es/guide_security_best-practices.md.po @@ -17,12 +17,7 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. type: Title ## -#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md -#: ../src/guide/concept/autoloading.md ../src/guide/concept/di-container.md -#: ../src/guide/security/best-practices.md ../src/guide/structure/domain.md -#: ../src/guide/tutorial/console-applications.md -#: ../src/internals/004-namespaces.md ../src/internals/007-exceptions.md -#: ../src/internals/008-interfaces.md +#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md ../src/guide/concept/autoloading.md ../src/guide/concept/di-container.md ../src/guide/security/best-practices.md ../src/guide/structure/domain.md ../src/guide/tutorial/console-applications.md ../src/internals/004-namespaces.md ../src/internals/007-exceptions.md ../src/internals/008-interfaces.md #, no-wrap msgid "References" msgstr "Referencias" @@ -241,7 +236,7 @@ msgstr "" #. type: Plain text #: ../src/guide/security/best-practices.md -msgid "If it should be HTML, you could get some help from [HtmlPurifier](http://htmlpurifier.org/). Note that HtmlPurifier processing is quite heavy, so consider adding caching." +msgid "If it should be HTML, you could get some help from [HtmlPurifier](https://github.com/ezyang/htmlpurifier). Note that HtmlPurifier processing is quite heavy, so consider adding caching." msgstr "" #. type: Title ## @@ -359,12 +354,12 @@ msgstr "" #. type: Bullet: '- ' #: ../src/guide/security/best-practices.md -msgid "" +msgid "" msgstr "" #. type: Bullet: '- ' #: ../src/guide/security/best-practices.md -msgid "" +msgid "" msgstr "" #. type: Title ## diff --git a/_translations/po/es/guide_start_hello.md.po b/_translations/po/es/guide_start_hello.md.po index ce84fb30..80e76490 100644 --- a/_translations/po/es/guide_start_hello.md.po +++ b/_translations/po/es/guide_start_hello.md.po @@ -17,9 +17,7 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. type: Title ## -#: ../src/cookbook/deployment/docker-swarm-caddy.md -#: ../src/cookbook/deployment/docker-swarm-traefik.md -#: ../src/guide/start/forms.md ../src/guide/start/hello.md +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md ../src/guide/start/forms.md ../src/guide/start/hello.md #, no-wrap msgid "Summary" msgstr "" @@ -43,7 +41,7 @@ msgstr "" #. type: Plain text #: ../src/guide/start/hello.md -msgid "To achieve this goal, you will define a route and create [a handler](../structure/handler.md) that does the job and forms the response. Then you will improve it to use [view](../views/view.md) for building the response." +msgid "To achieve this goal, you will define a route and create [a handler](../structure/action.md) that does the job and forms the response. Then you will improve it to use [view](../views/view.md) for building the response." msgstr "" #. type: Plain text diff --git a/_translations/po/es/guide_structure_overview.md.po b/_translations/po/es/guide_structure_overview.md.po index 78de4139..46ad1ec0 100644 --- a/_translations/po/es/guide_structure_overview.md.po +++ b/_translations/po/es/guide_structure_overview.md.po @@ -17,8 +17,7 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. type: Title ## -#: ../src/en/guide/structure/overview.md -#: ../src/en/guide/views/script-style-meta.md +#: ../src/en/guide/structure/overview.md ../src/en/guide/views/script-style-meta.md #, no-wrap msgid "Overview" msgstr "" @@ -137,7 +136,7 @@ msgstr "" #. type: Plain text #: ../src/en/guide/structure/overview.md -msgid "A context may have [an entry point known as \"action\" or \"controller\"](action.md). Its job is to take [a request instance](../runtime/request.md), pass it to [domain layer](domain.md) in a suitable format, and create [a response](../runtime/response.md) based on domain layer return." +msgid "A context may have [an entry point known as \"action\" or \"controller\"](action.md). Its job is to take [a request instance](../runtime/request.md), pass it to [domain layer](../../cookbook/organizing-code/domain.md) in a suitable format, and create [a response](../runtime/response.md) based on domain layer return." msgstr "" #. type: Plain text @@ -152,7 +151,7 @@ msgstr "" #. type: Bullet: '* ' #: ../src/en/guide/structure/overview.md -msgid "[services](service.md): they're typically stateless objects registered within dependency container and provide various action methods." +msgid "[services](../../cookbook/organizing-code/service.md): they're typically stateless objects registered within dependency container and provide various action methods." msgstr "" #. type: Bullet: '* ' diff --git a/_translations/po/es/internals_014-docs.md.po b/_translations/po/es/internals_014-docs.md.po index 201e8218..a9a59caa 100644 --- a/_translations/po/es/internals_014-docs.md.po +++ b/_translations/po/es/internals_014-docs.md.po @@ -68,7 +68,7 @@ msgstr "La Guía Definitiva de Yii 3.0" #. type: Plain text #: ../src/internals/014-docs.md -msgid "The definitive guide, [yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/guide/en) aims at covering usage of packages as a whole framework. Unlike package documentation, it isn't focused on a single package but is covering certain use-cases." +msgid "The definitive guide, [yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/src/guide) aims at covering usage of packages as a whole framework. Unlike package documentation, it isn't focused on a single package but is covering certain use-cases." msgstr "" #. type: Plain text diff --git a/_translations/po/id/cookbook_organizing-code_service.md.po b/_translations/po/id/cookbook_organizing-code_service.md.po index b0dd1ee2..c125327f 100644 --- a/_translations/po/id/cookbook_organizing-code_service.md.po +++ b/_translations/po/id/cookbook_organizing-code_service.md.po @@ -16,15 +16,13 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" #. type: Bullet: '- ' -#: ../src/cookbook/organizing-code/domain.md -#: ../src/cookbook/organizing-code/service.md +#: ../src/cookbook/organizing-code/domain.md ../src/cookbook/organizing-code/service.md #, no-wrap msgid "Entity" msgstr "" #. type: Title ## -#: ../src/cookbook/organizing-code/domain.md -#: ../src/cookbook/organizing-code/service.md ../src/guide/start/databases.md +#: ../src/cookbook/organizing-code/domain.md ../src/cookbook/organizing-code/service.md ../src/guide/start/databases.md #, no-wrap msgid "Repository" msgstr "" @@ -195,5 +193,5 @@ msgstr "" #. type: Bullet: '- ' #: ../src/cookbook/organizing-code/service.md -msgid "[Middleware](middleware.md)" +msgid "[Middleware](../../guide/structure/middleware.md)" msgstr "" diff --git a/_translations/po/id/guide_caching_data.md.po b/_translations/po/id/guide_caching_data.md.po index 5951b68a..777b2139 100644 --- a/_translations/po/id/guide_caching_data.md.po +++ b/_translations/po/id/guide_caching_data.md.po @@ -24,10 +24,10 @@ msgstr "Caching data" #. type: Plain text #: ../../guide/en/caching/data.md -msgid "Data caching is about storing some PHP variables in a cache and retrieving them later from the cache. It's also the foundation for more advanced caching features, such as [page caching](page.md)." +msgid "Data caching is about storing some PHP variables in a cache and retrieving them later from the cache. It's also the foundation for more advanced caching features, such as page caching." msgstr "" "Caching data adalah tentang menyimpan beberapa variabel PHP ke dalam cache dan mengambilnya kembali dari cache.\n" -"Ini juga menjadi fondasi untuk fitur caching yang lebih lanjut, seperti [caching halaman](page.md)." +"Ini juga menjadi fondasi untuk fitur caching yang lebih lanjut, seperti caching halaman." #. type: Plain text #: ../../guide/en/caching/data.md @@ -137,9 +137,9 @@ msgstr "`ArrayCache` — menyediakan caching hanya untuk permintaan saat ini den #. type: Bullet: '- ' #: ../../guide/en/caching/data.md -msgid "[APCu](https://github.com/yiisoft/cache-apcu) - uses a PHP [APC](https://secure.php.net/manual/en/book.apc.php) extension. You can consider this option as the fastest one when dealing with cache for a centralized thick application (e.g., one server, no dedicated load balancers, etc.)." +msgid "[APCu](https://github.com/yiisoft/cache-apcu) - uses a PHP [APC](https://www.php.net/manual/en/book.apcu.php) extension. You can consider this option as the fastest one when dealing with cache for a centralized thick application (e.g., one server, no dedicated load balancers, etc.)." msgstr "" -"[APCu](https://github.com/yiisoft/cache-apcu) — menggunakan ekstensi PHP [APC](https://secure.php.net/manual/en/book.apc.php).\n" +"[APCu](https://github.com/yiisoft/cache-apcu) — menggunakan ekstensi PHP [APC](https://www.php.net/manual/en/book.apcu.php).\n" " Ini bisa dianggap sebagai opsi tercepat saat berurusan dengan cache untuk aplikasi terpusat (mis., satu\n" " server, tanpa load balancer khusus, dll.)." diff --git a/_translations/po/id/guide_caching_overview.md.po b/_translations/po/id/guide_caching_overview.md.po index c6446e2f..7d9ce9aa 100644 --- a/_translations/po/id/guide_caching_overview.md.po +++ b/_translations/po/id/guide_caching_overview.md.po @@ -52,15 +52,15 @@ msgstr "[Data caching](data.md)" #. type: Bullet: '* ' #: ../src/guide/caching/overview.md -msgid "[Fragment caching](fragment.md)" -msgstr "[Fragment caching](fragment.md)" +msgid "Fragment caching" +msgstr "Fragment caching" #. type: Bullet: '* ' #: ../src/guide/caching/overview.md -msgid "[Page caching](page.md)" -msgstr "[Page caching](page.md)" +msgid "Page caching" +msgstr "Page caching" #. type: Bullet: '* ' #: ../src/guide/caching/overview.md -msgid "[HTTP caching](http.md)" -msgstr "[HTTP caching](http.md)" +msgid "HTTP caching" +msgstr "HTTP caching" diff --git a/_translations/po/id/guide_glossary.md.po b/_translations/po/id/guide_glossary.md.po index d3cf2441..93f19cd7 100644 --- a/_translations/po/id/guide_glossary.md.po +++ b/_translations/po/id/guide_glossary.md.po @@ -472,7 +472,7 @@ msgstr "" #. type: Plain text #: ../src/guide/glossary.md -msgid "Service is a focused object that performs application work or provides infrastructure behavior and is usually stored in the DI container. Read more in [\"Service components\"](structure/service.md)." +msgid "Service is a focused object that performs application work or provides infrastructure behavior and is usually stored in the DI container. Read more in [\"Service components\"](../cookbook/organizing-code/service.md)." msgstr "" #. type: Title ## diff --git a/_translations/po/id/guide_security_best-practices.md.po b/_translations/po/id/guide_security_best-practices.md.po index 0b1a553a..30d69ef4 100644 --- a/_translations/po/id/guide_security_best-practices.md.po +++ b/_translations/po/id/guide_security_best-practices.md.po @@ -16,12 +16,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" #. type: Title ## -#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md -#: ../src/guide/concept/autoloading.md ../src/guide/concept/di-container.md -#: ../src/guide/security/best-practices.md ../src/guide/structure/domain.md -#: ../src/guide/tutorial/console-applications.md -#: ../src/internals/004-namespaces.md ../src/internals/007-exceptions.md -#: ../src/internals/008-interfaces.md +#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md ../src/guide/concept/autoloading.md ../src/guide/concept/di-container.md ../src/guide/security/best-practices.md ../src/guide/structure/domain.md ../src/guide/tutorial/console-applications.md ../src/internals/004-namespaces.md ../src/internals/007-exceptions.md ../src/internals/008-interfaces.md #, no-wrap msgid "References" msgstr "Referensi" @@ -240,7 +235,7 @@ msgstr "" #. type: Plain text #: ../src/guide/security/best-practices.md -msgid "If it should be HTML, you could get some help from [HtmlPurifier](http://htmlpurifier.org/). Note that HtmlPurifier processing is quite heavy, so consider adding caching." +msgid "If it should be HTML, you could get some help from [HtmlPurifier](https://github.com/ezyang/htmlpurifier). Note that HtmlPurifier processing is quite heavy, so consider adding caching." msgstr "" #. type: Title ## @@ -358,12 +353,12 @@ msgstr "" #. type: Bullet: '- ' #: ../src/guide/security/best-practices.md -msgid "" +msgid "" msgstr "" #. type: Bullet: '- ' #: ../src/guide/security/best-practices.md -msgid "" +msgid "" msgstr "" #. type: Title ## diff --git a/_translations/po/id/guide_start_hello.md.po b/_translations/po/id/guide_start_hello.md.po index c4ffb409..1cdd3427 100644 --- a/_translations/po/id/guide_start_hello.md.po +++ b/_translations/po/id/guide_start_hello.md.po @@ -16,9 +16,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" #. type: Title ## -#: ../src/cookbook/deployment/docker-swarm-caddy.md -#: ../src/cookbook/deployment/docker-swarm-traefik.md -#: ../src/guide/start/forms.md ../src/guide/start/hello.md +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md ../src/guide/start/forms.md ../src/guide/start/hello.md #, no-wrap msgid "Summary" msgstr "" @@ -42,7 +40,7 @@ msgstr "" #. type: Plain text #: ../src/guide/start/hello.md -msgid "To achieve this goal, you will define a route and create [a handler](../structure/handler.md) that does the job and forms the response. Then you will improve it to use [view](../views/view.md) for building the response." +msgid "To achieve this goal, you will define a route and create [a handler](../structure/action.md) that does the job and forms the response. Then you will improve it to use [view](../views/view.md) for building the response." msgstr "" #. type: Plain text diff --git a/_translations/po/id/guide_structure_overview.md.po b/_translations/po/id/guide_structure_overview.md.po index aea11434..22a736a8 100644 --- a/_translations/po/id/guide_structure_overview.md.po +++ b/_translations/po/id/guide_structure_overview.md.po @@ -16,8 +16,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" #. type: Title ## -#: ../src/en/guide/structure/overview.md -#: ../src/en/guide/views/script-style-meta.md +#: ../src/en/guide/structure/overview.md ../src/en/guide/views/script-style-meta.md #, no-wrap msgid "Overview" msgstr "" @@ -136,7 +135,7 @@ msgstr "" #. type: Plain text #: ../src/en/guide/structure/overview.md -msgid "A context may have [an entry point known as \"action\" or \"controller\"](action.md). Its job is to take [a request instance](../runtime/request.md), pass it to [domain layer](domain.md) in a suitable format, and create [a response](../runtime/response.md) based on domain layer return." +msgid "A context may have [an entry point known as \"action\" or \"controller\"](action.md). Its job is to take [a request instance](../runtime/request.md), pass it to [domain layer](../../cookbook/organizing-code/domain.md) in a suitable format, and create [a response](../runtime/response.md) based on domain layer return." msgstr "" #. type: Plain text @@ -151,7 +150,7 @@ msgstr "" #. type: Bullet: '* ' #: ../src/en/guide/structure/overview.md -msgid "[services](service.md): they're typically stateless objects registered within dependency container and provide various action methods." +msgid "[services](../../cookbook/organizing-code/service.md): they're typically stateless objects registered within dependency container and provide various action methods." msgstr "" #. type: Bullet: '* ' diff --git a/_translations/po/id/internals_014-docs.md.po b/_translations/po/id/internals_014-docs.md.po index 3a5f44dd..46cc75a9 100644 --- a/_translations/po/id/internals_014-docs.md.po +++ b/_translations/po/id/internals_014-docs.md.po @@ -67,7 +67,7 @@ msgstr "Panduan Definitif untuk Yii 3.0" #. type: Plain text #: ../src/internals/014-docs.md -msgid "The definitive guide, [yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/guide/en) aims at covering usage of packages as a whole framework. Unlike package documentation, it isn't focused on a single package but is covering certain use-cases." +msgid "The definitive guide, [yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/src/guide) aims at covering usage of packages as a whole framework. Unlike package documentation, it isn't focused on a single package but is covering certain use-cases." msgstr "" #. type: Plain text diff --git a/_translations/po/it/cookbook_organizing-code_service.md.po b/_translations/po/it/cookbook_organizing-code_service.md.po index 24b3ea4f..9c80e817 100644 --- a/_translations/po/it/cookbook_organizing-code_service.md.po +++ b/_translations/po/it/cookbook_organizing-code_service.md.po @@ -17,15 +17,13 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. type: Bullet: '- ' -#: ../src/cookbook/organizing-code/domain.md -#: ../src/cookbook/organizing-code/service.md +#: ../src/cookbook/organizing-code/domain.md ../src/cookbook/organizing-code/service.md #, no-wrap msgid "Entity" msgstr "" #. type: Title ## -#: ../src/cookbook/organizing-code/domain.md -#: ../src/cookbook/organizing-code/service.md ../src/guide/start/databases.md +#: ../src/cookbook/organizing-code/domain.md ../src/cookbook/organizing-code/service.md ../src/guide/start/databases.md #, no-wrap msgid "Repository" msgstr "" @@ -224,5 +222,5 @@ msgstr "" #: ../src/cookbook/organizing-code/service.md #, fuzzy #| msgid "[Middleware](structure/middleware.md)" -msgid "[Middleware](middleware.md)" +msgid "[Middleware](../../guide/structure/middleware.md)" msgstr "[Middleware](structure/middleware.md)" diff --git a/_translations/po/it/guide_caching_data.md.po b/_translations/po/it/guide_caching_data.md.po index 5bfc2e6d..719bacc2 100644 --- a/_translations/po/it/guide_caching_data.md.po +++ b/_translations/po/it/guide_caching_data.md.po @@ -25,7 +25,7 @@ msgstr "Caching" #. type: Plain text #: ../../guide/en/caching/data.md -msgid "Data caching is about storing some PHP variables in a cache and retrieving them later from the cache. It's also the foundation for more advanced caching features, such as [page caching](page.md)." +msgid "Data caching is about storing some PHP variables in a cache and retrieving them later from the cache. It's also the foundation for more advanced caching features, such as page caching." msgstr "" #. type: Plain text @@ -100,7 +100,7 @@ msgstr "" #. type: Bullet: '- ' #: ../../guide/en/caching/data.md -msgid "[APCu](https://github.com/yiisoft/cache-apcu) - uses a PHP [APC](https://secure.php.net/manual/en/book.apc.php) extension. You can consider this option as the fastest one when dealing with cache for a centralized thick application (e.g., one server, no dedicated load balancers, etc.)." +msgid "[APCu](https://github.com/yiisoft/cache-apcu) - uses a PHP [APC](https://www.php.net/manual/en/book.apcu.php) extension. You can consider this option as the fastest one when dealing with cache for a centralized thick application (e.g., one server, no dedicated load balancers, etc.)." msgstr "" #. type: Bullet: '- ' diff --git a/_translations/po/it/guide_caching_overview.md.po b/_translations/po/it/guide_caching_overview.md.po index 8c57a7c8..de0327b7 100644 --- a/_translations/po/it/guide_caching_overview.md.po +++ b/_translations/po/it/guide_caching_overview.md.po @@ -48,19 +48,19 @@ msgstr "[Caching dei dati](caching/data.md)" #: ../src/guide/caching/overview.md #, fuzzy #| msgid "[Fragment caching](caching/fragment.md) TODO" -msgid "[Fragment caching](fragment.md)" +msgid "Fragment caching" msgstr "[Caching dei frammenti](caching/fragment.md) TODO" #. type: Bullet: '* ' #: ../src/guide/caching/overview.md #, fuzzy #| msgid "[Page caching](caching/page.md) TODO" -msgid "[Page caching](page.md)" +msgid "Page caching" msgstr "[Caching delle pagine](caching/page.md) TODO" #. type: Bullet: '* ' #: ../src/guide/caching/overview.md #, fuzzy #| msgid "[HTTP caching](caching/http.md) TODO" -msgid "[HTTP caching](http.md)" +msgid "HTTP caching" msgstr "[Caching HTTP](caching/http.md) TODO" diff --git a/_translations/po/it/guide_glossary.md.po b/_translations/po/it/guide_glossary.md.po index 470eafbb..ab421e75 100644 --- a/_translations/po/it/guide_glossary.md.po +++ b/_translations/po/it/guide_glossary.md.po @@ -468,7 +468,7 @@ msgstr "" #. type: Plain text #: ../src/guide/glossary.md -msgid "Service is a focused object that performs application work or provides infrastructure behavior and is usually stored in the DI container. Read more in [\"Service components\"](structure/service.md)." +msgid "Service is a focused object that performs application work or provides infrastructure behavior and is usually stored in the DI container. Read more in [\"Service components\"](../cookbook/organizing-code/service.md)." msgstr "" #. type: Title ## diff --git a/_translations/po/it/guide_security_best-practices.md.po b/_translations/po/it/guide_security_best-practices.md.po index 930b0fc8..e04654d8 100644 --- a/_translations/po/it/guide_security_best-practices.md.po +++ b/_translations/po/it/guide_security_best-practices.md.po @@ -17,12 +17,7 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. type: Title ## -#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md -#: ../src/guide/concept/autoloading.md ../src/guide/concept/di-container.md -#: ../src/guide/security/best-practices.md ../src/guide/structure/domain.md -#: ../src/guide/tutorial/console-applications.md -#: ../src/internals/004-namespaces.md ../src/internals/007-exceptions.md -#: ../src/internals/008-interfaces.md +#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md ../src/guide/concept/autoloading.md ../src/guide/concept/di-container.md ../src/guide/security/best-practices.md ../src/guide/structure/domain.md ../src/guide/tutorial/console-applications.md ../src/internals/004-namespaces.md ../src/internals/007-exceptions.md ../src/internals/008-interfaces.md #, no-wrap msgid "References" msgstr "" @@ -241,7 +236,7 @@ msgstr "" #. type: Plain text #: ../src/guide/security/best-practices.md -msgid "If it should be HTML, you could get some help from [HtmlPurifier](http://htmlpurifier.org/). Note that HtmlPurifier processing is quite heavy, so consider adding caching." +msgid "If it should be HTML, you could get some help from [HtmlPurifier](https://github.com/ezyang/htmlpurifier). Note that HtmlPurifier processing is quite heavy, so consider adding caching." msgstr "" #. type: Title ## @@ -359,12 +354,12 @@ msgstr "" #. type: Bullet: '- ' #: ../src/guide/security/best-practices.md -msgid "" +msgid "" msgstr "" #. type: Bullet: '- ' #: ../src/guide/security/best-practices.md -msgid "" +msgid "" msgstr "" #. type: Title ## diff --git a/_translations/po/it/guide_start_hello.md.po b/_translations/po/it/guide_start_hello.md.po index 48f67b11..9e7c392e 100644 --- a/_translations/po/it/guide_start_hello.md.po +++ b/_translations/po/it/guide_start_hello.md.po @@ -18,9 +18,7 @@ msgstr "" "X-Generator: Poedit 3.8\n" #. type: Title ## -#: ../src/cookbook/deployment/docker-swarm-caddy.md -#: ../src/cookbook/deployment/docker-swarm-traefik.md -#: ../src/guide/start/forms.md ../src/guide/start/hello.md +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md ../src/guide/start/forms.md ../src/guide/start/hello.md #, no-wrap msgid "Summary" msgstr "" @@ -44,8 +42,8 @@ msgstr "Questa sezione descrive come creare una nuova pagina “Hello” nella t #. type: Plain text #: ../src/guide/start/hello.md -msgid "To achieve this goal, you will define a route and create [a handler](../structure/handler.md) that does the job and forms the response. Then you will improve it to use [view](../views/view.md) for building the response." -msgstr "Per raggiungere questo obiettivo, definirai una rotta e creerai [un gestore di richieste](../structure/handler.md) che esegue il lavoro e forma la risposta. Poi lo migliorerai per usare [una vista](../views/view.md) per costruire la risposta." +msgid "To achieve this goal, you will define a route and create [a handler](../structure/action.md) that does the job and forms the response. Then you will improve it to use [view](../views/view.md) for building the response." +msgstr "Per raggiungere questo obiettivo, definirai una rotta e creerai [un gestore di richieste](../structure/action.md) che esegue il lavoro e forma la risposta. Poi lo migliorerai per usare [una vista](../views/view.md) per costruire la risposta." #. type: Plain text #: ../src/guide/start/hello.md diff --git a/_translations/po/it/guide_structure_overview.md.po b/_translations/po/it/guide_structure_overview.md.po index edb6c96e..635987d2 100644 --- a/_translations/po/it/guide_structure_overview.md.po +++ b/_translations/po/it/guide_structure_overview.md.po @@ -17,8 +17,7 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. type: Title ## -#: ../src/en/guide/structure/overview.md -#: ../src/en/guide/views/script-style-meta.md +#: ../src/en/guide/structure/overview.md ../src/en/guide/views/script-style-meta.md #, no-wrap msgid "Overview" msgstr "" @@ -139,7 +138,7 @@ msgstr "" #. type: Plain text #: ../src/en/guide/structure/overview.md -msgid "A context may have [an entry point known as \"action\" or \"controller\"](action.md). Its job is to take [a request instance](../runtime/request.md), pass it to [domain layer](domain.md) in a suitable format, and create [a response](../runtime/response.md) based on domain layer return." +msgid "A context may have [an entry point known as \"action\" or \"controller\"](action.md). Its job is to take [a request instance](../runtime/request.md), pass it to [domain layer](../../cookbook/organizing-code/domain.md) in a suitable format, and create [a response](../runtime/response.md) based on domain layer return." msgstr "" #. type: Plain text @@ -154,7 +153,7 @@ msgstr "" #. type: Bullet: '* ' #: ../src/en/guide/structure/overview.md -msgid "[services](service.md): they're typically stateless objects registered within dependency container and provide various action methods." +msgid "[services](../../cookbook/organizing-code/service.md): they're typically stateless objects registered within dependency container and provide various action methods." msgstr "" #. type: Bullet: '* ' diff --git a/_translations/po/it/internals_014-docs.md.po b/_translations/po/it/internals_014-docs.md.po index 6befbc5c..92b5c57a 100644 --- a/_translations/po/it/internals_014-docs.md.po +++ b/_translations/po/it/internals_014-docs.md.po @@ -68,7 +68,7 @@ msgstr "La guida definitiva a Yii3" #. type: Plain text #: ../src/internals/014-docs.md -msgid "The definitive guide, [yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/guide/en) aims at covering usage of packages as a whole framework. Unlike package documentation, it isn't focused on a single package but is covering certain use-cases." +msgid "The definitive guide, [yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/src/guide) aims at covering usage of packages as a whole framework. Unlike package documentation, it isn't focused on a single package but is covering certain use-cases." msgstr "" #. type: Plain text diff --git a/_translations/po/pt-BR/cookbook_configuring-webservers_apache.md.po b/_translations/po/pt-BR/cookbook_configuring-webservers_apache.md.po new file mode 100644 index 00000000..19b7dace --- /dev/null +++ b/_translations/po/pt-BR/cookbook_configuring-webservers_apache.md.po @@ -0,0 +1,132 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-10-15 10:10+0000\n" +"PO-Revision-Date: 2026-10-15 10:10+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/cookbook/configuring-webservers/apache.md +#, no-wrap +msgid "Configuring web servers: Apache" +msgstr "Configurando servidores web: Apache" + +#. type: Plain text +#: ../src/cookbook/configuring-webservers/apache.md +msgid "Use the following configuration in Apache's `httpd.conf` file or within a virtual host configuration. Note that you should replace `path/to/app/public` with the actual path for `app/public`." +msgstr "Use a configuração a seguir no arquivo `httpd.conf` do Apache ou na configuração de um virtual host. Substitua `path/to/app/public` pelo caminho real de `app/public`." + +#. type: Fenced code block (apache) +#: ../src/cookbook/configuring-webservers/apache.md +#, no-wrap +msgid "" +"# Set document root to be \"app/public\"\n" +"DocumentRoot \"path/to/app/public\"\n" +"\n" +"\n" +" # use mod_rewrite for pretty URL support\n" +" RewriteEngine on\n" +" \n" +" # Do not allow access to URLs with a script name\n" +" RewriteCond %{THE_REQUEST} index.php [NC]\n" +" RewriteRule . - [R=404,L]\n" +" \n" +" # If a directory or a file exists, use the request directly\n" +" RewriteCond %{REQUEST_FILENAME} !-f\n" +" RewriteCond %{REQUEST_FILENAME} !-d\n" +" \n" +" # Otherwise forward the request to index.php\n" +" RewriteRule . index.php\n" +" \n" +" SetEnv APP_ENV dev\n" +"\n" +" # ...other settings...\n" +"\n" +msgstr "" +"# Define o document root como \"app/public\"\n" +"DocumentRoot \"path/to/app/public\"\n" +"\n" +"\n" +" # usa mod_rewrite para suportar URLs amigáveis\n" +" RewriteEngine on\n" +" \n" +" # Não permite acesso a URLs com o nome do script\n" +" RewriteCond %{THE_REQUEST} index.php [NC]\n" +" RewriteRule . - [R=404,L]\n" +" \n" +" # Se um diretório ou arquivo existir, usa a requisição diretamente\n" +" RewriteCond %{REQUEST_FILENAME} !-f\n" +" RewriteCond %{REQUEST_FILENAME} !-d\n" +" \n" +" # Caso contrário, encaminha a requisição para index.php\n" +" RewriteRule . index.php\n" +" \n" +" SetEnv APP_ENV dev\n" +"\n" +" # ...outras configurações...\n" +"\n" + +#. type: Plain text +#: ../src/cookbook/configuring-webservers/apache.md +msgid "In case you have `AllowOverride All` you can add `.htaccess` file with the following configuration instead of using `httpd.conf`:" +msgstr "Se você tiver `AllowOverride All`, pode adicionar um arquivo `.htaccess` com a configuração a seguir em vez de usar o `httpd.conf`:" + +#. type: Fenced code block (apache) +#: ../src/cookbook/configuring-webservers/apache.md +#, no-wrap +msgid "" +"# use mod_rewrite for pretty URL support\n" +"RewriteEngine on\n" +"\n" +"# Do not allow access to URLs with a script name\n" +"RewriteCond %{THE_REQUEST} index.php [NC]\n" +"RewriteRule . - [R=404,L]\n" +"\n" +"# If a directory or a file exists, use the request directly\n" +"RewriteCond %{REQUEST_FILENAME} !-f\n" +"RewriteCond %{REQUEST_FILENAME} !-d\n" +"\n" +"# Otherwise forward the request to index.php\n" +"RewriteRule . index.php\n" +"\n" +"SetEnv APP_ENV dev\n" +"\n" +"# ...other settings...\n" +msgstr "" +"# usa mod_rewrite para suportar URLs amigáveis\n" +"RewriteEngine on\n" +"\n" +"# Não permite acesso a URLs com o nome do script\n" +"RewriteCond %{THE_REQUEST} index.php [NC]\n" +"RewriteRule . - [R=404,L]\n" +"\n" +"# Se um diretório ou arquivo existir, usa a requisição diretamente\n" +"RewriteCond %{REQUEST_FILENAME} !-f\n" +"RewriteCond %{REQUEST_FILENAME} !-d\n" +"\n" +"# Caso contrário, encaminha a requisição para index.php\n" +"RewriteRule . index.php\n" +"\n" +"SetEnv APP_ENV dev\n" +"\n" +"# ...outras configurações...\n" + +#. type: Plain text +#: ../src/cookbook/configuring-webservers/apache.md +msgid "In the above, note the usage of `SetEnv`. Since Yii3 application templates use environment variables, this is a possible place to set them. In production environment remember to set `APP_ENV` to `prod`." +msgstr "Observe o uso de `SetEnv` acima. Como os templates de aplicação do Yii3 usam variáveis de ambiente, este é um lugar possível para defini-las. Em produção, lembre-se de definir `APP_ENV` como `prod`." + +#. type: Plain text +#: ../src/cookbook/configuring-webservers/apache.md ../src/cookbook/configuring-webservers/iis.md ../src/cookbook/configuring-webservers/lighttpd.md ../src/cookbook/configuring-webservers/nginx-unit.md +msgid "See [application logs](general.md#application-logs) for logging configuration." +msgstr "Veja [logs da aplicação](general.md#logs-da-aplicacao) para a configuração de logs." diff --git a/_translations/po/pt-BR/cookbook_configuring-webservers_general.md.po b/_translations/po/pt-BR/cookbook_configuring-webservers_general.md.po new file mode 100644 index 00000000..fe40cfba --- /dev/null +++ b/_translations/po/pt-BR/cookbook_configuring-webservers_general.md.po @@ -0,0 +1,103 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-10-15 10:10+0000\n" +"PO-Revision-Date: 2026-10-15 10:10+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/cookbook/configuring-webservers/general.md +#, no-wrap +msgid "Configuring web servers: General" +msgstr "Configurando servidores web: geral" + +#. type: Plain text +#: ../src/cookbook/configuring-webservers/general.md +msgid "On a production server, if you don't use Docker, configure your web server to serve only the application's public files. Point the document root of your web server to the `app/public` folder." +msgstr "Em um servidor de produção, se você não usa Docker, configure seu servidor web para servir apenas os arquivos públicos da aplicação. Aponte o document root do servidor web para a pasta `app/public`." + +#. type: Plain text +#: ../src/cookbook/configuring-webservers/general.md +#, no-wrap +msgid "" +"> [!IMPORTANT]\n" +"> If you're running your Yii application behind a reverse proxy, you might need to configure\n" +"> [Trusted proxies and headers](../../guide/security/trusted-request.md).\n" +msgstr "" +"> [!IMPORTANT]\n" +"> Se você executa sua aplicação Yii atrás de um proxy reverso, pode ser necessário configurar\n" +"> [proxies e headers confiáveis](../../guide/security/trusted-request.md).\n" + +#. type: Title ## +#: ../src/cookbook/configuring-webservers/general.md +#, no-wrap +msgid "Application logs" +msgstr "Logs da aplicação" + +#. type: Plain text +#: ../src/cookbook/configuring-webservers/general.md +msgid "Yii3 application templates write application logs to standard output (`stdout`, or `php://stdout`) by default. They don't create application log files. Standard error (`stderr`) requires explicit log target configuration. Docker collects container output, but on a server without containers you must configure where that output goes or [configure a file target](../../guide/runtime/logging.md#logging-to-files). Web server access and error log settings don't configure Yii's log targets." +msgstr "Os templates de aplicação do Yii3 escrevem os logs da aplicação na saída padrão (`stdout`, ou `php://stdout`) por padrão. Eles não criam arquivos de log da aplicação. A saída de erro padrão (`stderr`) exige configuração explícita de destino de log. O Docker coleta a saída dos containers, mas em um servidor sem containers você precisa configurar para onde essa saída vai ou [configurar um destino de arquivo](../../guide/runtime/logging.md#logs-em-arquivos). As configurações de log de acesso e de erro do servidor web não configuram os destinos de log do Yii." + +#. type: Title ### +#: ../src/cookbook/configuring-webservers/general.md +#, no-wrap +msgid "PHP-FPM" +msgstr "PHP-FPM" + +#. type: Plain text +#: ../src/cookbook/configuring-webservers/general.md +msgid "If your web server uses PHP-FPM, enable worker output capture in the application's PHP-FPM pool configuration:" +msgstr "Se o seu servidor web usa PHP-FPM, habilite a captura da saída dos workers na configuração do pool PHP-FPM da aplicação:" + +#. type: Fenced code block (ini) +#: ../src/cookbook/configuring-webservers/general.md +#, no-wrap +msgid "catch_workers_output = yes\n" +msgstr "catch_workers_output = yes\n" + +#. type: Plain text +#: ../src/cookbook/configuring-webservers/general.md +msgid "Reload PHP-FPM after changing its configuration. PHP-FPM sends worker standard output and standard error to its main error log. The `error_log` directive in `php-fpm.conf` sets the destination. Without this setting, PHP-FPM redirects both streams to `/dev/null` by default. See the [PHP-FPM configuration reference](https://www.php.net/manual/en/install.fpm.configuration.php)." +msgstr "Recarregue o PHP-FPM depois de alterar a configuração. O PHP-FPM envia a saída padrão e a saída de erro dos workers para o seu log de erro principal. A diretiva `error_log` em `php-fpm.conf` define o destino. Sem essa configuração, o PHP-FPM redireciona as duas saídas para `/dev/null` por padrão. Veja a [referência de configuração do PHP-FPM](https://www.php.net/manual/en/install.fpm.configuration.php)." + +#. type: Title ## +#: ../src/cookbook/configuring-webservers/general.md +#, no-wrap +msgid "Specific server configurations" +msgstr "Configurações específicas de servidores" + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-webservers/general.md +msgid "[Nginx](nginx.md)" +msgstr "[Nginx](nginx.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-webservers/general.md +msgid "[Apache](apache.md)" +msgstr "[Apache](apache.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-webservers/general.md +msgid "[Lighttpd](lighttpd.md)" +msgstr "[Lighttpd](lighttpd.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-webservers/general.md +msgid "[Nginx Unit](nginx-unit.md)" +msgstr "[Nginx Unit](nginx-unit.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-webservers/general.md +msgid "[IIS](iis.md)" +msgstr "[IIS](iis.md)" diff --git a/_translations/po/pt-BR/cookbook_configuring-webservers_iis.md.po b/_translations/po/pt-BR/cookbook_configuring-webservers_iis.md.po new file mode 100644 index 00000000..02d01538 --- /dev/null +++ b/_translations/po/pt-BR/cookbook_configuring-webservers_iis.md.po @@ -0,0 +1,83 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-10-15 10:10+0000\n" +"PO-Revision-Date: 2026-10-15 10:10+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Plain text +#: ../src/cookbook/configuring-webservers/apache.md ../src/cookbook/configuring-webservers/iis.md ../src/cookbook/configuring-webservers/lighttpd.md ../src/cookbook/configuring-webservers/nginx-unit.md +msgid "See [application logs](general.md#application-logs) for logging configuration." +msgstr "Veja [logs da aplicação](general.md#logs-da-aplicacao) para a configuração de logs." + +#. type: Title # +#: ../src/cookbook/configuring-webservers/iis.md +#, no-wrap +msgid "Configuring web servers: IIS" +msgstr "Configurando servidores web: IIS" + +#. type: Plain text +#: ../src/cookbook/configuring-webservers/iis.md +msgid "When you use [IIS](https://www.iis.net/), host the application in a virtual host (Website) where the document root points to the `path/to/app/public` folder and configure the website to run PHP. In that `public` folder, place a file named `web.config` at `path/to/app/public/web.config`. Use the following content:" +msgstr "Ao usar o [IIS](https://www.iis.net/), hospede a aplicação em um virtual host (Website) cujo document root aponte para a pasta `path/to/app/public` e configure o site para executar PHP. Nessa pasta `public`, coloque um arquivo chamado `web.config` em `path/to/app/public/web.config`. Use o seguinte conteúdo:" + +#. type: Fenced code block (xml) +#: ../src/cookbook/configuring-webservers/iis.md +#, no-wrap +msgid "" +"\n" +"\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"\n" +msgstr "" +"\n" +"\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"\n" + +#. type: Plain text +#: ../src/cookbook/configuring-webservers/iis.md +msgid "Also, [IIS documentation](https://learn.microsoft.com/en-us/iis/) could be useful to configure PHP on IIS." +msgstr "A [documentação do IIS](https://learn.microsoft.com/en-us/iis/) também pode ser útil para configurar o PHP no IIS." diff --git a/_translations/po/pt-BR/cookbook_configuring-webservers_lighttpd.md.po b/_translations/po/pt-BR/cookbook_configuring-webservers_lighttpd.md.po new file mode 100644 index 00000000..61eab00b --- /dev/null +++ b/_translations/po/pt-BR/cookbook_configuring-webservers_lighttpd.md.po @@ -0,0 +1,39 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-10-15 10:10+0000\n" +"PO-Revision-Date: 2026-10-15 10:10+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Plain text +#: ../src/cookbook/configuring-webservers/apache.md ../src/cookbook/configuring-webservers/iis.md ../src/cookbook/configuring-webservers/lighttpd.md ../src/cookbook/configuring-webservers/nginx-unit.md +msgid "See [application logs](general.md#application-logs) for logging configuration." +msgstr "Veja [logs da aplicação](general.md#logs-da-aplicacao) para a configuração de logs." + +#. type: Title # +#: ../src/cookbook/configuring-webservers/lighttpd.md +#, no-wrap +msgid "Configuring web servers: lighttpd" +msgstr "Configurando servidores web: lighttpd" + +#. type: Plain text +#: ../src/cookbook/configuring-webservers/lighttpd.md +#, no-wrap +msgid "To use [lighttpd](https://www.lighttpd.net/) >= 1.4.24, put `index.php` in the web root and add the following to the configuration:\n" +msgstr "Para usar o [lighttpd](https://www.lighttpd.net/) >= 1.4.24, coloque o `index.php` na raiz web e adicione o seguinte à configuração:\n" + +#. type: Fenced code block +#: ../src/cookbook/configuring-webservers/lighttpd.md +#, no-wrap +msgid "url.rewrite-if-not-file = (\"(.*)\" => \"/index.php/$0\")\n" +msgstr "url.rewrite-if-not-file = (\"(.*)\" => \"/index.php/$0\")\n" diff --git a/_translations/po/pt-BR/cookbook_configuring-webservers_nginx-unit.md.po b/_translations/po/pt-BR/cookbook_configuring-webservers_nginx-unit.md.po new file mode 100644 index 00000000..f07ca3a6 --- /dev/null +++ b/_translations/po/pt-BR/cookbook_configuring-webservers_nginx-unit.md.po @@ -0,0 +1,147 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-10-15 10:10+0000\n" +"PO-Revision-Date: 2026-10-15 10:10+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Plain text +#: ../src/cookbook/configuring-webservers/apache.md ../src/cookbook/configuring-webservers/iis.md ../src/cookbook/configuring-webservers/lighttpd.md ../src/cookbook/configuring-webservers/nginx-unit.md +msgid "See [application logs](general.md#application-logs) for logging configuration." +msgstr "Veja [logs da aplicação](general.md#logs-da-aplicacao) para a configuração de logs." + +#. type: Title # +#: ../src/cookbook/configuring-webservers/nginx-unit.md +#, no-wrap +msgid "Configuring web servers: NGINX Unit and FreeUnit" +msgstr "Configurando servidores web: NGINX Unit e FreeUnit" + +#. type: Plain text +#: ../src/cookbook/configuring-webservers/nginx-unit.md +msgid "Run Yii-based apps using [NGINX Unit](https://unit.nginx.org/) with a PHP language module. The same configuration format is used by [FreeUnit](https://github.com/freeunitorg/freeunit), a community LTS fork of Unit. With FreeUnit Docker images, such as `ghcr.io/freeunitorg/freeunit:latest-php8.5`, put the configuration in `/var/lib/unit/config.json`." +msgstr "Execute aplicações baseadas em Yii usando o [NGINX Unit](https://unit.nginx.org/) com um módulo de linguagem PHP. O mesmo formato de configuração é usado pelo [FreeUnit](https://github.com/freeunitorg/freeunit), um fork LTS do Unit mantido pela comunidade. Com as imagens Docker do FreeUnit, como `ghcr.io/freeunitorg/freeunit:latest-php8.5`, coloque a configuração em `/var/lib/unit/config.json`." + +#. type: Plain text +#: ../src/cookbook/configuring-webservers/nginx-unit.md +msgid "Here is a sample configuration." +msgstr "Aqui está um exemplo de configuração." + +#. type: Fenced code block (json) +#: ../src/cookbook/configuring-webservers/nginx-unit.md +#, no-wrap +msgid "" +"{\n" +" \"listeners\": {\n" +" \"*:80\": {\n" +" \"pass\": \"routes\"\n" +" }\n" +" },\n" +"\n" +" \"routes\": [\n" +" {\n" +" \"match\": {\n" +" \"uri\": [\n" +" \"!/assets/*\",\n" +" \"*.php\",\n" +" \"*.php/*\"\n" +" ]\n" +" },\n" +"\n" +" \"action\": {\n" +" \"pass\": \"applications/yii/direct\"\n" +" }\n" +" },\n" +" {\n" +" \"action\": {\n" +" \"share\": \"/path/to/app/public$uri\",\n" +" \"fallback\": {\n" +" \"pass\": \"applications/yii/index\"\n" +" }\n" +" }\n" +" }\n" +" ],\n" +"\n" +" \"applications\": {\n" +" \"yii\": {\n" +" \"type\": \"php\",\n" +" \"targets\": {\n" +" \"direct\": {\n" +" \"root\": \"/path/to/app/public/\"\n" +" },\n" +"\n" +" \"index\": {\n" +" \"root\": \"/path/to/app/public/\",\n" +" \"script\": \"index.php\"\n" +" }\n" +" }\n" +" }\n" +" }\n" +"}\n" +msgstr "" +"{\n" +" \"listeners\": {\n" +" \"*:80\": {\n" +" \"pass\": \"routes\"\n" +" }\n" +" },\n" +"\n" +" \"routes\": [\n" +" {\n" +" \"match\": {\n" +" \"uri\": [\n" +" \"!/assets/*\",\n" +" \"*.php\",\n" +" \"*.php/*\"\n" +" ]\n" +" },\n" +"\n" +" \"action\": {\n" +" \"pass\": \"applications/yii/direct\"\n" +" }\n" +" },\n" +" {\n" +" \"action\": {\n" +" \"share\": \"/path/to/app/public$uri\",\n" +" \"fallback\": {\n" +" \"pass\": \"applications/yii/index\"\n" +" }\n" +" }\n" +" }\n" +" ],\n" +"\n" +" \"applications\": {\n" +" \"yii\": {\n" +" \"type\": \"php\",\n" +" \"targets\": {\n" +" \"direct\": {\n" +" \"root\": \"/path/to/app/public/\"\n" +" },\n" +"\n" +" \"index\": {\n" +" \"root\": \"/path/to/app/public/\",\n" +" \"script\": \"index.php\"\n" +" }\n" +" }\n" +" }\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/cookbook/configuring-webservers/nginx-unit.md +msgid "You can also [set up](https://unit.nginx.org/configuration/#php) your PHP environment or supply a custom `php.ini` in the same configuration." +msgstr "Você também pode [configurar](https://unit.nginx.org/configuration/#php) o ambiente PHP ou fornecer um `php.ini` personalizado na mesma configuração." + +#. type: Plain text +#: ../src/cookbook/configuring-webservers/nginx-unit.md +msgid "Since Yii3 application templates use environment variables, you can set them in `applications.yii.environment`. In a production environment, remember to set `APP_ENV` to `prod`." +msgstr "Como os templates de aplicação do Yii3 usam variáveis de ambiente, você pode defini-las em `applications.yii.environment`. Em produção, lembre-se de definir `APP_ENV` como `prod`." diff --git a/_translations/po/pt-BR/cookbook_configuring-webservers_nginx.md.po b/_translations/po/pt-BR/cookbook_configuring-webservers_nginx.md.po new file mode 100644 index 00000000..b00b8550 --- /dev/null +++ b/_translations/po/pt-BR/cookbook_configuring-webservers_nginx.md.po @@ -0,0 +1,139 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-10-15 10:10+0000\n" +"PO-Revision-Date: 2026-10-15 10:10+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/cookbook/configuring-webservers/nginx.md +#, no-wrap +msgid "Configuring web servers: Nginx" +msgstr "Configurando servidores web: Nginx" + +#. type: Plain text +#: ../src/cookbook/configuring-webservers/nginx.md +msgid "To use [Nginx](https:/nginx.org/), install PHP as an [FPM SAPI](https://secure.php.net/install.fpm). Use the following Nginx configuration, replacing `path/to/app/public` with the actual path for `app/public` and `mysite.test` with the actual hostname to serve." +msgstr "Para usar o [Nginx](https:/nginx.org/), instale o PHP como [FPM SAPI](https://secure.php.net/install.fpm). Use a configuração do Nginx a seguir, substituindo `path/to/app/public` pelo caminho real de `app/public` e `mysite.test` pelo hostname real a ser servido." + +#. type: Fenced code block (nginx) +#: ../src/cookbook/configuring-webservers/nginx.md +#, no-wrap +msgid "" +"server {\n" +" charset utf-8;\n" +" client_max_body_size 128M;\n" +"\n" +" listen 80; ## listen for ipv4\n" +" #listen [::]:80 default_server ipv6only=on; ## listen for ipv6\n" +"\n" +" server_name mysite.test;\n" +" root /path/to/app/public;\n" +" index index.php;\n" +"\n" +" access_log /path/to/basic/log/access.log;\n" +" error_log /path/to/basic/log/error.log;\n" +"\n" +" location / {\n" +" # Redirect everything that isn't a real file to index.php\n" +" try_files $uri $uri/ /index.php$is_args$args;\n" +" }\n" +"\n" +" # uncomment to avoid processing of calls to non-existing static files by Yii\n" +" #location ~ \\.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ {\n" +" # try_files $uri =404;\n" +" #}\n" +" #error_page 404 /404.html;\n" +"\n" +" # deny accessing php files for the /assets directory\n" +" location ~ ^/assets/.*\\.php$ {\n" +" deny all;\n" +" }\n" +"\n" +" location ~ \\.php$ {\n" +" include fastcgi_params;\n" +" fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;\n" +" fastcgi_pass 127.0.0.1:9000;\n" +" #fastcgi_pass unix:/var/run/php8-fpm.sock;\n" +" try_files $uri =404;\n" +" fastcgi_param APP_ENV \"dev\";\n" +" }\n" +"\n" +" location ~* /\\. {\n" +" deny all;\n" +" }\n" +"}\n" +msgstr "" +"server {\n" +" charset utf-8;\n" +" client_max_body_size 128M;\n" +"\n" +" listen 80; ## escuta em ipv4\n" +" #listen [::]:80 default_server ipv6only=on; ## escuta em ipv6\n" +"\n" +" server_name mysite.test;\n" +" root /path/to/app/public;\n" +" index index.php;\n" +"\n" +" access_log /path/to/basic/log/access.log;\n" +" error_log /path/to/basic/log/error.log;\n" +"\n" +" location / {\n" +" # Redireciona para index.php tudo que não for um arquivo real\n" +" try_files $uri $uri/ /index.php$is_args$args;\n" +" }\n" +"\n" +" # descomente para evitar que o Yii processe chamadas a arquivos estáticos inexistentes\n" +" #location ~ \\.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ {\n" +" # try_files $uri =404;\n" +" #}\n" +" #error_page 404 /404.html;\n" +"\n" +" # bloqueia o acesso a arquivos php no diretório /assets\n" +" location ~ ^/assets/.*\\.php$ {\n" +" deny all;\n" +" }\n" +"\n" +" location ~ \\.php$ {\n" +" include fastcgi_params;\n" +" fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;\n" +" fastcgi_pass 127.0.0.1:9000;\n" +" #fastcgi_pass unix:/var/run/php8-fpm.sock;\n" +" try_files $uri =404;\n" +" fastcgi_param APP_ENV \"dev\";\n" +" }\n" +"\n" +" location ~* /\\. {\n" +" deny all;\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/cookbook/configuring-webservers/nginx.md +msgid "When you use this configuration, also set `cgi.fix_pathinfo=0` in the `php.ini` file to avoid many unnecessary system `stat()` calls." +msgstr "Ao usar essa configuração, defina também `cgi.fix_pathinfo=0` no arquivo `php.ini` para evitar muitas chamadas de sistema `stat()` desnecessárias." + +#. type: Plain text +#: ../src/cookbook/configuring-webservers/nginx.md +msgid "Also, note that when running an HTTPS server, you need to add `fastcgi_param HTTPS on;` so that Yii can detect if a connection is secure." +msgstr "Além disso, ao executar um servidor HTTPS, você precisa adicionar `fastcgi_param HTTPS on;` para que o Yii consiga detectar se a conexão é segura." + +#. type: Plain text +#: ../src/cookbook/configuring-webservers/nginx.md +msgid "In the above, note the usage of `fastcgi_param APP_ENV`. Since Yii3 application templates use environment variables, this is a possible place to set them. In production environment remember to set `APP_ENV` to `prod`." +msgstr "Observe o uso de `fastcgi_param APP_ENV` acima. Como os templates de aplicação do Yii3 usam variáveis de ambiente, este é um lugar possível para defini-las. Em produção, lembre-se de definir `APP_ENV` como `prod`." + +#. type: Plain text +#: ../src/cookbook/configuring-webservers/nginx.md +msgid "The Nginx `access_log` and `error_log` directives above don't capture PHP-FPM worker output. See [application logs](general.md#application-logs) for logging configuration." +msgstr "As diretivas `access_log` e `error_log` do Nginx acima não capturam a saída dos workers do PHP-FPM. Veja [logs da aplicação](general.md#logs-da-aplicacao) para a configuração de logs." diff --git a/_translations/po/pt-BR/cookbook_configuring-xdebug.md.po b/_translations/po/pt-BR/cookbook_configuring-xdebug.md.po new file mode 100644 index 00000000..652f5695 --- /dev/null +++ b/_translations/po/pt-BR/cookbook_configuring-xdebug.md.po @@ -0,0 +1,608 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-05-07 14:37+0000\n" +"PO-Revision-Date: 2026-05-07 14:37+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "Configuring Xdebug" +msgstr "Configurando o Xdebug" + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "Xdebug lets an IDE stop PHP code on breakpoints while the application handles a web request, console command, or test. The IDE listens for debug connections. PHP starts the request and Xdebug connects back to the IDE." +msgstr "O Xdebug permite que a IDE pare o código PHP em breakpoints enquanto a aplicação processa uma requisição web, um comando de console ou um teste. A IDE escuta conexões de depuração. O PHP inicia a requisição e o Xdebug se conecta de volta à IDE." + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "Yii works with the regular Xdebug setup. Configure Xdebug for the PHP runtime that executes the code and make sure the IDE can map runtime paths to project files." +msgstr "O Yii funciona com a configuração comum do Xdebug. Configure o Xdebug no runtime PHP que executa o código e garanta que a IDE consiga mapear os caminhos do runtime para os arquivos do projeto." + +#. type: Title ## +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "Check Xdebug" +msgstr "Verificando o Xdebug" + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "Use Xdebug 3. The default debug port is `9003`." +msgstr "Use o Xdebug 3. A porta de depuração padrão é `9003`." + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "Without Docker, install Xdebug for the PHP executable that runs the application, then check it:" +msgstr "Sem Docker, instale o Xdebug no executável PHP que roda a aplicação e depois verifique:" + +#. type: Fenced code block (shell) +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "" +"php --version\n" +"php --ri xdebug\n" +msgstr "" +"php --version\n" +"php --ri xdebug\n" + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "In `php.ini` or an Xdebug-specific ini file, enable step debugging:" +msgstr "No `php.ini` ou em um arquivo ini específico do Xdebug, habilite a depuração passo a passo:" + +#. type: Fenced code block (ini) +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "" +"xdebug.mode=develop,debug\n" +"xdebug.start_with_request=trigger\n" +"xdebug.client_host=127.0.0.1\n" +"xdebug.client_port=9003\n" +msgstr "" +"xdebug.mode=develop,debug\n" +"xdebug.start_with_request=trigger\n" +"xdebug.client_host=127.0.0.1\n" +"xdebug.client_port=9003\n" + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "`trigger` starts a debug session only when a browser extension, query parameter, cookie, or `XDEBUG_SESSION` environment variable asks for it." +msgstr "`trigger` inicia uma sessão de depuração apenas quando uma extensão do navegador, um parâmetro de query string, um cookie ou a variável de ambiente `XDEBUG_SESSION` pedir." + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "With Docker, the Yii application template installs Xdebug in the development image. Enable step debugging in `docker/dev/override.env`:" +msgstr "Com Docker, o template de aplicação do Yii instala o Xdebug na imagem de desenvolvimento. Habilite a depuração passo a passo em `docker/dev/override.env`:" + +#. type: Fenced code block (dotenv) +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "" +"XDEBUG_MODE=develop,debug\n" +"XDEBUG_CONFIG=\"client_host=host.docker.internal idekey=phpstorm\"\n" +msgstr "" +"XDEBUG_MODE=develop,debug\n" +"XDEBUG_CONFIG=\"client_host=host.docker.internal idekey=phpstorm\"\n" + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "Keep the default `SERVER_NAME=:80` from `docker/dev/.env` unless the application needs a different Caddy address. Set the browser port with `DEV_PORT` in `docker/.env`:" +msgstr "Mantenha o `SERVER_NAME=:80` padrão de `docker/dev/.env`, a menos que a aplicação precise de outro endereço no Caddy. Defina a porta do navegador com `DEV_PORT` em `docker/.env`:" + +#. type: Fenced code block (dotenv) +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "DEV_PORT=80\n" +msgstr "DEV_PORT=80\n" + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "On Linux, Docker must resolve `host.docker.internal` to the host gateway. The current Yii application template already has this in `docker/compose.yml`:" +msgstr "No Linux, o Docker precisa resolver `host.docker.internal` para o gateway do host. O template de aplicação atual do Yii já traz isso em `docker/compose.yml`:" + +#. type: Fenced code block (yaml) +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "" +"services:\n" +" app:\n" +" extra_hosts:\n" +" - \"host.docker.internal:host-gateway\"\n" +msgstr "" +"services:\n" +" app:\n" +" extra_hosts:\n" +" - \"host.docker.internal:host-gateway\"\n" + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "Rebuild the development image if Xdebug was added after the image had already been built:" +msgstr "Reconstrua a imagem de desenvolvimento se o Xdebug foi adicionado depois que a imagem já tinha sido construída:" + +#. type: Fenced code block (shell) +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "make build\n" +msgstr "make build\n" + +#. type: Title ## +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "PhpStorm" +msgstr "PhpStorm" + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "" +"In **Settings** > **PHP** > **Debug**, check that Xdebug listens on port `9003`. Start listening with\n" +"**Run** > **Start Listening for PHP Debug Connections**.\n" +msgstr "" +"Em **Settings** > **PHP** > **Debug**, verifique se o Xdebug escuta na porta `9003`. Comece a escutar com\n" +"**Run** > **Start Listening for PHP Debug Connections**.\n" + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "" +"For browser debugging, install a browser extension from **Settings** > **PHP** > **Debug**. In the extension options,\n" +"use `phpstorm` as the IDE key.\n" +msgstr "" +"Para depurar pelo navegador, instale uma extensão de navegador a partir de **Settings** > **PHP** > **Debug**. Nas opções da extensão,\n" +"use `phpstorm` como IDE key.\n" + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "When PHP runs in Docker, configure a server in **Settings** > **PHP** > **Servers**:\n" +msgstr "Quando o PHP roda no Docker, configure um servidor em **Settings** > **PHP** > **Servers**:\n" + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-xdebug.md +msgid "Name: `localhost`." +msgstr "Nome: `localhost`." + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-xdebug.md +msgid "Host: `localhost`." +msgstr "Host: `localhost`." + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-xdebug.md +msgid "Port: `80`, or the host port configured by `DEV_PORT`." +msgstr "Porta: `80`, ou a porta do host configurada em `DEV_PORT`." + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-xdebug.md +msgid "Debugger: `Xdebug`." +msgstr "Depurador: `Xdebug`." + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-xdebug.md +msgid "Path mapping: map the project root on the host to `/app` in the container." +msgstr "Mapeamento de caminhos: mapeie a raiz do projeto no host para `/app` no container." + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "Use the project root for the mapping. Mapping only `public/` leaves files under `src/`, `config/`, and `vendor/` unmapped. The path in the container must match the path used by PHP. In the default template, the project is mounted into `/app`." +msgstr "Use a raiz do projeto no mapeamento. Mapear só `public/` deixa sem mapeamento os arquivos em `src/`, `config/` e `vendor/`. O caminho no container precisa ser igual ao caminho usado pelo PHP. No template padrão, o projeto é montado em `/app`." + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "For local PHP, PhpStorm usually uses the same filesystem paths as PHP, so path mappings are usually unnecessary." +msgstr "Com PHP local, o PhpStorm normalmente usa os mesmos caminhos do sistema de arquivos que o PHP, então mapeamentos de caminhos costumam ser desnecessários." + +#. type: Title ## +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "VS Code" +msgstr "VS Code" + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "Install the [PHP Debug](https://marketplace.visualstudio.com/items?itemName=xdebug.php-debug) extension." +msgstr "Instale a extensão [PHP Debug](https://marketplace.visualstudio.com/items?itemName=xdebug.php-debug)." + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "For PHP that runs on the same filesystem as VS Code, create `.vscode/launch.json`:" +msgstr "Para PHP rodando no mesmo sistema de arquivos que o VS Code, crie `.vscode/launch.json`:" + +#. type: Fenced code block (json) +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "" +"{\n" +" \"version\": \"0.2.0\",\n" +" \"configurations\": [\n" +" {\n" +" \"name\": \"Listen for Xdebug\",\n" +" \"type\": \"php\",\n" +" \"request\": \"launch\",\n" +" \"port\": 9003\n" +" }\n" +" ]\n" +"}\n" +msgstr "" +"{\n" +" \"version\": \"0.2.0\",\n" +" \"configurations\": [\n" +" {\n" +" \"name\": \"Listen for Xdebug\",\n" +" \"type\": \"php\",\n" +" \"request\": \"launch\",\n" +" \"port\": 9003\n" +" }\n" +" ]\n" +"}\n" + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "For Docker, add path mappings:" +msgstr "Para Docker, adicione mapeamentos de caminhos:" + +#. type: Fenced code block (json) +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "" +"{\n" +" \"version\": \"0.2.0\",\n" +" \"configurations\": [\n" +" {\n" +" \"name\": \"Listen for Xdebug\",\n" +" \"type\": \"php\",\n" +" \"request\": \"launch\",\n" +" \"port\": 9003,\n" +" \"pathMappings\": {\n" +" \"/app\": \"${workspaceFolder}\"\n" +" }\n" +" }\n" +" ]\n" +"}\n" +msgstr "" +"{\n" +" \"version\": \"0.2.0\",\n" +" \"configurations\": [\n" +" {\n" +" \"name\": \"Listen for Xdebug\",\n" +" \"type\": \"php\",\n" +" \"request\": \"launch\",\n" +" \"port\": 9003,\n" +" \"pathMappings\": {\n" +" \"/app\": \"${workspaceFolder}\"\n" +" }\n" +" }\n" +" ]\n" +"}\n" + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "Start this configuration before running the web request, command, or test." +msgstr "Inicie essa configuração antes de executar a requisição web, o comando ou o teste." + +#. type: Title ## +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "Zed" +msgstr "Zed" + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "Install or enable the PHP extension in Zed. It provides the `Xdebug` debug adapter." +msgstr "Instale ou habilite a extensão PHP no Zed. Ela fornece o adaptador de depuração `Xdebug`." + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "Create `.zed/debug.json`:" +msgstr "Crie `.zed/debug.json`:" + +#. type: Fenced code block (json) +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "" +"[\n" +" {\n" +" \"label\": \"PHP: Listen to Xdebug\",\n" +" \"adapter\": \"Xdebug\",\n" +" \"request\": \"launch\",\n" +" \"port\": 9003\n" +" }\n" +"]\n" +msgstr "" +"[\n" +" {\n" +" \"label\": \"PHP: Listen to Xdebug\",\n" +" \"adapter\": \"Xdebug\",\n" +" \"request\": \"launch\",\n" +" \"port\": 9003\n" +" }\n" +"]\n" + +#. type: Fenced code block (json) +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "" +"[\n" +" {\n" +" \"label\": \"PHP: Listen to Xdebug\",\n" +" \"adapter\": \"Xdebug\",\n" +" \"request\": \"launch\",\n" +" \"port\": 9003,\n" +" \"pathMappings\": {\n" +" \"/app\": \"$ZED_WORKTREE_ROOT\"\n" +" }\n" +" }\n" +"]\n" +msgstr "" +"[\n" +" {\n" +" \"label\": \"PHP: Listen to Xdebug\",\n" +" \"adapter\": \"Xdebug\",\n" +" \"request\": \"launch\",\n" +" \"port\": 9003,\n" +" \"pathMappings\": {\n" +" \"/app\": \"$ZED_WORKTREE_ROOT\"\n" +" }\n" +" }\n" +"]\n" + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "Start the configuration with **debugger: start** before running the web request, command, or test. Zed can also load debug configurations from `.vscode/launch.json` when `.zed/debug.json` is absent." +msgstr "Inicie a configuração com **debugger: start** antes de executar a requisição web, o comando ou o teste. O Zed também consegue carregar configurações de depuração de `.vscode/launch.json` quando `.zed/debug.json` não existe." + +#. type: Title ## +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "Debug a web request" +msgstr "Depurando uma requisição web" + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "Without Docker:" +msgstr "Sem Docker:" + +#. type: Bullet: '3. ' +#: ../src/cookbook/configuring-xdebug.md +msgid "Start listening in the IDE." +msgstr "Comece a escutar na IDE." + +#. type: Bullet: '4. ' +#: ../src/cookbook/configuring-xdebug.md +msgid "Put a breakpoint in an action or middleware." +msgstr "Coloque um breakpoint em uma action ou middleware." + +#. type: Bullet: '3. ' +#: ../src/cookbook/configuring-xdebug.md +msgid "Start the built-in server with an Xdebug trigger:" +msgstr "Inicie o servidor embutido com um trigger do Xdebug:" + +#. type: Fenced code block (shell) +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid " ./yii serve --xdebug\n" +msgstr " ./yii serve --xdebug\n" + +#. type: Bullet: '4. ' +#: ../src/cookbook/configuring-xdebug.md +msgid "Open or reload the page in the browser." +msgstr "Abra ou recarregue a página no navegador." + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "The `--xdebug` option passes `XDEBUG_MODE=debug XDEBUG_TRIGGER=yes` to the built-in PHP server. If you use another web server, enable debugging with the browser extension and reload the page." +msgstr "A opção `--xdebug` passa `XDEBUG_MODE=debug XDEBUG_TRIGGER=yes` para o servidor embutido do PHP. Se você usa outro servidor web, habilite a depuração com a extensão do navegador e recarregue a página." + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "With Docker:" +msgstr "Com Docker:" + +#. type: Bullet: '1. ' +#: ../src/cookbook/configuring-xdebug.md +msgid "Add the Docker Xdebug variables to `docker/dev/override.env`." +msgstr "Adicione as variáveis do Xdebug para Docker em `docker/dev/override.env`." + +#. type: Bullet: '2. ' +#: ../src/cookbook/configuring-xdebug.md +msgid "Start or restart the development containers:" +msgstr "Inicie ou reinicie os containers de desenvolvimento:" + +#. type: Fenced code block (shell) +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid " make up\n" +msgstr " make up\n" + +#. type: Bullet: '5. ' +#: ../src/cookbook/configuring-xdebug.md +msgid "Enable debugging in the browser extension and reload the page." +msgstr "Habilite a depuração na extensão do navegador e recarregue a página." + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "If the IDE accepts a connection and the breakpoint stays inactive, check path mappings first." +msgstr "Se a IDE aceita a conexão e o breakpoint continua inativo, verifique primeiro os mapeamentos de caminhos." + +#. type: Title ## +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "Debug a console command" +msgstr "Depurando um comando de console" + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "Without Docker, start the command with an Xdebug trigger:" +msgstr "Sem Docker, inicie o comando com um trigger do Xdebug:" + +#. type: Fenced code block (shell) +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "XDEBUG_MODE=debug XDEBUG_SESSION=phpstorm ./yii hello\n" +msgstr "XDEBUG_MODE=debug XDEBUG_SESSION=phpstorm ./yii hello\n" + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "With Docker, pass the trigger to the container:" +msgstr "Com Docker, passe o trigger para o container:" + +#. type: Fenced code block (shell) +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "" +"docker compose -f docker/compose.yml -f docker/dev/compose.yml run --rm \\\n" +" -e XDEBUG_MODE=debug \\\n" +" -e XDEBUG_SESSION=phpstorm \\\n" +" -e PHP_IDE_CONFIG=serverName=localhost \\\n" +" app ./yii hello\n" +msgstr "" +"docker compose -f docker/compose.yml -f docker/dev/compose.yml run --rm \\\n" +" -e XDEBUG_MODE=debug \\\n" +" -e XDEBUG_SESSION=phpstorm \\\n" +" -e PHP_IDE_CONFIG=serverName=localhost \\\n" +" app ./yii hello\n" + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "Use the command name and arguments you need instead of `hello`." +msgstr "Use o nome do comando e os argumentos de que você precisa no lugar de `hello`." + +#. type: Title ## +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "Debug tests" +msgstr "Depurando testes" + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "Without Docker, start the test runner with an Xdebug trigger:" +msgstr "Sem Docker, inicie o executor de testes com um trigger do Xdebug:" + +#. type: Fenced code block (shell) +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "XDEBUG_MODE=debug XDEBUG_SESSION=phpstorm vendor/bin/codecept run\n" +msgstr "XDEBUG_MODE=debug XDEBUG_SESSION=phpstorm vendor/bin/codecept run\n" + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "With Docker, configure `docker/test/override.env`:" +msgstr "Com Docker, configure `docker/test/override.env`:" + +#. type: Fenced code block (dotenv) +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "" +"XDEBUG_MODE=debug,coverage\n" +"XDEBUG_CONFIG=\"client_host=host.docker.internal idekey=phpstorm\"\n" +msgstr "" +"XDEBUG_MODE=debug,coverage\n" +"XDEBUG_CONFIG=\"client_host=host.docker.internal idekey=phpstorm\"\n" + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "Then run the test container with a trigger:" +msgstr "Depois, rode o container de testes com um trigger:" + +#. type: Fenced code block (shell) +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "" +"docker compose -f docker/compose.yml -f docker/test/compose.yml run --rm \\\n" +" -e XDEBUG_SESSION=phpstorm \\\n" +" -e PHP_IDE_CONFIG=serverName=localhost \\\n" +" app ./vendor/bin/codecept run\n" +msgstr "" +"docker compose -f docker/compose.yml -f docker/test/compose.yml run --rm \\\n" +" -e XDEBUG_SESSION=phpstorm \\\n" +" -e PHP_IDE_CONFIG=serverName=localhost \\\n" +" app ./vendor/bin/codecept run\n" + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md +msgid "Use `make test` for regular test runs. Use the explicit `docker compose` command when you need to pass debug-only environment variables to one run." +msgstr "Use `make test` para execuções normais dos testes. Use o comando `docker compose` explícito quando precisar passar variáveis de ambiente só de depuração para uma execução." + +#. type: Title ## +#: ../src/cookbook/configuring-xdebug.md ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md ../src/guide/views/asset.md +#, no-wrap +msgid "Troubleshooting" +msgstr "Solução de problemas" + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-xdebug.md +msgid "The IDE must listen before PHP starts the request." +msgstr "A IDE precisa estar escutando antes de o PHP iniciar a requisição." + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-xdebug.md +msgid "Xdebug connects from PHP to the IDE. Allow incoming connections to port `9003` in the host firewall." +msgstr "O Xdebug se conecta do PHP para a IDE. Libere conexões de entrada na porta `9003` no firewall do host." + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-xdebug.md +msgid "In Docker, `client_host` must be reachable from the container. The Yii template uses `host.docker.internal`." +msgstr "No Docker, o `client_host` precisa ser acessível a partir do container. O template do Yii usa `host.docker.internal`." + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-xdebug.md +msgid "For CLI and tests, set `XDEBUG_SESSION=phpstorm` or another trigger accepted by your Xdebug configuration." +msgstr "Para CLI e testes, defina `XDEBUG_SESSION=phpstorm` ou outro trigger aceito pela sua configuração do Xdebug." + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-xdebug.md +msgid "For Docker path mappings, map the host project root to `/app`." +msgstr "Para mapeamentos de caminhos no Docker, mapeie a raiz do projeto no host para `/app`." + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-xdebug.md +msgid "To inspect connection attempts, temporarily add `log=/app/runtime/xdebug.log` to `XDEBUG_CONFIG`." +msgstr "Para inspecionar as tentativas de conexão, adicione temporariamente `log=/app/runtime/xdebug.log` ao `XDEBUG_CONFIG`." + +#. type: Title ## +#: ../src/cookbook/configuring-xdebug.md +#, no-wrap +msgid "See also" +msgstr "Veja também" + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-xdebug.md +msgid "[Xdebug step debugging](https://xdebug.org/docs/step_debug)" +msgstr "[Depuração passo a passo do Xdebug](https://xdebug.org/docs/step_debug)" + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-xdebug.md +msgid "[PhpStorm Xdebug documentation](https://www.jetbrains.com/help/phpstorm/configuring-xdebug.html)" +msgstr "[Documentação do Xdebug no PhpStorm](https://www.jetbrains.com/help/phpstorm/configuring-xdebug.html)" + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-xdebug.md +msgid "[PhpStorm servers and path mappings](https://www.jetbrains.com/help/phpstorm/servers.html)" +msgstr "[Servidores e mapeamentos de caminhos no PhpStorm](https://www.jetbrains.com/help/phpstorm/servers.html)" + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-xdebug.md +msgid "[VS Code PHP Debug](https://github.com/xdebug/vscode-php-debug)" +msgstr "[VS Code PHP Debug](https://github.com/xdebug/vscode-php-debug)" + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-xdebug.md +msgid "[Zed PHP documentation](https://zed.dev/docs/languages/php#debugging)" +msgstr "[Documentação de PHP no Zed](https://zed.dev/docs/languages/php#debugging)" + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-xdebug.md +msgid "[Docker in application templates](../guide/tutorial/docker.md)" +msgstr "[Docker nos templates de aplicação](../guide/tutorial/docker.md)" diff --git a/_translations/po/pt-BR/cookbook_custom-hydrator-type-casters.md.po b/_translations/po/pt-BR/cookbook_custom-hydrator-type-casters.md.po new file mode 100644 index 00000000..29c87b64 --- /dev/null +++ b/_translations/po/pt-BR/cookbook_custom-hydrator-type-casters.md.po @@ -0,0 +1,1075 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-10-15 11:09+0000\n" +"PO-Revision-Date: 2026-10-15 11:09+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/cookbook/custom-hydrator-type-casters.md +#, no-wrap +msgid "Custom hydrator type casters" +msgstr "Type casters personalizados para o hydrator" + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "[Yii Hydrator](https://github.com/yiisoft/hydrator) creates objects and fills them with data from arrays. It's used directly and by packages built on top of it:" +msgstr "O [Yii Hydrator](https://github.com/yiisoft/hydrator) cria objetos e os preenche com dados de arrays. Ele é usado diretamente e por pacotes construídos sobre ele:" + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "[Yii Input HTTP](https://github.com/yiisoft/input-http) fills request input objects from query parameters, request body, and, with the help of [Yii Router](https://github.com/yiisoft/router), route arguments." +msgstr "O [Yii Input HTTP](https://github.com/yiisoft/input-http) preenche objetos de entrada da requisição a partir de parâmetros da query string, do corpo da requisição e, com a ajuda do [Yii Router](https://github.com/yiisoft/router), dos argumentos da rota." + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "[Yii Form Model](https://github.com/yiisoft/form-model) provides `FormHydrator` that fills form models from submitted data." +msgstr "O [Yii Form Model](https://github.com/yiisoft/form-model) fornece o `FormHydrator`, que preenche form models com os dados enviados." + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "The incoming data is usually \"raw\": HTTP requests, database rows, and queue messages contain strings, numbers, and arrays. Before assigning a value to a property or passing it to a constructor parameter, the hydrator converts it to the declared type. A *type caster* performs this conversion. By writing your own type caster, you teach the hydrator to create your types, such as value objects, from raw data." +msgstr "Os dados recebidos geralmente são \"brutos\": requisições HTTP, linhas do banco de dados e mensagens de fila contêm strings, números e arrays. Antes de atribuir um valor a uma propriedade ou passá-lo a um parâmetro do construtor, o hydrator o converte para o tipo declarado. Um *type caster* faz essa conversão. Ao escrever seu próprio type caster, você ensina o hydrator a criar seus tipos, como value objects, a partir de dados brutos." + +#. type: Title ## +#: ../src/cookbook/custom-hydrator-type-casters.md +#, no-wrap +msgid "Why custom type casters" +msgstr "Por que type casters personalizados" + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "Out of the box, the hydrator uses a composite type caster with two casters:" +msgstr "Por padrão, o hydrator usa um type caster composto com dois casters:" + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "`PhpNativeTypeCaster` casts values to built-in PHP types, such as `int`, `string`, `bool`, and `array`." +msgstr "`PhpNativeTypeCaster` converte valores para tipos nativos do PHP, como `int`, `string`, `bool` e `array`." + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "`HydratorTypeCaster` creates nested objects from arrays using the hydrator itself." +msgstr "`HydratorTypeCaster` cria objetos aninhados a partir de arrays usando o próprio hydrator." + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "That's enough for DTOs with scalar properties, but not for a rich domain model. Consider a property typed as `UserId`, `Email`, or `Money`. The incoming value is a string, and neither of the default casters knows how to turn it into such an object. So you end up declaring the property as `string` and converting it by hand wherever it's used:" +msgstr "Isso basta para DTOs com propriedades escalares, mas não para um modelo de domínio rico. Considere uma propriedade tipada como `UserId`, `Email` ou `Money`. O valor recebido é uma string, e nenhum dos casters padrão sabe transformá-lo em um objeto desses. Assim, você acaba declarando a propriedade como `string` e convertendo-a manualmente onde quer que ela seja usada:" + +#. type: Fenced code block (php) +#: ../src/cookbook/custom-hydrator-type-casters.md +#, no-wrap +msgid "" +"final class CreatePostForm extends FormModel\n" +"{\n" +" public string $authorId = '';\n" +"}\n" +"\n" +"// In every action that uses the form:\n" +"try {\n" +" $authorId = new UserId($form->authorId);\n" +"} catch (InvalidArgumentException) {\n" +" // Report the error somehow.\n" +"}\n" +msgstr "" +"final class CreatePostForm extends FormModel\n" +"{\n" +" public string $authorId = '';\n" +"}\n" +"\n" +"// Em toda action que usa o formulário:\n" +"try {\n" +" $authorId = new UserId($form->authorId);\n" +"} catch (InvalidArgumentException) {\n" +" // Reporte o erro de alguma forma.\n" +"}\n" + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "With a type caster for `UserId`, you can declare the property with its real type. The conversion happens during hydration:" +msgstr "Com um type caster para `UserId`, você pode declarar a propriedade com seu tipo real. A conversão acontece durante a hidratação:" + +#. type: Fenced code block (php) +#: ../src/cookbook/custom-hydrator-type-casters.md +#, no-wrap +msgid "" +"final class CreatePostForm extends FormModel\n" +"{\n" +" public ?UserId $authorId = null;\n" +"}\n" +"\n" +"// $form->authorId is already an instance of UserId.\n" +msgstr "" +"final class CreatePostForm extends FormModel\n" +"{\n" +" public ?UserId $authorId = null;\n" +"}\n" +"\n" +"// $form->authorId já é uma instância de UserId.\n" + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "The conversion logic lives in a single place. Once you register the caster, the hydrator applies it to every property and constructor parameter of the matching type in every object it creates." +msgstr "A lógica de conversão fica em um único lugar. Depois que você registra o caster, o hydrator o aplica a todas as propriedades e parâmetros de construtor do tipo correspondente em todos os objetos que ele cria." + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "Typical use cases are:" +msgstr "Casos de uso típicos:" + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "value objects, such as entity IDs, emails, phone numbers, and money amounts." +msgstr "value objects, como IDs de entidades, e-mails, números de telefone e valores monetários." + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "types from third-party libraries, such as UUIDs, dates, or currencies." +msgstr "tipos de bibliotecas de terceiros, como UUIDs, datas ou moedas." + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "consistent normalization of values, for example, parsing dates in a format specific to your application." +msgstr "normalização consistente de valores, por exemplo, interpretar datas em um formato específico da sua aplicação." + +#. type: Title ## +#: ../src/cookbook/custom-hydrator-type-casters.md +#, no-wrap +msgid "Anatomy of a type caster" +msgstr "Anatomia de um type caster" + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "A type caster implements `Yiisoft\\Hydrator\\TypeCaster\\TypeCasterInterface` with a single method:" +msgstr "Um type caster implementa `Yiisoft\\Hydrator\\TypeCaster\\TypeCasterInterface`, que tem um único método:" + +#. type: Fenced code block (php) +#: ../src/cookbook/custom-hydrator-type-casters.md +#, no-wrap +msgid "public function cast(mixed $value, TypeCastContext $context): Result;\n" +msgstr "public function cast(mixed $value, TypeCastContext $context): Result;\n" + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "`$value` is the raw value to convert." +msgstr "`$value` é o valor bruto a ser convertido." + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "`$context` is a `Yiisoft\\Hydrator\\TypeCaster\\TypeCastContext`. Its `getReflectionType()` method returns the declared type of the target property or constructor parameter. Use it to decide whether the caster supports the target type." +msgstr "`$context` é um `Yiisoft\\Hydrator\\TypeCaster\\TypeCastContext`. Seu método `getReflectionType()` retorna o tipo declarado da propriedade ou do parâmetro de construtor de destino. Use-o para decidir se o caster suporta o tipo de destino." + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "The method returns a `Yiisoft\\Hydrator\\Result`: `Result::success($convertedValue)` if the conversion succeeded or `Result::fail()` if the caster can't handle the value." +msgstr "O método retorna um `Yiisoft\\Hydrator\\Result`: `Result::success($convertedValue)` se a conversão deu certo ou `Result::fail()` se o caster não consegue lidar com o valor." + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "Follow these rules when writing a type caster:" +msgstr "Siga estas regras ao escrever um type caster:" + +#. type: Bullet: '1. ' +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "**Check the target type first.** If the declared type isn't the one your caster is responsible for, return `Result::fail()` right away so other casters can handle the value." +msgstr "**Verifique o tipo de destino primeiro.** Se o tipo declarado não for aquele pelo qual seu caster é responsável, retorne `Result::fail()` imediatamente para que outros casters possam lidar com o valor." + +#. type: Bullet: '2. ' +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "**Handle both named and union types.** PHP represents a nullable type such as `?Email` (or `Email|null`) with `ReflectionNamedType` and `Email|string` with `ReflectionUnionType`. In the latter case, look for your type among its subtypes." +msgstr "**Trate tipos nomeados e tipos união.** O PHP representa um tipo anulável como `?Email` (ou `Email|null`) com `ReflectionNamedType` e `Email|string` com `ReflectionUnionType`. No segundo caso, procure seu tipo entre os subtipos." + +#. type: Bullet: '3. ' +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "**Don't handle `null` yourself.** If the value is `null`, just return `Result::fail()`. `PhpNativeTypeCaster` returns `null` for any type that allows it, so a `null` value assigned to `?Email` stays `null`." +msgstr "**Não trate `null` você mesmo.** Se o valor for `null`, apenas retorne `Result::fail()`. O `PhpNativeTypeCaster` retorna `null` para qualquer tipo que o permita, então um valor `null` atribuído a `?Email` continua `null`." + +#. type: Bullet: '4. ' +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "**Accept already converted values.** If the value is already an instance of the target type, return it as is." +msgstr "**Aceite valores já convertidos.** Se o valor já for uma instância do tipo de destino, retorne-o como está." + +#. type: Bullet: '5. ' +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "**Fail instead of throwing.** If your caster can't convert the value, for example, a malformed string, return `Result::fail()`. An exception would break the whole hydration." +msgstr "**Falhe em vez de lançar exceções.** Se seu caster não consegue converter o valor, por exemplo, uma string malformada, retorne `Result::fail()`. Uma exceção quebraria toda a hidratação." + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "Keep in mind what happens when no caster succeeds:" +msgstr "Tenha em mente o que acontece quando nenhum caster tem sucesso:" + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "For a property, the cast fails silently. The hydrator doesn't set the property or report an error, so the property keeps its default value. Reporting the problem to the user is the job of the validation that runs after hydration. See [Null and invalid values](#null-and-invalid-values) for an example." +msgstr "Para uma propriedade, a conversão falha silenciosamente. O hydrator não define a propriedade nem reporta um erro, então a propriedade mantém seu valor padrão. Reportar o problema ao usuário é papel da validação que roda após a hidratação. Veja [Valores nulos e inválidos](#valores-nulos-e-invalidos) para um exemplo." + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "For a constructor parameter, the hydrator omits the argument. If the parameter has a default value, it's used. Otherwise, object creation fails with `WrongConstructorArgumentsCountException`, even for a nullable parameter without a default value." +msgstr "Para um parâmetro de construtor, o hydrator omite o argumento. Se o parâmetro tiver um valor padrão, ele é usado. Caso contrário, a criação do objeto falha com `WrongConstructorArgumentsCountException`, mesmo para um parâmetro anulável sem valor padrão." + +#. type: Title ## +#: ../src/cookbook/custom-hydrator-type-casters.md +#, no-wrap +msgid "Registering a type caster" +msgstr "Registrando um type caster" + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "Combine type casters with `CompositeTypeCaster`. It tries the casters one by one and uses the result of the first one that succeeds. To add your caster, redefine `TypeCasterInterface` in the DI container configuration, for example, in `config/common/di/hydrator.php`. The `HydratorInterface` implementation from the container uses this chain, as do packages that rely on it, such as Yii Input HTTP:" +msgstr "Combine type casters com `CompositeTypeCaster`. Ele tenta os casters um a um e usa o resultado do primeiro que tiver sucesso. Para adicionar seu caster, redefina `TypeCasterInterface` na configuração do container de DI, por exemplo, em `config/common/di/hydrator.php`. A implementação de `HydratorInterface` do container usa essa cadeia, assim como os pacotes que dependem dela, como o Yii Input HTTP:" + +#. type: Fenced code block (php) +#: ../src/cookbook/custom-hydrator-type-casters.md +#, no-wrap +msgid "" +" static fn() => new CompositeTypeCaster(\n" +" new UuidValueTypeCaster(),\n" +" new PhpNativeTypeCaster(),\n" +" new HydratorTypeCaster(),\n" +" ),\n" +"];\n" +msgstr "" +" static fn() => new CompositeTypeCaster(\n" +" new UuidValueTypeCaster(),\n" +" new PhpNativeTypeCaster(),\n" +" new HydratorTypeCaster(),\n" +" ),\n" +"];\n" + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "Since the first successful result wins, the order matters:" +msgstr "Como o primeiro resultado bem-sucedido vence, a ordem importa:" + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "Put custom casters before `PhpNativeTypeCaster`. Otherwise, for a property declared as `UserId|string`, `PhpNativeTypeCaster` accepts a string as is, and your caster never runs." +msgstr "Coloque os casters personalizados antes do `PhpNativeTypeCaster`. Caso contrário, para uma propriedade declarada como `UserId|string`, o `PhpNativeTypeCaster` aceita a string como está, e seu caster nunca é executado." + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "Keep the default casters in the list. `PhpNativeTypeCaster` casts scalar values to built-in types, and `HydratorTypeCaster` creates nested objects from arrays." +msgstr "Mantenha os casters padrão na lista. O `PhpNativeTypeCaster` converte valores escalares para tipos nativos, e o `HydratorTypeCaster` cria objetos aninhados a partir de arrays." + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "If a caster has dependencies, take it from the container:" +msgstr "Se um caster tiver dependências, obtenha-o do container:" + +#. type: Fenced code block (php) +#: ../src/cookbook/custom-hydrator-type-casters.md +#, no-wrap +msgid "" +" static fn(ContainerInterface $container) => new CompositeTypeCaster(\n" +" $container->get(MoneyTypeCaster::class),\n" +" new PhpNativeTypeCaster(),\n" +" new HydratorTypeCaster(),\n" +" ),\n" +"];\n" +msgstr "" +" static fn(ContainerInterface $container) => new CompositeTypeCaster(\n" +" $container->get(MoneyTypeCaster::class),\n" +" new PhpNativeTypeCaster(),\n" +" new HydratorTypeCaster(),\n" +" ),\n" +"];\n" + +#. type: Title ### +#: ../src/cookbook/custom-hydrator-type-casters.md +#, no-wrap +msgid "Registering for form models" +msgstr "Registrando para form models" + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "`FormHydrator` from Yii Form Model doesn't use `TypeCasterInterface`. Its DI configuration creates a dedicated hydrator with its own chain of type casters, so add your caster there as well:" +msgstr "O `FormHydrator` do Yii Form Model não usa `TypeCasterInterface`. Sua configuração de DI cria um hydrator dedicado com sua própria cadeia de type casters, então adicione seu caster lá também:" + +#. type: Fenced code block (php) +#: ../src/cookbook/custom-hydrator-type-casters.md +#, no-wrap +msgid "" +" [\n" +" '__construct()' => [\n" +" 'hydrator' => DynamicReference::to([\n" +" 'class' => Hydrator::class,\n" +" '__construct()' => [\n" +" 'typeCaster' => new CompositeTypeCaster(\n" +" new NullTypeCaster(emptyString: true),\n" +" new UuidValueTypeCaster(),\n" +" new PhpNativeTypeCaster(),\n" +" new NonArrayTypeCaster(),\n" +" new HydratorTypeCaster(),\n" +" ),\n" +" ],\n" +" ]),\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +" [\n" +" '__construct()' => [\n" +" 'hydrator' => DynamicReference::to([\n" +" 'class' => Hydrator::class,\n" +" '__construct()' => [\n" +" 'typeCaster' => new CompositeTypeCaster(\n" +" new NullTypeCaster(emptyString: true),\n" +" new UuidValueTypeCaster(),\n" +" new PhpNativeTypeCaster(),\n" +" new NonArrayTypeCaster(),\n" +" new HydratorTypeCaster(),\n" +" ),\n" +" ],\n" +" ]),\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "This definition replaces the one from the package, so keep its type casters. This example uses the list from `config/di.php` of Yii Form Model 1.1. Check it against the version you use. `NullTypeCaster` turns empty strings submitted by forms into `null` for nullable properties, so it stays first." +msgstr "Essa definição substitui a do pacote, então mantenha os type casters dele. Este exemplo usa a lista do `config/di.php` do Yii Form Model 1.1. Confira com a versão que você usa. O `NullTypeCaster` transforma strings vazias enviadas por formulários em `null` para propriedades anuláveis, por isso ele continua em primeiro." + +#. type: Title ## +#: ../src/cookbook/custom-hydrator-type-casters.md +#, no-wrap +msgid "Example: UUID value objects" +msgstr "Exemplo: value objects de UUID" + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "Entity IDs often use value objects, such as `UserId`, `PostId`, and `OrderId`, instead of plain strings. Such objects make method signatures self-documenting and prevent passing a post ID where a method expects a user ID. The following example shows how to write a type caster that creates them from UUID strings." +msgstr "IDs de entidades frequentemente usam value objects, como `UserId`, `PostId` e `OrderId`, em vez de strings simples. Esses objetos tornam as assinaturas dos métodos autodocumentadas e impedem que você passe um ID de post onde um método espera um ID de usuário. O exemplo a seguir mostra como escrever um type caster que os cria a partir de strings UUID." + +#. type: Title ### +#: ../src/cookbook/custom-hydrator-type-casters.md +#, no-wrap +msgid "Value objects" +msgstr "Value objects" + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "All ID value objects extend an abstract `UuidValue` class. The example uses [ramsey/uuid](https://github.com/ramsey/uuid) to validate and generate UUIDs:" +msgstr "Todos os value objects de ID estendem uma classe abstrata `UuidValue`. O exemplo usa [ramsey/uuid](https://github.com/ramsey/uuid) para validar e gerar UUIDs:" + +#. type: Fenced code block (shell) +#: ../src/cookbook/custom-hydrator-type-casters.md +#, no-wrap +msgid "composer require ramsey/uuid\n" +msgstr "composer require ramsey/uuid\n" + +#. type: Fenced code block (php) +#: ../src/cookbook/custom-hydrator-type-casters.md +#, no-wrap +msgid "" +"value = Uuid::fromString($value)->toString();\n" +" }\n" +"\n" +" public static function generate(): static\n" +" {\n" +" return new static(Uuid::uuid7()->toString());\n" +" }\n" +"\n" +" public function equals(self $other): bool\n" +" {\n" +" return $other instanceof static && $other->value === $this->value;\n" +" }\n" +"\n" +" public function __toString(): string\n" +" {\n" +" return $this->value;\n" +" }\n" +"}\n" +msgstr "" +"value = Uuid::fromString($value)->toString();\n" +" }\n" +"\n" +" public static function generate(): static\n" +" {\n" +" return new static(Uuid::uuid7()->toString());\n" +" }\n" +"\n" +" public function equals(self $other): bool\n" +" {\n" +" return $other instanceof static && $other->value === $this->value;\n" +" }\n" +"\n" +" public function __toString(): string\n" +" {\n" +" return $this->value;\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "The constructor is final, so `new static()` is safe and creates every child class from a string the same way. A concrete ID is just an empty child class:" +msgstr "O construtor é final, então `new static()` é seguro e cria todas as classes filhas a partir de uma string da mesma forma. Um ID concreto é apenas uma classe filha vazia:" + +#. type: Fenced code block (php) +#: ../src/cookbook/custom-hydrator-type-casters.md +#, no-wrap +msgid "" +"findUuidValueClass($context->getReflectionType());\n" +" if ($class === null) {\n" +" return Result::fail();\n" +" }\n" +"\n" +" if ($value instanceof $class) {\n" +" return Result::success($value);\n" +" }\n" +"\n" +" if (!is_string($value) || !Uuid::isValid($value)) {\n" +" return Result::fail();\n" +" }\n" +"\n" +" return Result::success(new $class($value));\n" +" }\n" +"\n" +" /**\n" +" * Returns the `UuidValue` child class from the declared type, or `null` if there is none or there are several\n" +" * of them, such as in `UserId|PostId`.\n" +" *\n" +" * @return class-string|null\n" +" */\n" +" private function findUuidValueClass(?ReflectionType $type): ?string\n" +" {\n" +" $types = match (true) {\n" +" $type instanceof ReflectionNamedType => [$type],\n" +" $type instanceof ReflectionUnionType => $type->getTypes(),\n" +" default => [],\n" +" };\n" +"\n" +" $classes = [];\n" +" foreach ($types as $subType) {\n" +" if (\n" +" $subType instanceof ReflectionNamedType\n" +" && !$subType->isBuiltin()\n" +" && is_subclass_of($subType->getName(), UuidValue::class)\n" +" ) {\n" +" $classes[] = $subType->getName();\n" +" }\n" +" }\n" +"\n" +" return count($classes) === 1 ? $classes[0] : null;\n" +" }\n" +"}\n" +msgstr "" +"findUuidValueClass($context->getReflectionType());\n" +" if ($class === null) {\n" +" return Result::fail();\n" +" }\n" +"\n" +" if ($value instanceof $class) {\n" +" return Result::success($value);\n" +" }\n" +"\n" +" if (!is_string($value) || !Uuid::isValid($value)) {\n" +" return Result::fail();\n" +" }\n" +"\n" +" return Result::success(new $class($value));\n" +" }\n" +"\n" +" /**\n" +" * Retorna a classe filha de `UuidValue` a partir do tipo declarado, ou `null` se não houver nenhuma ou houver várias\n" +" * delas, como em `UserId|PostId`.\n" +" *\n" +" * @return class-string|null\n" +" */\n" +" private function findUuidValueClass(?ReflectionType $type): ?string\n" +" {\n" +" $types = match (true) {\n" +" $type instanceof ReflectionNamedType => [$type],\n" +" $type instanceof ReflectionUnionType => $type->getTypes(),\n" +" default => [],\n" +" };\n" +"\n" +" $classes = [];\n" +" foreach ($types as $subType) {\n" +" if (\n" +" $subType instanceof ReflectionNamedType\n" +" && !$subType->isBuiltin()\n" +" && is_subclass_of($subType->getName(), UuidValue::class)\n" +" ) {\n" +" $classes[] = $subType->getName();\n" +" }\n" +" }\n" +"\n" +" return count($classes) === 1 ? $classes[0] : null;\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "The caster follows the [rules for writing a type caster](#anatomy-of-a-type-caster). It chooses the class to create from the declared type. All IDs share the same UUID format, so a string alone can't tell whether it's a user ID or a post ID. A single caster therefore serves all `UuidValue` child classes, and adding a new ID class doesn't require changes to the caster. For the same reason, the caster fails for a type with several ID classes, such as `UserId|PostId`. There's no way to choose the right one." +msgstr "O caster segue as [regras para escrever um type caster](#anatomia-de-um-type-caster). Ele escolhe a classe a ser criada a partir do tipo declarado. Todos os IDs compartilham o mesmo formato UUID, então uma string sozinha não diz se é um ID de usuário ou de post. Por isso, um único caster atende todas as classes filhas de `UuidValue`, e adicionar uma nova classe de ID não exige mudanças no caster. Pelo mesmo motivo, o caster falha para um tipo com várias classes de ID, como `UserId|PostId`. Não há como escolher a correta." + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "Register `UuidValueTypeCaster` as shown in the [Registering a type caster](#registering-a-type-caster) section, including the [form model configuration](#registering-for-form-models) if you use Yii Form Model." +msgstr "Registre o `UuidValueTypeCaster` como mostrado na seção [Registrando um type caster](#registrando-um-type-caster), incluindo a [configuração para form models](#registrando-para-form-models) se você usa o Yii Form Model." + +#. type: Title ### +#: ../src/cookbook/custom-hydrator-type-casters.md +#, no-wrap +msgid "Using the value objects" +msgstr "Usando os value objects" + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "Now any class that's populated by the hydrator can declare ID value objects directly." +msgstr "Agora qualquer classe preenchida pelo hydrator pode declarar value objects de ID diretamente." + +#. type: Title #### +#: ../src/cookbook/custom-hydrator-type-casters.md +#, no-wrap +msgid "Hydrator" +msgstr "Hydrator" + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "The same string becomes a different value object depending on the type of the property:" +msgstr "A mesma string se torna um value object diferente dependendo do tipo da propriedade:" + +#. type: Fenced code block (php) +#: ../src/cookbook/custom-hydrator-type-casters.md +#, no-wrap +msgid "" +"use App\\Post\\PostId;\n" +"use App\\User\\UserId;\n" +"use Yiisoft\\Hydrator\\HydratorInterface;\n" +"\n" +"final class CommentFilter\n" +"{\n" +" public ?UserId $authorId = null;\n" +" public ?PostId $postId = null;\n" +"}\n" +"\n" +"/** @var HydratorInterface $hydrator */\n" +"$filter = $hydrator->create(CommentFilter::class, [\n" +" 'authorId' => '0192f2a4-7a4b-7c3e-9a1b-3f5c8d2e6a10',\n" +" 'postId' => '0192f2a4-7a4b-7c3e-9a1b-3f5c8d2e6a10',\n" +"]);\n" +"\n" +"// $filter->authorId is UserId, $filter->postId is PostId.\n" +"// $filter->authorId->equals($filter->postId) returns false.\n" +msgstr "" +"use App\\Post\\PostId;\n" +"use App\\User\\UserId;\n" +"use Yiisoft\\Hydrator\\HydratorInterface;\n" +"\n" +"final class CommentFilter\n" +"{\n" +" public ?UserId $authorId = null;\n" +" public ?PostId $postId = null;\n" +"}\n" +"\n" +"/** @var HydratorInterface $hydrator */\n" +"$filter = $hydrator->create(CommentFilter::class, [\n" +" 'authorId' => '0192f2a4-7a4b-7c3e-9a1b-3f5c8d2e6a10',\n" +" 'postId' => '0192f2a4-7a4b-7c3e-9a1b-3f5c8d2e6a10',\n" +"]);\n" +"\n" +"// $filter->authorId é UserId, $filter->postId é PostId.\n" +"// $filter->authorId->equals($filter->postId) retorna false.\n" + +#. type: Title #### +#: ../src/cookbook/custom-hydrator-type-casters.md +#, no-wrap +msgid "Request input" +msgstr "Entrada da requisição " + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "The [Yii Input HTTP](https://github.com/yiisoft/input-http) package uses the hydrator to fill request input objects, so the same type caster works for query parameters, request body, and route arguments. The `RouteArgument` attribute comes from [Yii Router](https://github.com/yiisoft/router). Extend `AbstractInput` to get the input validated after hydration:" +msgstr "O pacote [Yii Input HTTP](https://github.com/yiisoft/input-http) usa o hydrator para preencher objetos de entrada da requisição, então o mesmo type caster funciona para parâmetros da query string, corpo da requisição e argumentos da rota. O atributo `RouteArgument` vem do [Yii Router](https://github.com/yiisoft/router). Estenda `AbstractInput` para que a entrada seja validada após a hidratação:" + +#. type: Fenced code block (php) +#: ../src/cookbook/custom-hydrator-type-casters.md +#, no-wrap +msgid "" +"getValidationResult()->isValid()) {\n" +" // Return an error response.\n" +" }\n" +"\n" +" // $input->id is PostId, $input->authorId is UserId.\n" +" // ...\n" +" }\n" +"}\n" +msgstr "" +"use Psr\\Http\\Message\\ResponseInterface;\n" +"\n" +"final readonly class Action\n" +"{\n" +" public function __invoke(UpdatePostInput $input): ResponseInterface\n" +" {\n" +" if (!$input->getValidationResult()->isValid()) {\n" +" // Retorne uma resposta de erro.\n" +" }\n" +"\n" +" // $input->id é PostId, $input->authorId é UserId.\n" +" // ...\n" +" }\n" +"}\n" + +#. type: Title #### +#: ../src/cookbook/custom-hydrator-type-casters.md +#, no-wrap +msgid "Form model" +msgstr "Form model" + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "`FormHydrator` from [Yii Form Model](https://github.com/yiisoft/form-model) populates form models. Once you [register the caster for form models](#registering-for-form-models), you can declare form properties as value objects too:" +msgstr "O `FormHydrator` do [Yii Form Model](https://github.com/yiisoft/form-model) preenche form models. Depois que você [registra o caster para form models](#registrando-para-form-models), também pode declarar propriedades de formulário como value objects:" + +#. type: Fenced code block (php) +#: ../src/cookbook/custom-hydrator-type-casters.md +#, no-wrap +msgid "" +"formHydrator->populateFromPostAndValidate($form, $request)) {\n" +" // $form->authorId is UserId.\n" +" // ...\n" +" }\n" +"\n" +" // ...\n" +" }\n" +"}\n" +msgstr "" +"use Psr\\Http\\Message\\ResponseInterface;\n" +"use Psr\\Http\\Message\\ServerRequestInterface;\n" +"use Yiisoft\\FormModel\\FormHydrator;\n" +"\n" +"final readonly class Action\n" +"{\n" +" public function __construct(\n" +" private FormHydrator $formHydrator,\n" +" ) {}\n" +"\n" +" public function __invoke(ServerRequestInterface $request): ResponseInterface\n" +" {\n" +" $form = new CreatePostForm();\n" +"\n" +" if ($this->formHydrator->populateFromPostAndValidate($form, $request)) {\n" +" // $form->authorId é UserId.\n" +" // ...\n" +" }\n" +"\n" +" // ...\n" +" }\n" +"}\n" + +#. type: Title ### +#: ../src/cookbook/custom-hydrator-type-casters.md +#, no-wrap +msgid "Null and invalid values" +msgstr "Valores nulos e inválidos " + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "Here is what happens with a property declared as `?UserId` for different input values:" +msgstr "Veja o que acontece com uma propriedade declarada como `?UserId` para diferentes valores de entrada:" + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +#, no-wrap +msgid "" +"| Input value | Handled by | Property value |\n" +"|------------------------------------------|------------------------|----------------------------------|\n" +"| `'0192f2a4-7a4b-7c3e-9a1b-3f5c8d2e6a10'` | `UuidValueTypeCaster` | `UserId` instance |\n" +"| `null` | `PhpNativeTypeCaster` | `null` |\n" +"| `'not-a-uuid'` | none, all casters fail | default value, `null` in example |\n" +msgstr "" +"| Valor de entrada | Tratado por | Valor da propriedade |\n" +"|------------------------------------------|------------------------|----------------------------------|\n" +"| `'0192f2a4-7a4b-7c3e-9a1b-3f5c8d2e6a10'` | `UuidValueTypeCaster` | instância de `UserId` |\n" +"| `null` | `PhpNativeTypeCaster` | `null` |\n" +"| `'not-a-uuid'` | nenhum, todos falham | valor padrão, `null` no exemplo |\n" + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "The last row is the important one: the hydrator doesn't report the malformed value. With the `Required` rule, validation catches it with the \"cannot be blank\" error. See the [request input](#request-input) and [form model](#form-model) examples. But if the property is optional, an invalid UUID is silently turned into `null` and is indistinguishable from a missing value. If that's not acceptable, keep the raw value for validation: declare the property as `string`, validate its format, and convert it to the value object after validation." +msgstr "A última linha é a importante: o hydrator não reporta o valor malformado. Com a regra `Required`, a validação o detecta com o erro \"cannot be blank\". Veja os exemplos de [entrada da requisição](#entrada-da-requisicao) e [form model](#form-model). Mas, se a propriedade for opcional, um UUID inválido é silenciosamente transformado em `null` e fica indistinguível de um valor ausente. Se isso não for aceitável, mantenha o valor bruto para validação: declare a propriedade como `string`, valide seu formato e converta-a para o value object após a validação." + +#. type: Title ## +#: ../src/cookbook/custom-hydrator-type-casters.md +#, no-wrap +msgid "When to use a type caster" +msgstr "Quando usar um type caster" + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "A type caster fits well when the conversion:" +msgstr "Um type caster é uma boa escolha quando a conversão:" + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "depends only on the value and the declared type." +msgstr "depende apenas do valor e do tipo declarado." + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "is the same everywhere in the application." +msgstr "é a mesma em toda a aplicação." + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "doesn't need I/O, such as database queries or HTTP calls." +msgstr "não precisa de I/O, como consultas ao banco de dados ou chamadas HTTP." + +#. type: Plain text +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "Value objects for IDs, emails, and money amounts match all three. Keep the conversion in a dedicated mapper or a domain factory instead when it:" +msgstr "Value objects para IDs, e-mails e valores monetários atendem aos três critérios. Mantenha a conversão em um mapper dedicado ou em uma factory de domínio quando ela:" + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "needs a database lookup, for example, turning an ID into a loaded entity." +msgstr "precisa consultar o banco de dados, por exemplo, transformar um ID em uma entidade carregada." + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "depends on context, such as the current user." +msgstr "depende de contexto, como o usuário atual." + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "combines several input fields into one object." +msgstr "combina vários campos de entrada em um único objeto." + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-hydrator-type-casters.md +msgid "differs between use cases." +msgstr "difere entre casos de uso." diff --git a/_translations/po/pt-BR/cookbook_custom-migration-template.md.po b/_translations/po/pt-BR/cookbook_custom-migration-template.md.po new file mode 100644 index 00000000..c5f32e99 --- /dev/null +++ b/_translations/po/pt-BR/cookbook_custom-migration-template.md.po @@ -0,0 +1,297 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-06-05 22:11+0000\n" +"PO-Revision-Date: 2026-06-05 22:11+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/cookbook/custom-migration-template.md +#, no-wrap +msgid "Using a custom migration template" +msgstr "Usando um template de migration personalizado" + +#. type: Plain text +#: ../src/cookbook/custom-migration-template.md +msgid "The `migrate:create` command from `yiisoft/db-migration` generates migration classes from PHP view templates. Use a custom template when your project wants a standard header, strict class shape, comments, helper calls, or team-specific placeholders in every new migration." +msgstr "O comando `migrate:create` do `yiisoft/db-migration` gera classes de migration a partir de templates PHP de view. Use um template personalizado quando seu projeto quiser um cabeçalho padrão, um formato de classe rígido, comentários, chamadas a helpers ou placeholders específicos da equipe em toda nova migration." + +#. type: Plain text +#: ../src/cookbook/custom-migration-template.md +msgid "This recipe assumes migrations are already configured as described in the [Database migrations](../guide/databases/db-migrations.md) guide." +msgstr "Esta receita assume que as migrations já estão configuradas como descrito no guia [Migrations de banco de dados](../guide/databases/db-migrations.md)." + +#. type: Title ## +#: ../src/cookbook/custom-migration-template.md +#, no-wrap +msgid "Create a template" +msgstr "Crie um template" + +#. type: Plain text +#: ../src/cookbook/custom-migration-template.md +msgid "Create `resources/migration-templates/migration.php`:" +msgstr "Crie `resources/migration-templates/migration.php`:" + +#. type: Fenced code block (php) +#: ../src/cookbook/custom-migration-template.md +#, no-wrap +msgid "" +"\n" +"\n" +"use Yiisoft\\Db\\Migration\\MigrationBuilder;\n" +"use Yiisoft\\Db\\Migration\\RevertibleMigrationInterface;\n" +"\n" +"final class implements RevertibleMigrationInterface\n" +"{\n" +" public function up(MigrationBuilder $b): void\n" +" {\n" +" // Add forward migration code.\n" +" }\n" +"\n" +" public function down(MigrationBuilder $b): void\n" +" {\n" +" // Add rollback migration code.\n" +" }\n" +"}\n" +msgstr "" +"\n" +"\n" +"use Yiisoft\\Db\\Migration\\MigrationBuilder;\n" +"use Yiisoft\\Db\\Migration\\RevertibleMigrationInterface;\n" +"\n" +"final class implements RevertibleMigrationInterface\n" +"{\n" +" public function up(MigrationBuilder $b): void\n" +" {\n" +" // Add forward migration code.\n" +" }\n" +"\n" +" public function down(MigrationBuilder $b): void\n" +" {\n" +" // Add rollback migration code.\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/cookbook/custom-migration-template.md +msgid "The template is a PHP file that prints the generated migration. For the default `create` command, the most useful variables are `$className` and `$namespace`." +msgstr "O template é um arquivo PHP que imprime a migration gerada. Para o comando `create` padrão, as variáveis mais úteis são `$className` e `$namespace`." + +#. type: Title ## +#: ../src/cookbook/custom-migration-template.md +#, no-wrap +msgid "Configure the generator" +msgstr "Configure o gerador" + +#. type: Plain text +#: ../src/cookbook/custom-migration-template.md +msgid "Create `config/common/di/migration-generator.php`:" +msgstr "Crie `config/common/di/migration-generator.php`:" + +#. type: Fenced code block (php) +#: ../src/cookbook/custom-migration-template.md +#, no-wrap +msgid "" +" [\n" +" 'setTemplate()' => [\n" +" 'create',\n" +" dirname(__DIR__, 3) . '/resources/migration-templates/migration.php',\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +" [\n" +" 'setTemplate()' => [\n" +" 'create',\n" +" dirname(__DIR__, 3) . '/resources/migration-templates/migration.php',\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/cookbook/custom-migration-template.md +msgid "The `create` key changes the template used by:" +msgstr "A chave `create` muda o template usado por:" + +#. type: Fenced code block (shell) +#: ../src/cookbook/custom-migration-template.md +#, no-wrap +msgid "./yii migrate:create audit_log\n" +msgstr "./yii migrate:create audit_log\n" + +#. type: Plain text +#: ../src/cookbook/custom-migration-template.md +msgid "The command asks for confirmation and then writes a migration using your template." +msgstr "O comando pede confirmação e então grava uma migration usando o seu template." + +#. type: Plain text +#: ../src/cookbook/custom-migration-template.md +msgid "If the new DI file is not picked up, rebuild the config merge plan:" +msgstr "Se o novo arquivo de DI não for carregado, reconstrua o merge plan da configuração:" + +#. type: Fenced code block (sh) +#: ../src/cookbook/custom-migration-template.md ../src/cookbook/using-yii-in-third-party-apps.md ../src/guide/structure/designing-packages.md ../src/guide/structure/module.md ../src/guide/structure/package.md ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "composer yii-config-rebuild\n" +msgstr "composer yii-config-rebuild\n" + +#. type: Title ## +#: ../src/cookbook/custom-migration-template.md +#, no-wrap +msgid "Configure multiple templates" +msgstr "Configure vários templates" + +#. type: Plain text +#: ../src/cookbook/custom-migration-template.md +msgid "`yiisoft/db-migration` supports these template keys:" +msgstr "O `yiisoft/db-migration` suporta estas chaves de template:" + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-migration-template.md +msgid "`create`" +msgstr "`create`" + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-migration-template.md +msgid "`table`" +msgstr "`table`" + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-migration-template.md +msgid "`dropTable`" +msgstr "`dropTable`" + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-migration-template.md +msgid "`addColumn`" +msgstr "`addColumn`" + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-migration-template.md +msgid "`dropColumn`" +msgstr "`dropColumn`" + +#. type: Bullet: '- ' +#: ../src/cookbook/custom-migration-template.md +msgid "`junction`" +msgstr "`junction`" + +#. type: Plain text +#: ../src/cookbook/custom-migration-template.md +msgid "To replace multiple templates at once, use `setTemplates()`:" +msgstr "Para substituir vários templates de uma vez, use `setTemplates()`:" + +#. type: Fenced code block (php) +#: ../src/cookbook/custom-migration-template.md +#, no-wrap +msgid "" +"use Yiisoft\\Db\\Migration\\Service\\Generate\\CreateService;\n" +"\n" +"return [\n" +" CreateService::class => [\n" +" 'setTemplates()' => [[\n" +" 'create' => dirname(__DIR__, 3) . '/resources/migration-templates/migration.php',\n" +" 'table' => dirname(__DIR__, 3) . '/resources/migration-templates/create-table.php',\n" +" 'dropTable' => dirname(__DIR__, 3) . '/resources/migration-templates/drop-table.php',\n" +" 'addColumn' => dirname(__DIR__, 3) . '/resources/migration-templates/add-column.php',\n" +" 'dropColumn' => dirname(__DIR__, 3) . '/resources/migration-templates/drop-column.php',\n" +" 'junction' => dirname(__DIR__, 3) . '/resources/migration-templates/create-junction.php',\n" +" ]],\n" +" ],\n" +"];\n" +msgstr "" +"use Yiisoft\\Db\\Migration\\Service\\Generate\\CreateService;\n" +"\n" +"return [\n" +" CreateService::class => [\n" +" 'setTemplates()' => [[\n" +" 'create' => dirname(__DIR__, 3) . '/resources/migration-templates/migration.php',\n" +" 'table' => dirname(__DIR__, 3) . '/resources/migration-templates/create-table.php',\n" +" 'dropTable' => dirname(__DIR__, 3) . '/resources/migration-templates/drop-table.php',\n" +" 'addColumn' => dirname(__DIR__, 3) . '/resources/migration-templates/add-column.php',\n" +" 'dropColumn' => dirname(__DIR__, 3) . '/resources/migration-templates/drop-column.php',\n" +" 'junction' => dirname(__DIR__, 3) . '/resources/migration-templates/create-junction.php',\n" +" ]],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/cookbook/custom-migration-template.md +msgid "For table-oriented templates, copy the corresponding file from `vendor/yiisoft/db-migration/resources/views/` and adjust it. Those templates receive additional variables such as `$table`, `$columns`, `$foreignKeys`, and `$tableComment`." +msgstr "Para os templates voltados a tabelas, copie o arquivo correspondente de `vendor/yiisoft/db-migration/resources/views/` e ajuste-o. Esses templates recebem variáveis adicionais, como `$table`, `$columns`, `$foreignKeys` e `$tableComment`." + +#. type: Title ## +#: ../src/cookbook/custom-migration-template.md +#, no-wrap +msgid "Keep templates maintainable" +msgstr "Mantenha os templates fáceis de manter" + +#. type: Plain text +#: ../src/cookbook/custom-migration-template.md +msgid "Keep generated migrations independent from current application services. A migration may run years later, after service APIs have changed. Put stable schema operations in the generated class and leave business logic in console commands or application services." +msgstr "Mantenha as migrations geradas independentes dos serviços atuais da aplicação. Uma migration pode rodar anos depois, quando as APIs dos serviços já mudaram. Coloque operações de schema estáveis na classe gerada e deixe a lógica de negócio em comandos de console ou serviços da aplicação." + +#. type: Plain text +#: ../src/cookbook/custom-migration-template.md +msgid "Do not edit templates under `vendor/`. Copy them into your project and configure `CreateService` to use the copies." +msgstr "Não edite templates dentro de `vendor/`. Copie-os para o seu projeto e configure o `CreateService` para usar as cópias." diff --git a/_translations/po/pt-BR/cookbook_deployment_angie-docker-proxy.md.po b/_translations/po/pt-BR/cookbook_deployment_angie-docker-proxy.md.po new file mode 100644 index 00000000..b19a8be5 --- /dev/null +++ b/_translations/po/pt-BR/cookbook_deployment_angie-docker-proxy.md.po @@ -0,0 +1,488 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-09-25 14:35+0000\n" +"PO-Revision-Date: 2026-09-25 14:35+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/cookbook/deployment/angie-docker-proxy.md +#, no-wrap +msgid "Deploying Yii applications with Angie Docker Proxy" +msgstr "Fazendo deploy de aplicações Yii com o Angie Docker Proxy" + +#. type: Plain text +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "[Angie Docker Proxy](https://hub.docker.com/r/angiesoftware/proxy) is a small reverse proxy for Docker Compose projects. It runs in a separate container alongside the applications, reads the Docker API through the Docker socket, discovers containers using the `VIRTUAL_HOST` and `VIRTUAL_PORT` environment variables, generates the Angie configuration, and automatically obtains TLS certificates using ACME." +msgstr "O [Angie Docker Proxy](https://hub.docker.com/r/angiesoftware/proxy) é um pequeno proxy reverso para projetos Docker Compose. Ele roda em um container separado, ao lado das aplicações, lê a API do Docker pelo socket do Docker, descobre containers pelas variáveis de ambiente `VIRTUAL_HOST` e `VIRTUAL_PORT`, gera a configuração do Angie e obtém certificados TLS automaticamente via ACME." + +#. type: Plain text +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "This approach is useful when you need to run several web applications on one server and enable HTTPS for them without manually editing the reverse proxy configuration for each domain." +msgstr "Essa abordagem é útil quando você precisa rodar várias aplicações web em um servidor e habilitar HTTPS para elas sem editar manualmente a configuração do proxy reverso para cada domínio." + +#. type: Plain text +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "In this example, we'll connect a containerized Yii application to Angie Docker Proxy and configure automatic HTTPS." +msgstr "Neste exemplo, vamos conectar uma aplicação Yii em container ao Angie Docker Proxy e configurar HTTPS automático." + +#. type: Plain text +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "This guide assumes that your Yii application is already packaged as a Docker image and accepts HTTP requests on port 80. Building and configuring the application image is outside the scope of this guide." +msgstr "Este guia assume que sua aplicação Yii já está empacotada como imagem Docker e aceita requisições HTTP na porta 80. Construir e configurar a imagem da aplicação está fora do escopo deste guia." + +#. type: Fenced code block (mermaid) +#: ../src/cookbook/deployment/angie-docker-proxy.md +#, no-wrap +msgid "" +"graph LR\n" +" A[Internet] --> B[Reverse Proxy: Angie]\n" +" B --> C[Yii application]\n" +" B --> D[Another application]\n" +"\n" +" subgraph Docker Compose Project\n" +" B\n" +" C\n" +" D\n" +" end\n" +msgstr "" +"graph LR\n" +" A[Internet] --> B[Proxy reverso: Angie]\n" +" B --> C[Aplicação Yii]\n" +" B --> D[Outra aplicação]\n" +"\n" +" subgraph Docker Compose Project\n" +" B\n" +" C\n" +" D\n" +" end\n" + +#. type: Title ## +#: ../src/cookbook/deployment/angie-docker-proxy.md ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md ../src/cookbook/preface.md +#, no-wrap +msgid "Prerequisites" +msgstr "Pré-requisitos" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "A server with a fresh Linux distribution." +msgstr "Um servidor com uma distribuição Linux recém-instalada." + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "A domain name pointing to your server's IP address." +msgstr "Um nome de domínio apontando para o IP do seu servidor." + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "Docker and Docker Compose." +msgstr "Docker e Docker Compose." + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "Open TCP ports `80` and `443`." +msgstr "Portas TCP `80` e `443` abertas." + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "SSH access to your server." +msgstr "Acesso SSH ao seu servidor." + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "Basic knowledge of Docker and command-line tools." +msgstr "Conhecimento básico de Docker e de ferramentas de linha de comando." + +#. type: Title ## +#: ../src/cookbook/deployment/angie-docker-proxy.md ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Project structure" +msgstr "Estrutura do projeto" + +#. type: Plain text +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "The example requires a single Docker Compose configuration:" +msgstr "O exemplo precisa de uma única configuração do Docker Compose:" + +#. type: Fenced code block (text) +#: ../src/cookbook/deployment/angie-docker-proxy.md +#, no-wrap +msgid "" +"yii-angie-demo/\n" +"└── docker-compose.yml\n" +msgstr "" +"yii-angie-demo/\n" +"└── docker-compose.yml\n" + +#. type: Title ## +#: ../src/cookbook/deployment/angie-docker-proxy.md +#, no-wrap +msgid "Configuring Docker Compose" +msgstr "Configurando o Docker Compose" + +#. type: Plain text +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "Create `docker-compose.yml` with the following configuration. Replace:" +msgstr "Crie o `docker-compose.yml` com a configuração a seguir. Substitua:" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "`admin@example.com` with your email address;" +msgstr "`admin@example.com` pelo seu endereço de e-mail;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "`registry.example.com/yii-app:1.0.0` with your application image;" +msgstr "`registry.example.com/yii-app:1.0.0` pela imagem da sua aplicação;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "`example-demo.example.com` with the domain pointing to your server." +msgstr "`example-demo.example.com` pelo domínio que aponta para o seu servidor." + +#. type: Fenced code block (yaml) +#: ../src/cookbook/deployment/angie-docker-proxy.md +#, no-wrap +msgid "" +"services:\n" +" angie-proxy:\n" +" image: angiesoftware/proxy:latest\n" +" environment:\n" +" - ANGIE_ACME_EMAIL=admin@example.com\n" +" - ANGIE_ACME_URL=https://acme-v02.api.letsencrypt.org/directory\n" +" - ANGIE_RESOLVER=1.1.1.1 8.8.8.8\n" +" - ANGIE_RESOLVER_VALID=300s\n" +" - ANGIE_PROXY_NETWORK=proxy\n" +" ports:\n" +" - \"80:80\"\n" +" - \"443:443\"\n" +" volumes:\n" +" - /var/run/docker.sock:/tmp/docker.sock:ro\n" +" - angie_acme:/var/lib/angie/acme\n" +" networks:\n" +" - proxy\n" +"\n" +" yii-app:\n" +" image: registry.example.com/yii-app:1.0.0\n" +" environment:\n" +" - VIRTUAL_HOST=example-demo.example.com\n" +" - VIRTUAL_PORT=80\n" +" networks:\n" +" - proxy\n" +"\n" +"networks:\n" +" proxy:\n" +" name: proxy\n" +"\n" +"volumes:\n" +" angie_acme:\n" +msgstr "" +"services:\n" +" angie-proxy:\n" +" image: angiesoftware/proxy:latest\n" +" environment:\n" +" - ANGIE_ACME_EMAIL=admin@example.com\n" +" - ANGIE_ACME_URL=https://acme-v02.api.letsencrypt.org/directory\n" +" - ANGIE_RESOLVER=1.1.1.1 8.8.8.8\n" +" - ANGIE_RESOLVER_VALID=300s\n" +" - ANGIE_PROXY_NETWORK=proxy\n" +" ports:\n" +" - \"80:80\"\n" +" - \"443:443\"\n" +" volumes:\n" +" - /var/run/docker.sock:/tmp/docker.sock:ro\n" +" - angie_acme:/var/lib/angie/acme\n" +" networks:\n" +" - proxy\n" +"\n" +" yii-app:\n" +" image: registry.example.com/yii-app:1.0.0\n" +" environment:\n" +" - VIRTUAL_HOST=example-demo.example.com\n" +" - VIRTUAL_PORT=80\n" +" networks:\n" +" - proxy\n" +"\n" +"networks:\n" +" proxy:\n" +" name: proxy\n" +"\n" +"volumes:\n" +" angie_acme:\n" + +#. type: Plain text +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "`VIRTUAL_HOST` is the application's public domain." +msgstr "`VIRTUAL_HOST` é o domínio público da aplicação." + +#. type: Plain text +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "`VIRTUAL_PORT` is the container's internal port to which Angie should proxy requests." +msgstr "`VIRTUAL_PORT` é a porta interna do container para a qual o Angie deve encaminhar as requisições." + +#. type: Plain text +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "Angie Docker Proxy automatically discovers `VIRTUAL_HOST` and `VIRTUAL_PORT` from the environment variables and issues certificates using the Angie ACME module and Let's Encrypt." +msgstr "O Angie Docker Proxy descobre `VIRTUAL_HOST` e `VIRTUAL_PORT` automaticamente pelas variáveis de ambiente e emite certificados usando o módulo ACME do Angie e o Let's Encrypt." + +#. type: Title ## +#: ../src/cookbook/deployment/angie-docker-proxy.md +#, no-wrap +msgid "Starting the services" +msgstr "Subindo os serviços" + +#. type: Plain text +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "Start the proxy and application containers:" +msgstr "Suba os containers do proxy e da aplicação:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/angie-docker-proxy.md +#, no-wrap +msgid "docker compose up -d\n" +msgstr "docker compose up -d\n" + +#. type: Title ## +#: ../src/cookbook/deployment/angie-docker-proxy.md +#, no-wrap +msgid "Adding another application" +msgstr "Adicionando outra aplicação" + +#. type: Plain text +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "To expose another application, add it to `services` in `docker-compose.yml` and attach it to the `proxy` network:" +msgstr "Para expor outra aplicação, adicione-a em `services` no `docker-compose.yml` e conecte-a à rede `proxy`:" + +#. type: Fenced code block (yaml) +#: ../src/cookbook/deployment/angie-docker-proxy.md +#, no-wrap +msgid "" +"services:\n" +" second-app:\n" +" image: traefik/whoami\n" +" environment:\n" +" - VIRTUAL_HOST=example-demo2.example.com\n" +" - VIRTUAL_PORT=80\n" +" networks:\n" +" - proxy\n" +msgstr "" +"services:\n" +" second-app:\n" +" image: traefik/whoami\n" +" environment:\n" +" - VIRTUAL_HOST=example-demo2.example.com\n" +" - VIRTUAL_PORT=80\n" +" networks:\n" +" - proxy\n" + +#. type: Plain text +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "Apply the changes:" +msgstr "Aplique as alterações:" + +#. type: Title ## +#: ../src/cookbook/deployment/angie-docker-proxy.md +#, no-wrap +msgid "How it works" +msgstr "Como funciona" + +#. type: Plain text +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "Angie Docker Proxy monitors the Docker API and discovers containers configured with `VIRTUAL_HOST` and `VIRTUAL_PORT`. It generates the Angie configuration, obtains TLS certificates using ACME, and forwards incoming requests to the corresponding containers through the shared Docker network." +msgstr "O Angie Docker Proxy monitora a API do Docker e descobre os containers configurados com `VIRTUAL_HOST` e `VIRTUAL_PORT`. Ele gera a configuração do Angie, obtém certificados TLS via ACME e encaminha as requisições recebidas para os containers correspondentes pela rede Docker compartilhada." + +#. type: Plain text +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "When containers are added, removed, or updated, the proxy regenerates its configuration and performs a graceful reload. Existing connections continue to be handled while the updated configuration is applied." +msgstr "Quando containers são adicionados, removidos ou atualizados, o proxy gera a configuração de novo e faz um reload gracioso. As conexões existentes continuam sendo atendidas enquanto a configuração atualizada é aplicada." + +#. type: Plain text +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "For configuration options and implementation details, see the [Angie Docker Proxy documentation](https://hub.docker.com/r/angiesoftware/proxy)." +msgstr "Para opções de configuração e detalhes de implementação, veja a [documentação do Angie Docker Proxy](https://hub.docker.com/r/angiesoftware/proxy)." + +#. type: Title ## +#: ../src/cookbook/deployment/angie-docker-proxy.md +#, no-wrap +msgid "Verification" +msgstr "Verificação" + +#. type: Plain text +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "Check the containers:" +msgstr "Verifique os containers:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/angie-docker-proxy.md +#, no-wrap +msgid "docker compose ps\n" +msgstr "docker compose ps\n" + +#. type: Plain text +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "Check the HTTP redirect:" +msgstr "Verifique o redirecionamento HTTP:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/angie-docker-proxy.md +#, no-wrap +msgid "curl -I http://example-demo.example.com/\n" +msgstr "curl -I http://example-demo.example.com/\n" + +#. type: Plain text +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "Expected result:" +msgstr "Resultado esperado:" + +#. type: Fenced code block (text) +#: ../src/cookbook/deployment/angie-docker-proxy.md +#, no-wrap +msgid "" +"HTTP/1.1 301 Moved Permanently\n" +"Location: https://example-demo.example.com/\n" +msgstr "" +"HTTP/1.1 301 Moved Permanently\n" +"Location: https://example-demo.example.com/\n" + +#. type: Plain text +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "Check HTTPS:" +msgstr "Verifique o HTTPS:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/angie-docker-proxy.md +#, no-wrap +msgid "curl -I https://example-demo.example.com/\n" +msgstr "curl -I https://example-demo.example.com/\n" + +#. type: Fenced code block (text) +#: ../src/cookbook/deployment/angie-docker-proxy.md +#, no-wrap +msgid "" +"HTTP/1.1 200 OK\n" +"Server: Angie/...\n" +msgstr "" +"HTTP/1.1 200 OK\n" +"Server: Angie/...\n" + +#. type: Plain text +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "Check the certificate:" +msgstr "Verifique o certificado:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/angie-docker-proxy.md +#, no-wrap +msgid "" +"echo | openssl s_client \\\n" +" -connect example-demo.example.com:443 \\\n" +" -servername example-demo.example.com 2>/dev/null \\\n" +" | openssl x509 -noout -issuer -subject -dates\n" +msgstr "" +"echo | openssl s_client \\\n" +" -connect example-demo.example.com:443 \\\n" +" -servername example-demo.example.com 2>/dev/null \\\n" +" | openssl x509 -noout -issuer -subject -dates\n" + +#. type: Plain text +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "Expected issuer:" +msgstr "Emissor esperado:" + +#. type: Fenced code block (text) +#: ../src/cookbook/deployment/angie-docker-proxy.md +#, no-wrap +msgid "Let's Encrypt\n" +msgstr "Let's Encrypt\n" + +#. type: Title ## +#: ../src/cookbook/deployment/angie-docker-proxy.md +#, no-wrap +msgid "Logs" +msgstr "Logs" + +#. type: Plain text +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "Proxy logs:" +msgstr "Logs do proxy:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/angie-docker-proxy.md +#, no-wrap +msgid "docker compose logs -f angie-proxy\n" +msgstr "docker compose logs -f angie-proxy\n" + +#. type: Title ## +#: ../src/cookbook/deployment/angie-docker-proxy.md +#, no-wrap +msgid "Stopping the services" +msgstr "Parando os serviços" + +#. type: Plain text +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "Stop the services:" +msgstr "Pare os serviços:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/angie-docker-proxy.md +#, no-wrap +msgid "docker compose down\n" +msgstr "docker compose down\n" + +#. type: Plain text +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "Stop the services and remove the certificates:" +msgstr "Pare os serviços e remova os certificados:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/angie-docker-proxy.md +#, no-wrap +msgid "docker compose down -v\n" +msgstr "docker compose down -v\n" + +#. type: Title ## +#: ../src/cookbook/deployment/angie-docker-proxy.md +#, no-wrap +msgid "Limitations" +msgstr "Limitações" + +#. type: Plain text +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "This setup is intended for Docker Compose. Kubernetes doesn't expose workloads through the Docker API and requires an Ingress or Gateway API controller. Docker Swarm also uses the Docker API, but Swarm deployment isn't covered in this guide." +msgstr "Esta configuração é feita para o Docker Compose. O Kubernetes não expõe workloads pela API do Docker e exige um controller de Ingress ou de Gateway API. O Docker Swarm também usa a API do Docker, mas o deploy no Swarm não é coberto neste guia." + +#. type: Title ## +#: ../src/cookbook/deployment/angie-docker-proxy.md +#, no-wrap +msgid "For more information" +msgstr "Para mais informações" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "[Angie Docker Proxy documentation](https://hub.docker.com/r/angiesoftware/proxy)" +msgstr "[Documentação do Angie Docker Proxy](https://hub.docker.com/r/angiesoftware/proxy)" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "[Yii Application Template](https://github.com/yiisoft/app)" +msgstr "[Template de aplicação do Yii](https://github.com/yiisoft/app)" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "[Docker in Yii Application Templates](https://yiisoft.github.io/docs/guide/tutorial/docker.html)" +msgstr "[Docker nos templates de aplicação do Yii](https://yiisoft.github.io/docs/guide/tutorial/docker.html)" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/angie-docker-proxy.md +msgid "[Docker Compose documentation](https://docs.docker.com/compose/)" +msgstr "[Documentação do Docker Compose](https://docs.docker.com/compose/)" diff --git a/_translations/po/pt-BR/cookbook_deployment_autoscaling.md.po b/_translations/po/pt-BR/cookbook_deployment_autoscaling.md.po new file mode 100644 index 00000000..4a3eb94b --- /dev/null +++ b/_translations/po/pt-BR/cookbook_deployment_autoscaling.md.po @@ -0,0 +1,369 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-06-02 22:17+0000\n" +"PO-Revision-Date: 2026-06-02 22:17+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/cookbook/deployment/autoscaling.md +#, no-wrap +msgid "Configuring an application for autoscaling" +msgstr "Configurando uma aplicação para autoscaling" + +#. type: Plain text +#: ../src/cookbook/deployment/autoscaling.md +msgid "Autoscaling works when any application instance can handle any request and can be added or removed without special local state. In Yii applications this mostly means keeping runtime state outside the container or VM, making health checks cheap, and running migrations and workers separately from web replicas." +msgstr "O autoscaling funciona quando qualquer instância da aplicação consegue atender qualquer requisição e pode ser adicionada ou removida sem estado local especial. Em aplicações Yii, isso significa principalmente manter o estado de runtime fora do container ou da VM, deixar os health checks baratos e rodar migrations e workers separados das réplicas web." + +#. type: Title ## +#: ../src/cookbook/deployment/autoscaling.md +#, no-wrap +msgid "Keep web instances stateless" +msgstr "Mantenha as instâncias web sem estado" + +#. type: Plain text +#: ../src/cookbook/deployment/autoscaling.md +msgid "Do not store user-visible state on the local filesystem of a web instance. Local files disappear when an instance is replaced and are not visible to other replicas." +msgstr "Não guarde estado visível ao usuário no sistema de arquivos local de uma instância web. Arquivos locais somem quando uma instância é substituída e não ficam visíveis para as outras réplicas." + +#. type: Plain text +#: ../src/cookbook/deployment/autoscaling.md +msgid "Move these resources to shared services:" +msgstr "Mova estes recursos para serviços compartilhados:" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/autoscaling.md +msgid "Sessions: use a shared session handler when users can move between replicas. See [Sessions](../../guide/runtime/sessions.md) and prefer closing sessions early." +msgstr "Sessões: use um handler de sessão compartilhado quando os usuários puderem alternar entre réplicas. Veja [Sessões](../../guide/runtime/sessions.md) e prefira fechar as sessões cedo." + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/autoscaling.md +msgid "Cache: use Redis, Memcached, database, or another shared PSR-16 cache backend for data that must be consistent across replicas. See [Data caching](../../guide/caching/data.md)." +msgstr "Cache: use Redis, Memcached, banco de dados ou outro backend de cache PSR-16 compartilhado para dados que precisam ser consistentes entre as réplicas. Veja [Cache de dados](../../guide/caching/data.md)." + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/autoscaling.md +msgid "Uploads: store files in object storage, a shared volume, or a service dedicated to file storage. Local `runtime` or `public/uploads` directories are safe only for temporary files." +msgstr "Uploads: guarde arquivos em object storage, em um volume compartilhado ou em um serviço dedicado ao armazenamento de arquivos. Os diretórios locais `runtime` ou `public/uploads` só são seguros para arquivos temporários." + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/autoscaling.md +msgid "Generated assets: build them into the image or publish them to shared storage/CDN during deployment." +msgstr "Assets gerados: inclua-os na imagem ou publique-os em um armazenamento compartilhado/CDN durante o deploy." + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/autoscaling.md +msgid "Logs: write to stdout/stderr or a central log target. Do not depend on files inside a short-lived instance." +msgstr "Logs: escreva em stdout/stderr ou em um destino de log central. Não dependa de arquivos dentro de uma instância de vida curta." + +#. type: Plain text +#: ../src/cookbook/deployment/autoscaling.md +msgid "Sticky sessions can reduce immediate pressure, but they are not a substitute for shared state. A replacement instance or deployment rollout still breaks local session and upload storage." +msgstr "Sticky sessions podem aliviar a pressão imediata, mas não substituem o estado compartilhado. Uma instância substituta ou o rollout de um deploy ainda quebram o armazenamento local de sessões e de uploads." + +#. type: Title ## +#: ../src/cookbook/deployment/autoscaling.md +#, no-wrap +msgid "Add health endpoints" +msgstr "Adicione endpoints de saúde" + +#. type: Plain text +#: ../src/cookbook/deployment/autoscaling.md +msgid "Use a cheap liveness endpoint for the load balancer or orchestrator:" +msgstr "Use um endpoint de liveness barato para o load balancer ou o orquestrador:" + +#. type: Fenced code block (php) +#: ../src/cookbook/deployment/autoscaling.md +#, no-wrap +msgid "" +"responseFactory->createResponse(Status::NO_CONTENT);\n" +" }\n" +"}\n" +msgstr "" +"responseFactory->createResponse(Status::NO_CONTENT);\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/cookbook/deployment/autoscaling.md +msgid "Register it in `config/common/routes.php`:" +msgstr "Registre-o em `config/common/routes.php`:" + +#. type: Fenced code block (php) +#: ../src/cookbook/deployment/autoscaling.md +#, no-wrap +msgid "" +"use App\\Web\\Health\\HealthCheckAction;\n" +"use Yiisoft\\Router\\Route;\n" +"\n" +"return [\n" +" // ...\n" +" Route::get('/healthz')\n" +" ->action(HealthCheckAction::class)\n" +" ->name('healthz'),\n" +"];\n" +msgstr "" +"use App\\Web\\Health\\HealthCheckAction;\n" +"use Yiisoft\\Router\\Route;\n" +"\n" +"return [\n" +" // ...\n" +" Route::get('/healthz')\n" +" ->action(HealthCheckAction::class)\n" +" ->name('healthz'),\n" +"];\n" + +#. type: Plain text +#: ../src/cookbook/deployment/autoscaling.md +msgid "Keep this endpoint independent from the database and external APIs. It should answer whether the PHP process can accept requests, not whether every dependency is healthy." +msgstr "Mantenha esse endpoint independente do banco de dados e de APIs externas. Ele deve responder se o processo PHP consegue aceitar requisições, não se todas as dependências estão saudáveis." + +#. type: Plain text +#: ../src/cookbook/deployment/autoscaling.md +msgid "If your platform supports readiness checks, add a separate endpoint such as `/readyz` for dependencies that must be available before routing traffic to a new instance. Keep it bounded with short timeouts. A slow readiness check can make a traffic spike worse." +msgstr "Se a sua plataforma suporta readiness checks, adicione um endpoint separado, como `/readyz`, para as dependências que precisam estar disponíveis antes de direcionar tráfego para uma nova instância. Limite-o com timeouts curtos. Um readiness check lento pode piorar um pico de tráfego." + +#. type: Title ## +#: ../src/cookbook/deployment/autoscaling.md +#, no-wrap +msgid "Configure runtime paths" +msgstr "Configure os caminhos de runtime" + +#. type: Plain text +#: ../src/cookbook/deployment/autoscaling.md +msgid "The `runtime` directory should contain disposable process-local files only: logs before shipping, cache files that can be rebuilt, temporary upload chunks, locks scoped to one instance, and debug artifacts." +msgstr "O diretório `runtime` deve conter apenas arquivos descartáveis e locais ao processo: logs antes de serem enviados, arquivos de cache que podem ser recriados, partes temporárias de upload, locks restritos a uma instância e artefatos de debug." + +#. type: Plain text +#: ../src/cookbook/deployment/autoscaling.md +msgid "For autoscaled deployments:" +msgstr "Para deploys com autoscaling:" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/autoscaling.md +msgid "mount `runtime` as an instance-local writable volume or create it during image startup;" +msgstr "monte `runtime` como um volume gravável local à instância ou crie-o na inicialização da imagem;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/autoscaling.md +msgid "do not store permanent uploaded files in `runtime`;" +msgstr "não guarde arquivos enviados permanentes em `runtime`;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/autoscaling.md +msgid "do not use local file locks for jobs that must be unique across all replicas;" +msgstr "não use locks de arquivo locais para jobs que precisam ser únicos entre todas as réplicas;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/autoscaling.md +msgid "clear or ignore local runtime cache during rollouts." +msgstr "limpe ou ignore o cache local de runtime durante os rollouts." + +#. type: Plain text +#: ../src/cookbook/deployment/autoscaling.md +msgid "When a command or worker must be unique globally, use a database lock, Redis lock, queue semantics, or run it as a single scheduled job outside the web autoscaling group." +msgstr "Quando um comando ou worker precisa ser único globalmente, use um lock no banco de dados, um lock no Redis, a semântica da fila, ou rode-o como um único job agendado fora do grupo de autoscaling web." + +#. type: Title ## +#: ../src/cookbook/deployment/autoscaling.md +#, no-wrap +msgid "Run migrations once" +msgstr "Rode as migrations uma única vez" + +#. type: Plain text +#: ../src/cookbook/deployment/autoscaling.md +msgid "Do not run `./yii migrate` from every web instance during startup. Multiple replicas starting at the same time can compete for locks, slow down boot, or partially deploy incompatible schema." +msgstr "Não rode `./yii migrate` em cada instância web durante a inicialização. Várias réplicas subindo ao mesmo tempo podem disputar locks, deixar o boot lento ou aplicar parcialmente um schema incompatível." + +#. type: Plain text +#: ../src/cookbook/deployment/autoscaling.md +msgid "Run migrations from one deployment job or a dedicated console container before or during rollout:" +msgstr "Rode as migrations a partir de um único job de deploy ou de um container de console dedicado, antes ou durante o rollout:" + +#. type: Fenced code block (shell) +#: ../src/cookbook/deployment/autoscaling.md +#, no-wrap +msgid "APP_ENV=prod php ./yii migrate --no-interaction\n" +msgstr "APP_ENV=prod php ./yii migrate --no-interaction\n" + +#. type: Plain text +#: ../src/cookbook/deployment/autoscaling.md +msgid "For zero-downtime deployments, use an expand-and-contract migration flow. See [Applying migrations during rolling updates](rolling-update-migrations.md)." +msgstr "Para deploys sem downtime, use um fluxo de migrations do tipo expand-and-contract. Veja [Aplicando migrations durante rolling updates](rolling-update-migrations.md)." + +#. type: Title ## +#: ../src/cookbook/deployment/autoscaling.md +#, no-wrap +msgid "Separate web, workers, and scheduled jobs" +msgstr "Separe web, workers e jobs agendados" + +#. type: Plain text +#: ../src/cookbook/deployment/autoscaling.md +msgid "Scale web replicas for request traffic. Scale queue workers for queue depth or processing latency. Run scheduled jobs from one scheduler, not from every web replica." +msgstr "Escale as réplicas web conforme o tráfego de requisições. Escale os workers de fila conforme o tamanho da fila ou a latência de processamento. Rode os jobs agendados a partir de um único agendador, não de cada réplica web." + +#. type: Plain text +#: ../src/cookbook/deployment/autoscaling.md +msgid "Use the same application image when practical, but different entry points:" +msgstr "Use a mesma imagem da aplicação quando for prático, mas com pontos de entrada diferentes:" + +#. type: Fenced code block (shell) +#: ../src/cookbook/deployment/autoscaling.md +#, no-wrap +msgid "" +"php ./yii queue:listen\n" +"php ./yii app:send-digests --no-interaction\n" +msgstr "" +"php ./yii queue:listen\n" +"php ./yii app:send-digests --no-interaction\n" + +#. type: Plain text +#: ../src/cookbook/deployment/autoscaling.md +msgid "Make workers and scheduled commands idempotent. A deployment may stop a worker after it started processing a message, and the queue may deliver it again." +msgstr "Torne workers e comandos agendados idempotentes. Um deploy pode parar um worker depois que ele começou a processar uma mensagem, e a fila pode entregá-la de novo." + +#. type: Title ## +#: ../src/cookbook/deployment/autoscaling.md +#, no-wrap +msgid "Use environment-specific configuration" +msgstr "Use configuração específica por ambiente" + +#. type: Plain text +#: ../src/cookbook/deployment/autoscaling.md +msgid "Keep secrets and per-environment values out of the image:" +msgstr "Mantenha segredos e valores de cada ambiente fora da imagem:" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/autoscaling.md +msgid "database DSN, username, and password;" +msgstr "DSN, usuário e senha do banco de dados;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/autoscaling.md +msgid "cache/session backend addresses;" +msgstr "endereços dos backends de cache/sessão;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/autoscaling.md +msgid "cookie validation keys and encryption keys;" +msgstr "chaves de validação de cookies e chaves de criptografia;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/autoscaling.md +msgid "mail, queue, and object-storage credentials;" +msgstr "credenciais de e-mail, fila e object storage;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/autoscaling.md +msgid "public base URL and trusted proxy settings." +msgstr "URL base pública e configurações de proxies confiáveis." + +#. type: Plain text +#: ../src/cookbook/deployment/autoscaling.md +msgid "Load them through environment variables or environment-specific Yii config files. Every replica of the same release should receive the same configuration values, except for platform-provided instance metadata." +msgstr "Carregue-os por variáveis de ambiente ou por arquivos de configuração do Yii específicos de cada ambiente. Todas as réplicas da mesma release devem receber os mesmos valores de configuração, exceto os metadados de instância fornecidos pela plataforma." + +#. type: Title ## +#: ../src/cookbook/deployment/autoscaling.md +#, no-wrap +msgid "Capacity checklist" +msgstr "Checklist de capacidade" + +#. type: Plain text +#: ../src/cookbook/deployment/autoscaling.md +msgid "Before enabling autoscaling, verify that:" +msgstr "Antes de habilitar o autoscaling, verifique que:" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/autoscaling.md +msgid "a request can be served correctly after the previous request went to another replica;" +msgstr "uma requisição é atendida corretamente depois que a requisição anterior foi para outra réplica;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/autoscaling.md +msgid "login and flash messages work without sticky sessions;" +msgstr "login e mensagens flash funcionam sem sticky sessions;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/autoscaling.md +msgid "uploaded files remain available after the handling instance is removed;" +msgstr "arquivos enviados continuam disponíveis depois que a instância que os recebeu é removida;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/autoscaling.md +msgid "cache misses on one instance do not corrupt or hide data on another instance;" +msgstr "cache misses em uma instância não corrompem nem escondem dados em outra instância;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/autoscaling.md +msgid "migrations are run by exactly one deployment step;" +msgstr "as migrations são executadas por exatamente uma etapa do deploy;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/autoscaling.md +msgid "background workers and scheduled commands are not multiplied accidentally;" +msgstr "workers em segundo plano e comandos agendados não são multiplicados por acidente;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/autoscaling.md +msgid "health checks are fast and do not overload the database;" +msgstr "os health checks são rápidos e não sobrecarregam o banco de dados;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/autoscaling.md +msgid "logs and metrics identify the application version and instance;" +msgstr "logs e métricas identificam a versão da aplicação e a instância;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/autoscaling.md +msgid "shutdown is graceful enough for your web server and queue worker timeouts." +msgstr "o desligamento é gracioso o bastante para os timeouts do seu servidor web e dos workers de fila." diff --git a/_translations/po/pt-BR/cookbook_deployment_docker-swarm-caddy.md.po b/_translations/po/pt-BR/cookbook_deployment_docker-swarm-caddy.md.po new file mode 100644 index 00000000..5e99a4a0 --- /dev/null +++ b/_translations/po/pt-BR/cookbook_deployment_docker-swarm-caddy.md.po @@ -0,0 +1,1228 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-09-25 14:35+0000\n" +"PO-Revision-Date: 2026-09-25 14:35+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/configuring-xdebug.md ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md ../src/guide/views/asset.md +#, no-wrap +msgid "Troubleshooting" +msgstr "Solução de problemas" + +#. type: Title ## +#: ../src/cookbook/deployment/angie-docker-proxy.md ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md ../src/cookbook/preface.md +#, no-wrap +msgid "Prerequisites" +msgstr "Pré-requisitos" + +#. type: Title # +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#, no-wrap +msgid "Deploying Yii applications to Docker Swarm and Caddy" +msgstr "Fazendo deploy de aplicações Yii no Docker Swarm com Caddy" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +msgid "This guide walks you through deploying a Yii application to [Docker Swarm](https://docs.docker.com/engine/swarm/) starting from a blank server, using [Caddy](https://caddyserver.com/) as a reverse proxy and deploying from a container registry ([Forgejo](https://forgejo.org/) or [Gitea](https://about.gitea.com/))." +msgstr "Este guia mostra como fazer o deploy de uma aplicação Yii no [Docker Swarm](https://docs.docker.com/engine/swarm/) a partir de um servidor vazio, usando o [Caddy](https://caddyserver.com/) como proxy reverso e fazendo o deploy a partir de um registro de containers ([Forgejo](https://forgejo.org/) ou [Gitea](https://about.gitea.com/))." + +#. type: Fenced code block (mermaid) +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#, no-wrap +msgid "" +"graph LR\n" +" A[Internet] --> B[Reverse Proxy: Caddy]\n" +" B --> C[app1.example.com]\n" +" B --> D[app2.example.com]\n" +" \n" +" subgraph Docker Swarm Cluster\n" +" B\n" +" C\n" +" D\n" +" end\n" +msgstr "" +"graph LR\n" +" A[Internet] --> B[Proxy reverso: Caddy]\n" +" B --> C[app1.example.com]\n" +" B --> D[app2.example.com]\n" +" \n" +" subgraph Docker Swarm Cluster\n" +" B\n" +" C\n" +" D\n" +" end\n" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "A server with a fresh installation of a Linux distribution (Ubuntu 22.04 LTS or later recommended)" +msgstr "Um servidor com uma distribuição Linux recém-instalada (recomendado Ubuntu 22.04 LTS ou mais recente)" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "A domain name pointing to your server's IP address" +msgstr "Um nome de domínio apontando para o IP do seu servidor" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "SSH access to your server" +msgstr "Acesso SSH ao seu servidor" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Basic knowledge of Docker and command-line tools" +msgstr "Conhecimento básico de Docker e de ferramentas de linha de comando" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Server preparation" +msgstr "Preparando o servidor" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Install Docker" +msgstr "Instale o Docker" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "For installation instructions, see the [official Docker documentation](https://docs.docker.com/engine/install/ubuntu/)." +msgstr "Para as instruções de instalação, veja a [documentação oficial do Docker](https://docs.docker.com/engine/install/ubuntu/)." + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Initialize Docker Swarm" +msgstr "Inicialize o Docker Swarm" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Initialize your server as a Docker Swarm manager:" +msgstr "Inicialize o seu servidor como manager do Docker Swarm:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "docker swarm init --advertise-addr \n" +msgstr "docker swarm init --advertise-addr \n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Replace `` with your server's public IP address.\n" +msgstr "Substitua `` pelo IP público do seu servidor.\n" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Set up the reverse proxy network" +msgstr "Configure a rede do proxy reverso" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Create a dedicated overlay network for reverse proxy to communicate with your services:" +msgstr "Crie uma rede overlay dedicada para o proxy reverso se comunicar com os seus serviços:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "docker network create --driver=overlay reverse_proxy_public\n" +msgstr "docker network create --driver=overlay reverse_proxy_public\n" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#, no-wrap +msgid "Setting up Caddy as reverse proxy" +msgstr "Configurando o Caddy como proxy reverso" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +msgid "To deploy Caddy as reverse proxy create a file `caddy-stack.yml`:" +msgstr "Para fazer o deploy do Caddy como proxy reverso, crie um arquivo `caddy-stack.yml`:" + +#. type: Fenced code block (yaml) +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#, no-wrap +msgid "" +"services:\n" +" caddy:\n" +" image: lucaslorentz/caddy-docker-proxy:ci-alpine\n" +" ports:\n" +" - \"80:80\"\n" +" - \"443:443\"\n" +" volumes:\n" +" - /var/run/docker.sock:/var/run/docker.sock\n" +" - caddy_data:/data\n" +" networks:\n" +" - reverse_proxy_public\n" +"\n" +"volumes:\n" +" caddy_data:\n" +"\n" +"networks:\n" +" reverse_proxy_public:\n" +" external: true\n" +msgstr "" +"services:\n" +" caddy:\n" +" image: lucaslorentz/caddy-docker-proxy:ci-alpine\n" +" ports:\n" +" - \"80:80\"\n" +" - \"443:443\"\n" +" volumes:\n" +" - /var/run/docker.sock:/var/run/docker.sock\n" +" - caddy_data:/data\n" +" networks:\n" +" - reverse_proxy_public\n" +"\n" +"volumes:\n" +" caddy_data:\n" +"\n" +"networks:\n" +" reverse_proxy_public:\n" +" external: true\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +msgid "Deploy Caddy:" +msgstr "Faça o deploy do Caddy:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#, no-wrap +msgid "docker stack deploy -c caddy-stack.yml caddy\n" +msgstr "docker stack deploy -c caddy-stack.yml caddy\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +msgid "Caddy automatically discovers services with Caddy labels and sets up HTTPS using Let's Encrypt. Yii3 application templates are using Caddy labels by default:" +msgstr "O Caddy descobre automaticamente os serviços com labels do Caddy e configura HTTPS usando o Let's Encrypt. Os templates de aplicação do Yii3 usam labels do Caddy por padrão:" + +#. type: Fenced code block (yaml) +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#, no-wrap +msgid "" +"deploy:\n" +" labels:\n" +" - caddy: ${PROD_HOST:-app.example.com}\n" +" - caddy.reverse_proxy: \"{{upstreams 80}}\"\n" +msgstr "" +"deploy:\n" +" labels:\n" +" - caddy: ${PROD_HOST:-app.example.com}\n" +" - caddy.reverse_proxy: \"{{upstreams 80}}\"\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#, no-wrap +msgid "" +"> [!IMPORTANT]\n" +"> Make sure your domain DNS records are configured and pointing to your server before deploying services with\n" +"> Caddy labels, as Let's Encrypt requires domain validation.\n" +msgstr "" +"> [!IMPORTANT]\n" +"> Garanta que os registros DNS do seu domínio estejam configurados e apontando para o seu servidor antes de fazer o deploy de serviços com\n" +"> labels do Caddy, porque o Let's Encrypt exige a validação do domínio.\n" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Setting up a container registry" +msgstr "Configurando um registro de containers" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "You need a container registry to store your Docker images. Choose one of the following options." +msgstr "Você precisa de um registro de containers para guardar as suas imagens Docker. Escolha uma das opções a seguir." + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Option 1: Using Forgejo" +msgstr "Opção 1: usando o Forgejo" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "To deploy Forgejo create a file `forgejo-stack.yml`:" +msgstr "Para fazer o deploy do Forgejo, crie um arquivo `forgejo-stack.yml`:" + +#. type: Fenced code block (yaml) +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#, no-wrap +msgid "" +"services:\n" +" forgejo:\n" +" image: codeberg.org/forgejo/forgejo:1.21\n" +" ports:\n" +" - \"3000:3000\"\n" +" volumes:\n" +" - forgejo_data:/data\n" +" networks:\n" +" - reverse_proxy_public\n" +" deploy:\n" +" labels:\n" +" - \"caddy=git.example.com\"\n" +" - \"caddy.reverse_proxy={{upstreams 3000}}\"\n" +"\n" +"volumes:\n" +" forgejo_data:\n" +"\n" +"networks:\n" +" reverse_proxy_public:\n" +" external: true\n" +msgstr "" +"services:\n" +" forgejo:\n" +" image: codeberg.org/forgejo/forgejo:1.21\n" +" ports:\n" +" - \"3000:3000\"\n" +" volumes:\n" +" - forgejo_data:/data\n" +" networks:\n" +" - reverse_proxy_public\n" +" deploy:\n" +" labels:\n" +" - \"caddy=git.example.com\"\n" +" - \"caddy.reverse_proxy={{upstreams 3000}}\"\n" +"\n" +"volumes:\n" +" forgejo_data:\n" +"\n" +"networks:\n" +" reverse_proxy_public:\n" +" external: true\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Deploy Forgejo:" +msgstr "Faça o deploy do Forgejo:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "docker stack deploy -c forgejo-stack.yml forgejo\n" +msgstr "docker stack deploy -c forgejo-stack.yml forgejo\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Replace `git.example.com` with your desired subdomain." +msgstr "Substitua `git.example.com` pelo subdomínio desejado." + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +msgid "After deployment, access Forgejo at `https://git.example.com` and complete the initial setup. Make sure to enable the container registry in the settings." +msgstr "Depois do deploy, acesse o Forgejo em `https://git.example.com` e conclua a configuração inicial. Não esqueça de habilitar o registro de containers nas configurações." + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Option 2: Using Gitea" +msgstr "Opção 2: usando o Gitea" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "To deploy Gitea create a file `gitea-stack.yml`:" +msgstr "Para fazer o deploy do Gitea, crie um arquivo `gitea-stack.yml`:" + +#. type: Fenced code block (yaml) +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#, no-wrap +msgid "" +"services:\n" +" gitea:\n" +" image: gitea/gitea:latest\n" +" ports:\n" +" - \"3000:3000\"\n" +" volumes:\n" +" - gitea_data:/data\n" +" networks:\n" +" - reverse_proxy_public\n" +" deploy:\n" +" labels:\n" +" - \"caddy=git.example.com\"\n" +" - \"caddy.reverse_proxy={{upstreams 3000}}\"\n" +"\n" +"volumes:\n" +" gitea_data:\n" +"\n" +"networks:\n" +" reverse_proxy_public:\n" +" external: true\n" +msgstr "" +"services:\n" +" gitea:\n" +" image: gitea/gitea:latest\n" +" ports:\n" +" - \"3000:3000\"\n" +" volumes:\n" +" - gitea_data:/data\n" +" networks:\n" +" - reverse_proxy_public\n" +" deploy:\n" +" labels:\n" +" - \"caddy=git.example.com\"\n" +" - \"caddy.reverse_proxy={{upstreams 3000}}\"\n" +"\n" +"volumes:\n" +" gitea_data:\n" +"\n" +"networks:\n" +" reverse_proxy_public:\n" +" external: true\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Deploy Gitea:" +msgstr "Faça o deploy do Gitea:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "docker stack deploy -c gitea-stack.yml gitea\n" +msgstr "docker stack deploy -c gitea-stack.yml gitea\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "After deployment, access Gitea at `https://git.example.com` and complete the initial setup. Make sure to enable the container registry in the settings." +msgstr "Depois do deploy, acesse o Gitea em `https://git.example.com` e conclua a configuração inicial. Não esqueça de habilitar o registro de containers nas configurações." + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Configuring your Yii application" +msgstr "Configurando a sua aplicação Yii" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Update the Makefile configuration" +msgstr "Atualize a configuração do Makefile" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "The [Yii application template](https://github.com/yiisoft/app) includes a Makefile with deployment commands. Update the `docker/.env` file in your project:" +msgstr "O [template de aplicação do Yii](https://github.com/yiisoft/app) inclui um Makefile com comandos de deploy. Atualize o arquivo `docker/.env` do seu projeto:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"STACK_NAME=myapp\n" +"\n" +"#\n" +"# Production\n" +"#\n" +"\n" +"PROD_HOST=app.example.com\n" +"PROD_SSH=\"ssh://user@your-server-ip\"\n" +"\n" +"IMAGE=git.example.com/username/myapp\n" +"IMAGE_TAG=latest\n" +msgstr "" +"STACK_NAME=myapp\n" +"\n" +"#\n" +"# Produção\n" +"#\n" +"\n" +"PROD_HOST=app.example.com\n" +"PROD_SSH=\"ssh://user@your-server-ip\"\n" +"\n" +"IMAGE=git.example.com/username/myapp\n" +"IMAGE_TAG=latest\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Replace the values: - `STACK_NAME`: A unique name for your application stack - `PROD_HOST`: The domain name where your app will be accessible - `PROD_SSH`: SSH connection string to your server (format: `ssh://user@host`) - `IMAGE`: Full path to your container image in the registry - `IMAGE_TAG`: Image tag, typically `latest` or a version number" +msgstr "Substitua os valores: - `STACK_NAME`: um nome único para a stack da sua aplicação - `PROD_HOST`: o nome de domínio em que a aplicação vai ficar acessível - `PROD_SSH`: a string de conexão SSH com o seu servidor (formato: `ssh://user@host`) - `IMAGE`: o caminho completo da imagem do container no registro - `IMAGE_TAG`: a tag da imagem, normalmente `latest` ou um número de versão" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Configure the production environment" +msgstr "Configure o ambiente de produção" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Update `docker/prod/.env` with your production environment variables:" +msgstr "Atualize o `docker/prod/.env` com as variáveis de ambiente de produção:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"APP_ENV=prod\n" +"YII_DEBUG=false\n" +"YII_ENV=prod\n" +"\n" +"# Database configuration\n" +"DB_HOST=db\n" +"DB_NAME=myapp\n" +"DB_USER=myapp\n" +"DB_PASSWORD=secure_password_here\n" +"\n" +"# Add other environment-specific variables\n" +msgstr "" +"APP_ENV=prod\n" +"YII_DEBUG=false\n" +"YII_ENV=prod\n" +"\n" +"# Configuração do banco de dados\n" +"DB_HOST=db\n" +"DB_NAME=myapp\n" +"DB_USER=myapp\n" +"DB_PASSWORD=secure_password_here\n" +"\n" +"# Adicione outras variáveis específicas do ambiente\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"> [!WARNING]\n" +"> Never commit sensitive credentials to version control. Use `docker/prod/override.env` for sensitive values and add it to `.gitignore`.\n" +msgstr "" +"> [!WARNING]\n" +"> Nunca faça commit de credenciais sensíveis no controle de versão. Use `docker/prod/override.env` para valores sensíveis e adicione-o ao `.gitignore`.\n" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Review the production Docker Compose configuration" +msgstr "Revise a configuração do Docker Compose de produção" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +msgid "The default `docker/prod/compose.yml` includes:" +msgstr "O `docker/prod/compose.yml` padrão inclui:" + +#. type: Fenced code block (yaml) +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#, no-wrap +msgid "" +"services:\n" +" app:\n" +" image: ${IMAGE}:${IMAGE_TAG}\n" +" networks:\n" +" - reverse_proxy_public\n" +" volumes:\n" +" - runtime:/app/runtime\n" +" - caddy_data:/data\n" +" - caddy_config:/config\n" +" env_file:\n" +" - path: ./prod/.env\n" +" - path: ./prod/override.env\n" +" required: false\\\n" +" environment:\n" +" CADDY_EXTRA_CONFIG: 'auto_https off'\n" +" deploy:\n" +" replicas: 2\n" +" update_config:\n" +" delay: 10s\n" +" parallelism: 1\n" +" order: start-first\n" +" failure_action: rollback\n" +" monitor: 10s\n" +" rollback_config:\n" +" parallelism: 0\n" +" order: stop-first\n" +" restart_policy:\n" +" condition: on-failure\n" +" delay: 5s\n" +" max_attempts: 3\n" +" window: 120s\n" +" labels:\n" +" caddy: ${PROD_HOST:-app.example.com}\n" +" caddy.reverse_proxy: \"{{upstreams 80}}\"\n" +msgstr "" +"services:\n" +" app:\n" +" image: ${IMAGE}:${IMAGE_TAG}\n" +" networks:\n" +" - reverse_proxy_public\n" +" volumes:\n" +" - runtime:/app/runtime\n" +" - caddy_data:/data\n" +" - caddy_config:/config\n" +" env_file:\n" +" - path: ./prod/.env\n" +" - path: ./prod/override.env\n" +" required: false\\\n" +" environment:\n" +" CADDY_EXTRA_CONFIG: 'auto_https off'\n" +" deploy:\n" +" replicas: 2\n" +" update_config:\n" +" delay: 10s\n" +" parallelism: 1\n" +" order: start-first\n" +" failure_action: rollback\n" +" monitor: 10s\n" +" rollback_config:\n" +" parallelism: 0\n" +" order: stop-first\n" +" restart_policy:\n" +" condition: on-failure\n" +" delay: 5s\n" +" max_attempts: 3\n" +" window: 120s\n" +" labels:\n" +" caddy: ${PROD_HOST:-app.example.com}\n" +" caddy.reverse_proxy: \"{{upstreams 80}}\"\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"This configuration:\n" +"- Runs 2 replicas for high availability\n" +"- Uses a rolling update strategy with automatic rollback on failure\n" +"- Configures `labels` for automatic HTTPS on the reverse proxy\n" +"- Disables obtaining of HTTPs certificates on the container itself\n" +" since proxy communicates with the container via HTTP. That is `auto_https off`.\n" +msgstr "" +"Essa configuração:\n" +"- Roda 2 réplicas para alta disponibilidade\n" +"- Usa uma estratégia de rolling update com rollback automático em caso de falha\n" +"- Configura `labels` para HTTPS automático no proxy reverso\n" +"- Desabilita a obtenção de certificados HTTPS no próprio container,\n" +" já que o proxy se comunica com o container via HTTP. Isso é o `auto_https off`.\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "If you need a database, add it to the stack:" +msgstr "Se você precisa de um banco de dados, adicione-o à stack:" + +#. type: Fenced code block (yaml) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"services:\n" +" app:\n" +" # ... existing configuration ...\n" +" \n" +" db:\n" +" image: postgres:18-alpine\n" +" environment:\n" +" POSTGRES_DB: myapp\n" +" POSTGRES_USER: myapp\n" +" POSTGRES_PASSWORD_FILE: /run/secrets/db_password\n" +" POSTGRES_INITDB_ARGS: \"--locale-provider=icu --icu-locale=und --encoding=UTF8\"\n" +" volumes:\n" +" - db_data:/var/lib/postgresql\n" +" networks:\n" +" - reverse_proxy_public\n" +" deploy:\n" +" placement:\n" +" constraints:\n" +" - node.role == manager\n" +" secrets:\n" +" - db_password\n" +"\n" +"volumes:\n" +" runtime:\n" +" db_data:\n" +"\n" +"secrets:\n" +" db_password:\n" +" external: true\n" +msgstr "" +"services:\n" +" app:\n" +" # ... configuração existente ...\n" +" \n" +" db:\n" +" image: postgres:18-alpine\n" +" environment:\n" +" POSTGRES_DB: myapp\n" +" POSTGRES_USER: myapp\n" +" POSTGRES_PASSWORD_FILE: /run/secrets/db_password\n" +" POSTGRES_INITDB_ARGS: \"--locale-provider=icu --icu-locale=und --encoding=UTF8\"\n" +" volumes:\n" +" - db_data:/var/lib/postgresql\n" +" networks:\n" +" - reverse_proxy_public\n" +" deploy:\n" +" placement:\n" +" constraints:\n" +" - node.role == manager\n" +" secrets:\n" +" - db_password\n" +"\n" +"volumes:\n" +" runtime:\n" +" db_data:\n" +"\n" +"secrets:\n" +" db_password:\n" +" external: true\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Create the database password secret on the server:" +msgstr "Crie o secret com a senha do banco de dados no servidor:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "echo \"your_secure_password\" | docker secret create db_password -\n" +msgstr "echo \"your_secure_password\" | docker secret create db_password -\n" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Building and pushing the image" +msgstr "Construindo e enviando a imagem" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Set up Docker login on your local machine" +msgstr "Configure o login do Docker na sua máquina local" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Configure Docker to authenticate with your container registry:" +msgstr "Configure o Docker para se autenticar no seu registro de containers:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "docker login git.example.com\n" +msgstr "docker login git.example.com\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Enter your username and password when prompted." +msgstr "Informe o seu usuário e a sua senha quando solicitado." + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Build the production image" +msgstr "Construa a imagem de produção" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Use the Makefile to build your production image:" +msgstr "Use o Makefile para construir a imagem de produção:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "make prod-build\n" +msgstr "make prod-build\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "This runs the command defined in the Makefile:" +msgstr "Isso executa o comando definido no Makefile:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "docker build --file docker/Dockerfile --target prod --pull -t ${IMAGE}:${IMAGE_TAG} .\n" +msgstr "docker build --file docker/Dockerfile --target prod --pull -t ${IMAGE}:${IMAGE_TAG} .\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "The Dockerfile uses a multi-stage build: 1. Installs Composer dependencies in a builder stage 2. Creates a minimal production image with only the necessary files 3. Runs as a non-root user (`www-data`)" +msgstr "O Dockerfile usa um build multi-stage: 1. Instala as dependências do Composer em um estágio de build 2. Cria uma imagem de produção mínima, só com os arquivos necessários 3. Roda como um usuário não root (`www-data`)" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Push the image to the registry" +msgstr "Envie a imagem para o registro" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Push your built image to the container registry:" +msgstr "Envie a imagem construída para o registro de containers:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "make prod-push\n" +msgstr "make prod-push\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "This executes:" +msgstr "Isso executa:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "docker push ${IMAGE}:${IMAGE_TAG}\n" +msgstr "docker push ${IMAGE}:${IMAGE_TAG}\n" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Deploying to Docker Swarm" +msgstr "Fazendo deploy no Docker Swarm" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Configure SSH access" +msgstr "Configure o acesso SSH" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Set up SSH key-based authentication to your server:" +msgstr "Configure a autenticação por chave SSH no seu servidor:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"# Generate SSH key (if you don't have one)\n" +"ssh-keygen -t ed25519 -C \"your_email@example.com\"\n" +"\n" +"# Copy the key to your server\n" +"ssh-copy-id user@your-server-ip\n" +"\n" +"# Add the SSH host to your SSH config (~/.ssh/config)\n" +"cat >> ~/.ssh/config << EOF\n" +"Host docker-web\n" +" HostName your-server-ip\n" +" User user\n" +" IdentityFile ~/.ssh/id_ed25519\n" +"EOF\n" +msgstr "" +"# Gera uma chave SSH (se você ainda não tiver uma)\n" +"ssh-keygen -t ed25519 -C \"your_email@example.com\"\n" +"\n" +"# Copia a chave para o seu servidor\n" +"ssh-copy-id user@your-server-ip\n" +"\n" +"# Adiciona o host SSH à sua configuração SSH (~/.ssh/config)\n" +"cat >> ~/.ssh/config << EOF\n" +"Host docker-web\n" +" HostName your-server-ip\n" +" User user\n" +" IdentityFile ~/.ssh/id_ed25519\n" +"EOF\n" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Set up Docker context" +msgstr "Configure o contexto do Docker" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Create a Docker context for remote deployment:" +msgstr "Crie um contexto do Docker para o deploy remoto:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "docker context create swarm-prod --docker \"host=ssh://docker-web\"\n" +msgstr "docker context create swarm-prod --docker \"host=ssh://docker-web\"\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Alternatively, configure the `DOCKER_HOST` environment variable:" +msgstr "Como alternativa, configure a variável de ambiente `DOCKER_HOST`:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "export DOCKER_HOST=ssh://docker-web\n" +msgstr "export DOCKER_HOST=ssh://docker-web\n" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Deploy the application" +msgstr "Faça o deploy da aplicação" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Deploy your application stack to Docker Swarm:" +msgstr "Faça o deploy da stack da sua aplicação no Docker Swarm:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "make prod-deploy\n" +msgstr "make prod-deploy\n" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "docker -H ${PROD_SSH} stack deploy --prune --detach=false --with-registry-auth -c docker/compose.yml -c docker/prod/compose.yml ${STACK_NAME}\n" +msgstr "docker -H ${PROD_SSH} stack deploy --prune --detach=false --with-registry-auth -c docker/compose.yml -c docker/prod/compose.yml ${STACK_NAME}\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "The `--with-registry-auth` flag ensures the Swarm nodes can pull images from your private registry." +msgstr "A flag `--with-registry-auth` garante que os nós do Swarm consigam baixar imagens do seu registro privado." + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Verify the deployment" +msgstr "Verifique o deploy" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Check the status of your services:" +msgstr "Verifique o status dos seus serviços:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"docker -H ssh://docker-web service ls\n" +"docker -H ssh://docker-web service ps ${STACK_NAME}_app\n" +msgstr "" +"docker -H ssh://docker-web service ls\n" +"docker -H ssh://docker-web service ps ${STACK_NAME}_app\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "View logs:" +msgstr "Veja os logs:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "docker -H ssh://docker-web service logs ${STACK_NAME}_app\n" +msgstr "docker -H ssh://docker-web service logs ${STACK_NAME}_app\n" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Monitoring and maintenance" +msgstr "Monitoramento e manutenção" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "View service logs" +msgstr "Veja os logs do serviço" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"# View all logs\n" +"docker -H ssh://docker-web service logs -f ${STACK_NAME}_app\n" +"\n" +"# View logs from the last 100 lines\n" +"docker -H ssh://docker-web service logs --tail 100 ${STACK_NAME}_app\n" +"\n" +"# View logs with timestamps\n" +"docker -H ssh://docker-web service logs -t ${STACK_NAME}_app\n" +msgstr "" +"# Mostra todos os logs\n" +"docker -H ssh://docker-web service logs -f ${STACK_NAME}_app\n" +"\n" +"# Mostra as últimas 100 linhas de log\n" +"docker -H ssh://docker-web service logs --tail 100 ${STACK_NAME}_app\n" +"\n" +"# Mostra os logs com timestamps\n" +"docker -H ssh://docker-web service logs -t ${STACK_NAME}_app\n" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Scale the application" +msgstr "Escale a aplicação" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Adjust the number of replicas:" +msgstr "Ajuste o número de réplicas:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "docker -H ssh://docker-web service scale ${STACK_NAME}_app=3\n" +msgstr "docker -H ssh://docker-web service scale ${STACK_NAME}_app=3\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Or update the `replicas` value in `docker/prod/compose.yml` and redeploy." +msgstr "Ou atualize o valor de `replicas` em `docker/prod/compose.yml` e faça o deploy de novo." + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Resource limits" +msgstr "Limites de recursos" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Add resource limits to prevent containers from consuming all server resources. Update `docker/prod/compose.yml`:" +msgstr "Adicione limites de recursos para evitar que os containers consumam todos os recursos do servidor. Atualize o `docker/prod/compose.yml`:" + +#. type: Fenced code block (yaml) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"services:\n" +" app:\n" +" # ... existing configuration ...\n" +" deploy:\n" +" resources:\n" +" limits:\n" +" cpus: '0.5'\n" +" memory: 512M\n" +" reservations:\n" +" cpus: '0.25'\n" +" memory: 256M\n" +msgstr "" +"services:\n" +" app:\n" +" # ... configuração existente ...\n" +" deploy:\n" +" resources:\n" +" limits:\n" +" cpus: '0.5'\n" +" memory: 512M\n" +" reservations:\n" +" cpus: '0.25'\n" +" memory: 256M\n" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md ../src/cookbook/disabling-csrf-protection.md +#, no-wrap +msgid "Security considerations" +msgstr "Considerações de segurança" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Use Docker secrets for sensitive data" +msgstr "Use Docker secrets para dados sensíveis" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Instead of environment variables, use Docker secrets for sensitive information:" +msgstr "Em vez de variáveis de ambiente, use Docker secrets para informações sensíveis:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"# Create secrets\n" +"echo \"database_password\" | docker secret create db_password -\n" +"echo \"api_key\" | docker secret create api_key -\n" +msgstr "" +"# Cria os secrets\n" +"echo \"database_password\" | docker secret create db_password -\n" +"echo \"api_key\" | docker secret create api_key -\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Update `docker/prod/compose.yml`:" +msgstr "Atualize o `docker/prod/compose.yml`:" + +#. type: Fenced code block (yaml) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"services:\n" +" app:\n" +" secrets:\n" +" - db_password\n" +" - api_key\n" +"\n" +"secrets:\n" +" db_password:\n" +" external: true\n" +" api_key:\n" +" external: true\n" +msgstr "" +"services:\n" +" app:\n" +" secrets:\n" +" - db_password\n" +" - api_key\n" +"\n" +"secrets:\n" +" db_password:\n" +" external: true\n" +" api_key:\n" +" external: true\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Access secrets in your application at `/run/secrets/secret_name`." +msgstr "Acesse os secrets na sua aplicação em `/run/secrets/secret_name`." + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Set up a firewall" +msgstr "Configure um firewall" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Configure UFW (Uncomplicated Firewall) on your server:" +msgstr "Configure o UFW (Uncomplicated Firewall) no seu servidor:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"# Allow SSH\n" +"sudo ufw allow 22/tcp\n" +"\n" +"# Allow HTTP and HTTPS\n" +"sudo ufw allow 80/tcp\n" +"sudo ufw allow 443/tcp\n" +"\n" +"# Allow Docker Swarm ports (if you plan to add more nodes)\n" +"sudo ufw allow 2377/tcp\n" +"sudo ufw allow 7946/tcp\n" +"sudo ufw allow 7946/udp\n" +"sudo ufw allow 4789/udp\n" +"\n" +"# Enable the firewall\n" +"sudo ufw enable\n" +msgstr "" +"# Libera SSH\n" +"sudo ufw allow 22/tcp\n" +"\n" +"# Libera HTTP e HTTPS\n" +"sudo ufw allow 80/tcp\n" +"sudo ufw allow 443/tcp\n" +"\n" +"# Libera as portas do Docker Swarm (se você pretende adicionar mais nós)\n" +"sudo ufw allow 2377/tcp\n" +"sudo ufw allow 7946/tcp\n" +"sudo ufw allow 7946/udp\n" +"sudo ufw allow 4789/udp\n" +"\n" +"# Habilita o firewall\n" +"sudo ufw enable\n" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Keep the system updated" +msgstr "Mantenha o sistema atualizado" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Regularly update your server and Docker:" +msgstr "Atualize regularmente o seu servidor e o Docker:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"# Update system packages\n" +"sudo apt-get update && sudo apt-get upgrade -y\n" +"\n" +"# Update Docker images\n" +"docker -H ssh://docker-web service update --image ${IMAGE}:${IMAGE_TAG} ${STACK_NAME}_app\n" +msgstr "" +"# Atualiza os pacotes do sistema\n" +"sudo apt-get update && sudo apt-get upgrade -y\n" +"\n" +"# Atualiza as imagens Docker\n" +"docker -H ssh://docker-web service update --image ${IMAGE}:${IMAGE_TAG} ${STACK_NAME}_app\n" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Service won't start" +msgstr "O serviço não sobe" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Check service events and logs:" +msgstr "Verifique os eventos e os logs do serviço:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"docker -H ssh://docker-web service ps ${STACK_NAME}_app --no-trunc\n" +"docker -H ssh://docker-web service logs ${STACK_NAME}_app\n" +msgstr "" +"docker -H ssh://docker-web service ps ${STACK_NAME}_app --no-trunc\n" +"docker -H ssh://docker-web service logs ${STACK_NAME}_app\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Common issues: - **Image pull errors**: Verify registry authentication with `docker -H ssh://docker-web login` - **Port conflicts**: Ensure no other services are using ports 80/443 - **Resource constraints**: Check available resources with `docker -H ssh://docker-web node ls`" +msgstr "Problemas comuns: - **Erros ao baixar a imagem**: verifique a autenticação no registro com `docker -H ssh://docker-web login` - **Conflitos de porta**: garanta que nenhum outro serviço esteja usando as portas 80/443 - **Limitação de recursos**: verifique os recursos disponíveis com `docker -H ssh://docker-web node ls`" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "SSL certificate issues" +msgstr "Problemas com certificados SSL" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +msgid "If Caddy can't obtain certificates: - Verify DNS is pointing to your server - Check that ports 80 and 443 are accessible from the internet - Ensure the email in the Let's Encrypt configuration is valid - Check logs: `docker -H ssh://docker-web service logs caddy`" +msgstr "Se o Caddy não consegue obter os certificados: - Verifique se o DNS aponta para o seu servidor - Verifique se as portas 80 e 443 estão acessíveis pela internet - Garanta que o e-mail na configuração do Let's Encrypt é válido - Verifique os logs: `docker -H ssh://docker-web service logs caddy`" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Container registry connection issues" +msgstr "Problemas de conexão com o registro de containers" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Test registry connectivity:" +msgstr "Teste a conectividade com o registro:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"# From your local machine\n" +"docker pull git.example.com/username/myapp:latest\n" +"\n" +"# From the server\n" +"docker -H ssh://docker-web pull git.example.com/username/myapp:latest\n" +msgstr "" +"# Na sua máquina local\n" +"docker pull git.example.com/username/myapp:latest\n" +"\n" +"# No servidor\n" +"docker -H ssh://docker-web pull git.example.com/username/myapp:latest\n" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md ../src/guide/start/forms.md ../src/guide/start/hello.md +#, no-wrap +msgid "Summary" +msgstr "Resumo" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +msgid "You've successfully deployed a Yii application to Docker Swarm with: - A container registry (Forgejo or Gitea) - Automatic HTTPS via Caddy - Zero-downtime deployments with rolling updates - High availability with multiple replicas" +msgstr "Você fez o deploy de uma aplicação Yii no Docker Swarm com: - Um registro de containers (Forgejo ou Gitea) - HTTPS automático via Caddy - Deploys sem downtime com rolling updates - Alta disponibilidade com várias réplicas" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "The Makefile commands simplify the deployment workflow: - `make prod-build` - Build the production image - `make prod-push` - Push to the registry - `make prod-deploy` - Deploy to Docker Swarm" +msgstr "Os comandos do Makefile simplificam o fluxo de deploy: - `make prod-build` - Constrói a imagem de produção - `make prod-push` - Envia para o registro - `make prod-deploy` - Faz o deploy no Docker Swarm" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +msgid "For more information, see: - [Yii Application Template](https://github.com/yiisoft/app) - [Docker Swarm Documentation](https://docs.docker.com/engine/swarm/) - [Caddy Docker Proxy](https://github.com/lucaslorentz/caddy-docker-proxy)" +msgstr "Para mais informações, veja: - [Template de aplicação do Yii](https://github.com/yiisoft/app) - [Documentação do Docker Swarm](https://docs.docker.com/engine/swarm/) - [Caddy Docker Proxy](https://github.com/lucaslorentz/caddy-docker-proxy)" diff --git a/_translations/po/pt-BR/cookbook_deployment_docker-swarm-traefik.md.po b/_translations/po/pt-BR/cookbook_deployment_docker-swarm-traefik.md.po new file mode 100644 index 00000000..efc3c0bc --- /dev/null +++ b/_translations/po/pt-BR/cookbook_deployment_docker-swarm-traefik.md.po @@ -0,0 +1,1245 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-05-07 14:37+0000\n" +"PO-Revision-Date: 2026-05-07 14:37+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/configuring-xdebug.md ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md ../src/guide/views/asset.md +#, no-wrap +msgid "Troubleshooting" +msgstr "Solução de problemas" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md ../src/cookbook/preface.md +#, no-wrap +msgid "Prerequisites" +msgstr "Pré-requisitos" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "A server with a fresh installation of a Linux distribution (Ubuntu 22.04 LTS or later recommended)" +msgstr "Um servidor com uma distribuição Linux recém-instalada (recomendado Ubuntu 22.04 LTS ou mais recente)" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "A domain name pointing to your server's IP address" +msgstr "Um nome de domínio apontando para o IP do seu servidor" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "SSH access to your server" +msgstr "Acesso SSH ao seu servidor" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Basic knowledge of Docker and command-line tools" +msgstr "Conhecimento básico de Docker e de ferramentas de linha de comando" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Server preparation" +msgstr "Preparando o servidor" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Install Docker" +msgstr "Instale o Docker" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "For installation instructions, see the [official Docker documentation](https://docs.docker.com/engine/install/ubuntu/)." +msgstr "Para as instruções de instalação, veja a [documentação oficial do Docker](https://docs.docker.com/engine/install/ubuntu/)." + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Initialize Docker Swarm" +msgstr "Inicialize o Docker Swarm" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Initialize your server as a Docker Swarm manager:" +msgstr "Inicialize o seu servidor como manager do Docker Swarm:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "docker swarm init --advertise-addr \n" +msgstr "docker swarm init --advertise-addr \n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Replace `` with your server's public IP address.\n" +msgstr "Substitua `` pelo IP público do seu servidor.\n" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Set up the reverse proxy network" +msgstr "Configure a rede do proxy reverso" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Create a dedicated overlay network for reverse proxy to communicate with your services:" +msgstr "Crie uma rede overlay dedicada para o proxy reverso se comunicar com os seus serviços:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "docker network create --driver=overlay reverse_proxy_public\n" +msgstr "docker network create --driver=overlay reverse_proxy_public\n" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Setting up a container registry" +msgstr "Configurando um registro de containers" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "You need a container registry to store your Docker images. Choose one of the following options." +msgstr "Você precisa de um registro de containers para guardar as suas imagens Docker. Escolha uma das opções a seguir." + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Option 1: Using Forgejo" +msgstr "Opção 1: usando o Forgejo" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "To deploy Forgejo create a file `forgejo-stack.yml`:" +msgstr "Para fazer o deploy do Forgejo, crie um arquivo `forgejo-stack.yml`:" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Deploy Forgejo:" +msgstr "Faça o deploy do Forgejo:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "docker stack deploy -c forgejo-stack.yml forgejo\n" +msgstr "docker stack deploy -c forgejo-stack.yml forgejo\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Replace `git.example.com` with your desired subdomain." +msgstr "Substitua `git.example.com` pelo subdomínio desejado." + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Option 2: Using Gitea" +msgstr "Opção 2: usando o Gitea" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "To deploy Gitea create a file `gitea-stack.yml`:" +msgstr "Para fazer o deploy do Gitea, crie um arquivo `gitea-stack.yml`:" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Deploy Gitea:" +msgstr "Faça o deploy do Gitea:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "docker stack deploy -c gitea-stack.yml gitea\n" +msgstr "docker stack deploy -c gitea-stack.yml gitea\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "After deployment, access Gitea at `https://git.example.com` and complete the initial setup. Make sure to enable the container registry in the settings." +msgstr "Depois do deploy, acesse o Gitea em `https://git.example.com` e conclua a configuração inicial. Não esqueça de habilitar o registro de containers nas configurações." + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Configuring your Yii application" +msgstr "Configurando a sua aplicação Yii" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Update the Makefile configuration" +msgstr "Atualize a configuração do Makefile" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "The [Yii application template](https://github.com/yiisoft/app) includes a Makefile with deployment commands. Update the `docker/.env` file in your project:" +msgstr "O [template de aplicação do Yii](https://github.com/yiisoft/app) inclui um Makefile com comandos de deploy. Atualize o arquivo `docker/.env` do seu projeto:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"STACK_NAME=myapp\n" +"\n" +"#\n" +"# Production\n" +"#\n" +"\n" +"PROD_HOST=app.example.com\n" +"PROD_SSH=\"ssh://user@your-server-ip\"\n" +"\n" +"IMAGE=git.example.com/username/myapp\n" +"IMAGE_TAG=latest\n" +msgstr "" +"STACK_NAME=myapp\n" +"\n" +"#\n" +"# Produção\n" +"#\n" +"\n" +"PROD_HOST=app.example.com\n" +"PROD_SSH=\"ssh://user@your-server-ip\"\n" +"\n" +"IMAGE=git.example.com/username/myapp\n" +"IMAGE_TAG=latest\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Replace the values: - `STACK_NAME`: A unique name for your application stack - `PROD_HOST`: The domain name where your app will be accessible - `PROD_SSH`: SSH connection string to your server (format: `ssh://user@host`) - `IMAGE`: Full path to your container image in the registry - `IMAGE_TAG`: Image tag, typically `latest` or a version number" +msgstr "Substitua os valores: - `STACK_NAME`: um nome único para a stack da sua aplicação - `PROD_HOST`: o nome de domínio em que a aplicação vai ficar acessível - `PROD_SSH`: a string de conexão SSH com o seu servidor (formato: `ssh://user@host`) - `IMAGE`: o caminho completo da imagem do container no registro - `IMAGE_TAG`: a tag da imagem, normalmente `latest` ou um número de versão" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Configure the production environment" +msgstr "Configure o ambiente de produção" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Update `docker/prod/.env` with your production environment variables:" +msgstr "Atualize o `docker/prod/.env` com as variáveis de ambiente de produção:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"APP_ENV=prod\n" +"YII_DEBUG=false\n" +"YII_ENV=prod\n" +"\n" +"# Database configuration\n" +"DB_HOST=db\n" +"DB_NAME=myapp\n" +"DB_USER=myapp\n" +"DB_PASSWORD=secure_password_here\n" +"\n" +"# Add other environment-specific variables\n" +msgstr "" +"APP_ENV=prod\n" +"YII_DEBUG=false\n" +"YII_ENV=prod\n" +"\n" +"# Configuração do banco de dados\n" +"DB_HOST=db\n" +"DB_NAME=myapp\n" +"DB_USER=myapp\n" +"DB_PASSWORD=secure_password_here\n" +"\n" +"# Adicione outras variáveis específicas do ambiente\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"> [!WARNING]\n" +"> Never commit sensitive credentials to version control. Use `docker/prod/override.env` for sensitive values and add it to `.gitignore`.\n" +msgstr "" +"> [!WARNING]\n" +"> Nunca faça commit de credenciais sensíveis no controle de versão. Use `docker/prod/override.env` para valores sensíveis e adicione-o ao `.gitignore`.\n" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Review the production Docker Compose configuration" +msgstr "Revise a configuração do Docker Compose de produção" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"This configuration:\n" +"- Runs 2 replicas for high availability\n" +"- Uses a rolling update strategy with automatic rollback on failure\n" +"- Configures `labels` for automatic HTTPS on the reverse proxy\n" +"- Disables obtaining of HTTPs certificates on the container itself\n" +" since proxy communicates with the container via HTTP. That is `auto_https off`.\n" +msgstr "" +"Essa configuração:\n" +"- Roda 2 réplicas para alta disponibilidade\n" +"- Usa uma estratégia de rolling update com rollback automático em caso de falha\n" +"- Configura `labels` para HTTPS automático no proxy reverso\n" +"- Desabilita a obtenção de certificados HTTPS no próprio container,\n" +" já que o proxy se comunica com o container via HTTP. Isso é o `auto_https off`.\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "If you need a database, add it to the stack:" +msgstr "Se você precisa de um banco de dados, adicione-o à stack:" + +#. type: Fenced code block (yaml) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"services:\n" +" app:\n" +" # ... existing configuration ...\n" +" \n" +" db:\n" +" image: postgres:18-alpine\n" +" environment:\n" +" POSTGRES_DB: myapp\n" +" POSTGRES_USER: myapp\n" +" POSTGRES_PASSWORD_FILE: /run/secrets/db_password\n" +" POSTGRES_INITDB_ARGS: \"--locale-provider=icu --icu-locale=und --encoding=UTF8\"\n" +" volumes:\n" +" - db_data:/var/lib/postgresql\n" +" networks:\n" +" - reverse_proxy_public\n" +" deploy:\n" +" placement:\n" +" constraints:\n" +" - node.role == manager\n" +" secrets:\n" +" - db_password\n" +"\n" +"volumes:\n" +" runtime:\n" +" db_data:\n" +"\n" +"secrets:\n" +" db_password:\n" +" external: true\n" +msgstr "" +"services:\n" +" app:\n" +" # ... configuração existente ...\n" +" \n" +" db:\n" +" image: postgres:18-alpine\n" +" environment:\n" +" POSTGRES_DB: myapp\n" +" POSTGRES_USER: myapp\n" +" POSTGRES_PASSWORD_FILE: /run/secrets/db_password\n" +" POSTGRES_INITDB_ARGS: \"--locale-provider=icu --icu-locale=und --encoding=UTF8\"\n" +" volumes:\n" +" - db_data:/var/lib/postgresql\n" +" networks:\n" +" - reverse_proxy_public\n" +" deploy:\n" +" placement:\n" +" constraints:\n" +" - node.role == manager\n" +" secrets:\n" +" - db_password\n" +"\n" +"volumes:\n" +" runtime:\n" +" db_data:\n" +"\n" +"secrets:\n" +" db_password:\n" +" external: true\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Create the database password secret on the server:" +msgstr "Crie o secret com a senha do banco de dados no servidor:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "echo \"your_secure_password\" | docker secret create db_password -\n" +msgstr "echo \"your_secure_password\" | docker secret create db_password -\n" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Building and pushing the image" +msgstr "Construindo e enviando a imagem" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Set up Docker login on your local machine" +msgstr "Configure o login do Docker na sua máquina local" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Configure Docker to authenticate with your container registry:" +msgstr "Configure o Docker para se autenticar no seu registro de containers:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "docker login git.example.com\n" +msgstr "docker login git.example.com\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Enter your username and password when prompted." +msgstr "Informe o seu usuário e a sua senha quando solicitado." + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Build the production image" +msgstr "Construa a imagem de produção" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Use the Makefile to build your production image:" +msgstr "Use o Makefile para construir a imagem de produção:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "make prod-build\n" +msgstr "make prod-build\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "This runs the command defined in the Makefile:" +msgstr "Isso executa o comando definido no Makefile:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "docker build --file docker/Dockerfile --target prod --pull -t ${IMAGE}:${IMAGE_TAG} .\n" +msgstr "docker build --file docker/Dockerfile --target prod --pull -t ${IMAGE}:${IMAGE_TAG} .\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "The Dockerfile uses a multi-stage build: 1. Installs Composer dependencies in a builder stage 2. Creates a minimal production image with only the necessary files 3. Runs as a non-root user (`www-data`)" +msgstr "O Dockerfile usa um build multi-stage: 1. Instala as dependências do Composer em um estágio de build 2. Cria uma imagem de produção mínima, só com os arquivos necessários 3. Roda como um usuário não root (`www-data`)" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Push the image to the registry" +msgstr "Envie a imagem para o registro" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Push your built image to the container registry:" +msgstr "Envie a imagem construída para o registro de containers:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "make prod-push\n" +msgstr "make prod-push\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "This executes:" +msgstr "Isso executa:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "docker push ${IMAGE}:${IMAGE_TAG}\n" +msgstr "docker push ${IMAGE}:${IMAGE_TAG}\n" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Deploying to Docker Swarm" +msgstr "Fazendo deploy no Docker Swarm" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Configure SSH access" +msgstr "Configure o acesso SSH" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Set up SSH key-based authentication to your server:" +msgstr "Configure a autenticação por chave SSH no seu servidor:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"# Generate SSH key (if you don't have one)\n" +"ssh-keygen -t ed25519 -C \"your_email@example.com\"\n" +"\n" +"# Copy the key to your server\n" +"ssh-copy-id user@your-server-ip\n" +"\n" +"# Add the SSH host to your SSH config (~/.ssh/config)\n" +"cat >> ~/.ssh/config << EOF\n" +"Host docker-web\n" +" HostName your-server-ip\n" +" User user\n" +" IdentityFile ~/.ssh/id_ed25519\n" +"EOF\n" +msgstr "" +"# Gera uma chave SSH (se você ainda não tiver uma)\n" +"ssh-keygen -t ed25519 -C \"your_email@example.com\"\n" +"\n" +"# Copia a chave para o seu servidor\n" +"ssh-copy-id user@your-server-ip\n" +"\n" +"# Adiciona o host SSH à sua configuração SSH (~/.ssh/config)\n" +"cat >> ~/.ssh/config << EOF\n" +"Host docker-web\n" +" HostName your-server-ip\n" +" User user\n" +" IdentityFile ~/.ssh/id_ed25519\n" +"EOF\n" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Set up Docker context" +msgstr "Configure o contexto do Docker" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Create a Docker context for remote deployment:" +msgstr "Crie um contexto do Docker para o deploy remoto:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "docker context create swarm-prod --docker \"host=ssh://docker-web\"\n" +msgstr "docker context create swarm-prod --docker \"host=ssh://docker-web\"\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Alternatively, configure the `DOCKER_HOST` environment variable:" +msgstr "Como alternativa, configure a variável de ambiente `DOCKER_HOST`:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "export DOCKER_HOST=ssh://docker-web\n" +msgstr "export DOCKER_HOST=ssh://docker-web\n" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Deploy the application" +msgstr "Faça o deploy da aplicação" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Deploy your application stack to Docker Swarm:" +msgstr "Faça o deploy da stack da sua aplicação no Docker Swarm:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "make prod-deploy\n" +msgstr "make prod-deploy\n" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "docker -H ${PROD_SSH} stack deploy --prune --detach=false --with-registry-auth -c docker/compose.yml -c docker/prod/compose.yml ${STACK_NAME}\n" +msgstr "docker -H ${PROD_SSH} stack deploy --prune --detach=false --with-registry-auth -c docker/compose.yml -c docker/prod/compose.yml ${STACK_NAME}\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "The `--with-registry-auth` flag ensures the Swarm nodes can pull images from your private registry." +msgstr "A flag `--with-registry-auth` garante que os nós do Swarm consigam baixar imagens do seu registro privado." + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Verify the deployment" +msgstr "Verifique o deploy" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Check the status of your services:" +msgstr "Verifique o status dos seus serviços:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"docker -H ssh://docker-web service ls\n" +"docker -H ssh://docker-web service ps ${STACK_NAME}_app\n" +msgstr "" +"docker -H ssh://docker-web service ls\n" +"docker -H ssh://docker-web service ps ${STACK_NAME}_app\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "View logs:" +msgstr "Veja os logs:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "docker -H ssh://docker-web service logs ${STACK_NAME}_app\n" +msgstr "docker -H ssh://docker-web service logs ${STACK_NAME}_app\n" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Monitoring and maintenance" +msgstr "Monitoramento e manutenção" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "View service logs" +msgstr "Veja os logs do serviço" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"# View all logs\n" +"docker -H ssh://docker-web service logs -f ${STACK_NAME}_app\n" +"\n" +"# View logs from the last 100 lines\n" +"docker -H ssh://docker-web service logs --tail 100 ${STACK_NAME}_app\n" +"\n" +"# View logs with timestamps\n" +"docker -H ssh://docker-web service logs -t ${STACK_NAME}_app\n" +msgstr "" +"# Mostra todos os logs\n" +"docker -H ssh://docker-web service logs -f ${STACK_NAME}_app\n" +"\n" +"# Mostra as últimas 100 linhas de log\n" +"docker -H ssh://docker-web service logs --tail 100 ${STACK_NAME}_app\n" +"\n" +"# Mostra os logs com timestamps\n" +"docker -H ssh://docker-web service logs -t ${STACK_NAME}_app\n" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Scale the application" +msgstr "Escale a aplicação" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Adjust the number of replicas:" +msgstr "Ajuste o número de réplicas:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "docker -H ssh://docker-web service scale ${STACK_NAME}_app=3\n" +msgstr "docker -H ssh://docker-web service scale ${STACK_NAME}_app=3\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Or update the `replicas` value in `docker/prod/compose.yml` and redeploy." +msgstr "Ou atualize o valor de `replicas` em `docker/prod/compose.yml` e faça o deploy de novo." + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Resource limits" +msgstr "Limites de recursos" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Add resource limits to prevent containers from consuming all server resources. Update `docker/prod/compose.yml`:" +msgstr "Adicione limites de recursos para evitar que os containers consumam todos os recursos do servidor. Atualize o `docker/prod/compose.yml`:" + +#. type: Fenced code block (yaml) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"services:\n" +" app:\n" +" # ... existing configuration ...\n" +" deploy:\n" +" resources:\n" +" limits:\n" +" cpus: '0.5'\n" +" memory: 512M\n" +" reservations:\n" +" cpus: '0.25'\n" +" memory: 256M\n" +msgstr "" +"services:\n" +" app:\n" +" # ... configuração existente ...\n" +" deploy:\n" +" resources:\n" +" limits:\n" +" cpus: '0.5'\n" +" memory: 512M\n" +" reservations:\n" +" cpus: '0.25'\n" +" memory: 256M\n" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md ../src/cookbook/disabling-csrf-protection.md +#, no-wrap +msgid "Security considerations" +msgstr "Considerações de segurança" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Use Docker secrets for sensitive data" +msgstr "Use Docker secrets para dados sensíveis" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Instead of environment variables, use Docker secrets for sensitive information:" +msgstr "Em vez de variáveis de ambiente, use Docker secrets para informações sensíveis:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"# Create secrets\n" +"echo \"database_password\" | docker secret create db_password -\n" +"echo \"api_key\" | docker secret create api_key -\n" +msgstr "" +"# Cria os secrets\n" +"echo \"database_password\" | docker secret create db_password -\n" +"echo \"api_key\" | docker secret create api_key -\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Update `docker/prod/compose.yml`:" +msgstr "Atualize o `docker/prod/compose.yml`:" + +#. type: Fenced code block (yaml) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"services:\n" +" app:\n" +" secrets:\n" +" - db_password\n" +" - api_key\n" +"\n" +"secrets:\n" +" db_password:\n" +" external: true\n" +" api_key:\n" +" external: true\n" +msgstr "" +"services:\n" +" app:\n" +" secrets:\n" +" - db_password\n" +" - api_key\n" +"\n" +"secrets:\n" +" db_password:\n" +" external: true\n" +" api_key:\n" +" external: true\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Access secrets in your application at `/run/secrets/secret_name`." +msgstr "Acesse os secrets na sua aplicação em `/run/secrets/secret_name`." + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Set up a firewall" +msgstr "Configure um firewall" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Configure UFW (Uncomplicated Firewall) on your server:" +msgstr "Configure o UFW (Uncomplicated Firewall) no seu servidor:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"# Allow SSH\n" +"sudo ufw allow 22/tcp\n" +"\n" +"# Allow HTTP and HTTPS\n" +"sudo ufw allow 80/tcp\n" +"sudo ufw allow 443/tcp\n" +"\n" +"# Allow Docker Swarm ports (if you plan to add more nodes)\n" +"sudo ufw allow 2377/tcp\n" +"sudo ufw allow 7946/tcp\n" +"sudo ufw allow 7946/udp\n" +"sudo ufw allow 4789/udp\n" +"\n" +"# Enable the firewall\n" +"sudo ufw enable\n" +msgstr "" +"# Libera SSH\n" +"sudo ufw allow 22/tcp\n" +"\n" +"# Libera HTTP e HTTPS\n" +"sudo ufw allow 80/tcp\n" +"sudo ufw allow 443/tcp\n" +"\n" +"# Libera as portas do Docker Swarm (se você pretende adicionar mais nós)\n" +"sudo ufw allow 2377/tcp\n" +"sudo ufw allow 7946/tcp\n" +"sudo ufw allow 7946/udp\n" +"sudo ufw allow 4789/udp\n" +"\n" +"# Habilita o firewall\n" +"sudo ufw enable\n" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Keep the system updated" +msgstr "Mantenha o sistema atualizado" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Regularly update your server and Docker:" +msgstr "Atualize regularmente o seu servidor e o Docker:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"# Update system packages\n" +"sudo apt-get update && sudo apt-get upgrade -y\n" +"\n" +"# Update Docker images\n" +"docker -H ssh://docker-web service update --image ${IMAGE}:${IMAGE_TAG} ${STACK_NAME}_app\n" +msgstr "" +"# Atualiza os pacotes do sistema\n" +"sudo apt-get update && sudo apt-get upgrade -y\n" +"\n" +"# Atualiza as imagens Docker\n" +"docker -H ssh://docker-web service update --image ${IMAGE}:${IMAGE_TAG} ${STACK_NAME}_app\n" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Service won't start" +msgstr "O serviço não sobe" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Check service events and logs:" +msgstr "Verifique os eventos e os logs do serviço:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"docker -H ssh://docker-web service ps ${STACK_NAME}_app --no-trunc\n" +"docker -H ssh://docker-web service logs ${STACK_NAME}_app\n" +msgstr "" +"docker -H ssh://docker-web service ps ${STACK_NAME}_app --no-trunc\n" +"docker -H ssh://docker-web service logs ${STACK_NAME}_app\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Common issues: - **Image pull errors**: Verify registry authentication with `docker -H ssh://docker-web login` - **Port conflicts**: Ensure no other services are using ports 80/443 - **Resource constraints**: Check available resources with `docker -H ssh://docker-web node ls`" +msgstr "Problemas comuns: - **Erros ao baixar a imagem**: verifique a autenticação no registro com `docker -H ssh://docker-web login` - **Conflitos de porta**: garanta que nenhum outro serviço esteja usando as portas 80/443 - **Limitação de recursos**: verifique os recursos disponíveis com `docker -H ssh://docker-web node ls`" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "SSL certificate issues" +msgstr "Problemas com certificados SSL" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Container registry connection issues" +msgstr "Problemas de conexão com o registro de containers" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Test registry connectivity:" +msgstr "Teste a conectividade com o registro:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"# From your local machine\n" +"docker pull git.example.com/username/myapp:latest\n" +"\n" +"# From the server\n" +"docker -H ssh://docker-web pull git.example.com/username/myapp:latest\n" +msgstr "" +"# Na sua máquina local\n" +"docker pull git.example.com/username/myapp:latest\n" +"\n" +"# No servidor\n" +"docker -H ssh://docker-web pull git.example.com/username/myapp:latest\n" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Summary" +msgstr "Resumo" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "The Makefile commands simplify the deployment workflow: - `make prod-build` - Build the production image - `make prod-push` - Push to the registry - `make prod-deploy` - Deploy to Docker Swarm" +msgstr "Os comandos do Makefile simplificam o fluxo de deploy: - `make prod-build` - Constrói a imagem de produção - `make prod-push` - Envia para o registro - `make prod-deploy` - Faz o deploy no Docker Swarm" + +#. type: Title # +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Deploying Yii applications to Docker Swarm and Traefik" +msgstr "Fazendo deploy de aplicações Yii no Docker Swarm com Traefik" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "This guide walks you through deploying a Yii application to [Docker Swarm](https://docs.docker.com/engine/swarm/) starting from a blank server, using [Traefik](https://traefik.io/traefik) as a reverse proxy and deploying from a container registry ([Forgejo](https://forgejo.org/) or [Gitea](https://about.gitea.com/))." +msgstr "Este guia mostra como fazer o deploy de uma aplicação Yii no [Docker Swarm](https://docs.docker.com/engine/swarm/) a partir de um servidor vazio, usando o [Traefik](https://traefik.io/traefik) como proxy reverso e fazendo o deploy a partir de um registro de containers ([Forgejo](https://forgejo.org/) ou [Gitea](https://about.gitea.com/))." + +#. type: Fenced code block (mermaid) +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"graph LR\n" +" A[Internet] --> B[Reverse Proxy: Traefik]\n" +" B --> C[app1.example.com]\n" +" B --> D[app2.example.com]\n" +" \n" +" subgraph Docker Swarm Cluster\n" +" B\n" +" C\n" +" D\n" +" end\n" +msgstr "" +"graph LR\n" +" A[Internet] --> B[Proxy reverso: Traefik]\n" +" B --> C[app1.example.com]\n" +" B --> D[app2.example.com]\n" +" \n" +" subgraph Docker Swarm Cluster\n" +" B\n" +" C\n" +" D\n" +" end\n" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Setting up Traefik as reverse proxy" +msgstr "Configurando o Traefik como proxy reverso" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "To deploy Traefik as reverse proxy create a file `traefik-stack.yml`:" +msgstr "Para fazer o deploy do Traefik como proxy reverso, crie um arquivo `traefik-stack.yml`:" + +#. type: Fenced code block (yaml) +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"services:\n" +" traefik:\n" +" image: traefik:v2.10\n" +" command:\n" +" - \"--api.insecure=true\"\n" +" - \"--providers.docker=true\"\n" +" - \"--providers.docker.swarmMode=true\"\n" +" - \"--providers.docker.exposedbydefault=false\"\n" +" - \"--entrypoints.web.address=:80\"\n" +" - \"--entrypoints.websecure.address=:443\"\n" +" - \"--certificatesresolvers.letsencrypt.acme.tlschallenge=true\"\n" +" - \"--certificatesresolvers.letsencrypt.acme.email=admin@example.com\"\n" +" - \"--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json\"\n" +" ports:\n" +" - \"80:80\"\n" +" - \"443:443\"\n" +" - \"8080:8080\"\n" +" volumes:\n" +" - \"/var/run/docker.sock:/var/run/docker.sock:ro\"\n" +" - \"traefik_certificates:/letsencrypt\"\n" +" networks:\n" +" - reverse_proxy_public\n" +" deploy:\n" +" placement:\n" +" constraints:\n" +" - node.role == manager\n" +"\n" +"volumes:\n" +" traefik_certificates:\n" +"\n" +"networks:\n" +" reverse_proxy_public:\n" +" external: true\n" +msgstr "" +"services:\n" +" traefik:\n" +" image: traefik:v2.10\n" +" command:\n" +" - \"--api.insecure=true\"\n" +" - \"--providers.docker=true\"\n" +" - \"--providers.docker.swarmMode=true\"\n" +" - \"--providers.docker.exposedbydefault=false\"\n" +" - \"--entrypoints.web.address=:80\"\n" +" - \"--entrypoints.websecure.address=:443\"\n" +" - \"--certificatesresolvers.letsencrypt.acme.tlschallenge=true\"\n" +" - \"--certificatesresolvers.letsencrypt.acme.email=admin@example.com\"\n" +" - \"--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json\"\n" +" ports:\n" +" - \"80:80\"\n" +" - \"443:443\"\n" +" - \"8080:8080\"\n" +" volumes:\n" +" - \"/var/run/docker.sock:/var/run/docker.sock:ro\"\n" +" - \"traefik_certificates:/letsencrypt\"\n" +" networks:\n" +" - reverse_proxy_public\n" +" deploy:\n" +" placement:\n" +" constraints:\n" +" - node.role == manager\n" +"\n" +"volumes:\n" +" traefik_certificates:\n" +"\n" +"networks:\n" +" reverse_proxy_public:\n" +" external: true\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Deploy Traefik:" +msgstr "Faça o deploy do Traefik:" + +#. type: Fenced code block (bash) +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "docker stack deploy -c traefik-stack.yml traefik\n" +msgstr "docker stack deploy -c traefik-stack.yml traefik\n" + +#. type: Fenced code block (yaml) +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"services:\n" +" forgejo:\n" +" image: codeberg.org/forgejo/forgejo:1.21\n" +" ports:\n" +" - \"3000:3000\"\n" +" volumes:\n" +" - forgejo_data:/data\n" +" networks:\n" +" - reverse_proxy_public\n" +" deploy:\n" +" labels:\n" +" - \"traefik.enable=true\"\n" +" - \"traefik.http.routers.app.rule=Host(`git.example.com`)\"\n" +" - \"traefik.http.routers.app.entrypoints=websecure\"\n" +" - \"traefik.http.routers.app.tls.certresolver=letsencrypt\"\n" +" - \"traefik.http.services.app.loadbalancer.server.port=3000\" \n" +"\n" +"volumes:\n" +" forgejo_data:\n" +"\n" +"networks:\n" +" reverse_proxy_public:\n" +" external: true\n" +msgstr "" +"services:\n" +" forgejo:\n" +" image: codeberg.org/forgejo/forgejo:1.21\n" +" ports:\n" +" - \"3000:3000\"\n" +" volumes:\n" +" - forgejo_data:/data\n" +" networks:\n" +" - reverse_proxy_public\n" +" deploy:\n" +" labels:\n" +" - \"traefik.enable=true\"\n" +" - \"traefik.http.routers.app.rule=Host(`git.example.com`)\"\n" +" - \"traefik.http.routers.app.entrypoints=websecure\"\n" +" - \"traefik.http.routers.app.tls.certresolver=letsencrypt\"\n" +" - \"traefik.http.services.app.loadbalancer.server.port=3000\" \n" +"\n" +"volumes:\n" +" forgejo_data:\n" +"\n" +"networks:\n" +" reverse_proxy_public:\n" +" external: true\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "After deployment, access Forgejo at `https://git.example.com` and complete the initial setup. Make sure to enable the container registry in the settings." +msgstr "Depois do deploy, acesse o Forgejo em `https://git.example.com` e conclua a configuração inicial. Não esqueça de habilitar o registro de containers nas configurações." + +#. type: Fenced code block (yaml) +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"services:\n" +" gitea:\n" +" image: gitea/gitea:latest\n" +" ports:\n" +" - \"3000:3000\"\n" +" volumes:\n" +" - gitea_data:/data\n" +" networks:\n" +" - reverse_proxy_public\n" +" deploy:\n" +" labels:\n" +" - \"traefik.enable=true\"\n" +" - \"traefik.http.routers.app.rule=Host(`git.example.com`)\"\n" +" - \"traefik.http.routers.app.entrypoints=websecure\"\n" +" - \"traefik.http.routers.app.tls.certresolver=letsencrypt\"\n" +" - \"traefik.http.services.app.loadbalancer.server.port=3000\" \n" +"\n" +"volumes:\n" +" gitea_data:\n" +"\n" +"networks:\n" +" reverse_proxy_public:\n" +" external: true\n" +msgstr "" +"services:\n" +" gitea:\n" +" image: gitea/gitea:latest\n" +" ports:\n" +" - \"3000:3000\"\n" +" volumes:\n" +" - gitea_data:/data\n" +" networks:\n" +" - reverse_proxy_public\n" +" deploy:\n" +" labels:\n" +" - \"traefik.enable=true\"\n" +" - \"traefik.http.routers.app.rule=Host(`git.example.com`)\"\n" +" - \"traefik.http.routers.app.entrypoints=websecure\"\n" +" - \"traefik.http.routers.app.tls.certresolver=letsencrypt\"\n" +" - \"traefik.http.services.app.loadbalancer.server.port=3000\" \n" +"\n" +"volumes:\n" +" gitea_data:\n" +"\n" +"networks:\n" +" reverse_proxy_public:\n" +" external: true\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "When using Traefik, you'll need to modify the Yii application's `docker/prod/compose.yml` to use Traefik labels instead of Caddy labels:" +msgstr "Ao usar o Traefik, você precisa alterar o `docker/prod/compose.yml` da aplicação Yii para usar labels do Traefik em vez de labels do Caddy:" + +#. type: Fenced code block (yaml) +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "" +"services:\n" +" app:\n" +" image: ${IMAGE}:${IMAGE_TAG}\n" +" networks:\n" +" - reverse_proxy_public\n" +" volumes:\n" +" - runtime:/app/runtime\n" +" - caddy_data:/data\n" +" - caddy_config:/config\n" +" env_file:\n" +" - path: ./prod/.env\n" +" - path: ./prod/override.env\n" +" required: false\\\n" +" environment:\n" +" CADDY_EXTRA_CONFIG: 'auto_https off'\n" +" deploy:\n" +" replicas: 2\n" +" update_config:\n" +" delay: 10s\n" +" parallelism: 1\n" +" order: start-first\n" +" failure_action: rollback\n" +" monitor: 10s\n" +" rollback_config:\n" +" parallelism: 0\n" +" order: stop-first\n" +" restart_policy:\n" +" condition: on-failure\n" +" delay: 5s\n" +" max_attempts: 3\n" +" window: 120s\n" +" labels:\n" +" - \"traefik.enable=true\"\n" +" - \"traefik.http.routers.app.rule=Host(`${PROD_HOST:-app.example.com}`)\"\n" +" - \"traefik.http.routers.app.entrypoints=websecure\"\n" +" - \"traefik.http.routers.app.tls.certresolver=letsencrypt\"\n" +" - \"traefik.http.services.app.loadbalancer.server.port=80\"\n" +msgstr "" +"services:\n" +" app:\n" +" image: ${IMAGE}:${IMAGE_TAG}\n" +" networks:\n" +" - reverse_proxy_public\n" +" volumes:\n" +" - runtime:/app/runtime\n" +" - caddy_data:/data\n" +" - caddy_config:/config\n" +" env_file:\n" +" - path: ./prod/.env\n" +" - path: ./prod/override.env\n" +" required: false\\\n" +" environment:\n" +" CADDY_EXTRA_CONFIG: 'auto_https off'\n" +" deploy:\n" +" replicas: 2\n" +" update_config:\n" +" delay: 10s\n" +" parallelism: 1\n" +" order: start-first\n" +" failure_action: rollback\n" +" monitor: 10s\n" +" rollback_config:\n" +" parallelism: 0\n" +" order: stop-first\n" +" restart_policy:\n" +" condition: on-failure\n" +" delay: 5s\n" +" max_attempts: 3\n" +" window: 120s\n" +" labels:\n" +" - \"traefik.enable=true\"\n" +" - \"traefik.http.routers.app.rule=Host(`${PROD_HOST:-app.example.com}`)\"\n" +" - \"traefik.http.routers.app.entrypoints=websecure\"\n" +" - \"traefik.http.routers.app.tls.certresolver=letsencrypt\"\n" +" - \"traefik.http.services.app.loadbalancer.server.port=80\"\n" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "If Traefik can't obtain certificates: - Verify DNS is pointing to your server - Check that ports 80 and 443 are accessible from the internet - Ensure the email in the Let's Encrypt configuration is valid - Check logs: `docker -H ssh://docker-web service logs traefik_traefik`" +msgstr "Se o Traefik não consegue obter os certificados: - Verifique se o DNS aponta para o seu servidor - Verifique se as portas 80 e 443 estão acessíveis pela internet - Garanta que o e-mail na configuração do Let's Encrypt é válido - Verifique os logs: `docker -H ssh://docker-web service logs traefik_traefik`" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "You've successfully deployed a Yii application to Docker Swarm with: - A container registry (Forgejo or Gitea) - Automatic HTTPS via Traefik - Zero-downtime deployments with rolling updates - High availability with multiple replicas" +msgstr "Você fez o deploy de uma aplicação Yii no Docker Swarm com: - Um registro de containers (Forgejo ou Gitea) - HTTPS automático via Traefik - Deploys sem downtime com rolling updates - Alta disponibilidade com várias réplicas" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "For more information, see: - [Yii Application Template](https://github.com/yiisoft/app) - [Docker Swarm Documentation](https://docs.docker.com/engine/swarm/) - [Traefik Documentation](https://doc.traefik.io/traefik/)" +msgstr "Para mais informações, veja: - [Template de aplicação do Yii](https://github.com/yiisoft/app) - [Documentação do Docker Swarm](https://docs.docker.com/engine/swarm/) - [Documentação do Traefik](https://doc.traefik.io/traefik/)" diff --git a/_translations/po/pt-BR/cookbook_deployment_docker-swarm.md.po b/_translations/po/pt-BR/cookbook_deployment_docker-swarm.md.po new file mode 100644 index 00000000..128b97f8 --- /dev/null +++ b/_translations/po/pt-BR/cookbook_deployment_docker-swarm.md.po @@ -0,0 +1,32 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-01-02 23:54+0000\n" +"PO-Revision-Date: 2026-01-02 23:54+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/cookbook/deployment/docker-swarm.md +#, no-wrap +msgid "Deploying Yii applications to Docker Swarm" +msgstr "Fazendo deploy de aplicações Yii no Docker Swarm" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/docker-swarm.md +msgid "[Using Caddy](docker-swarm-caddy.md)" +msgstr "[Usando Caddy](docker-swarm-caddy.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/docker-swarm.md +msgid "[Using Traefik](docker-swarm-traefik.md)" +msgstr "[Usando Traefik](docker-swarm-traefik.md)" diff --git a/_translations/po/pt-BR/cookbook_deployment_rolling-update-migrations.md.po b/_translations/po/pt-BR/cookbook_deployment_rolling-update-migrations.md.po new file mode 100644 index 00000000..a3b7446c --- /dev/null +++ b/_translations/po/pt-BR/cookbook_deployment_rolling-update-migrations.md.po @@ -0,0 +1,496 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-05-30 09:18+0000\n" +"PO-Revision-Date: 2026-05-30 09:18+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/cookbook/deployment/rolling-update-migrations.md +#, no-wrap +msgid "Applying migrations during rolling updates" +msgstr "Aplicando migrations durante rolling updates" + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Rolling updates keep old and new application instances running at the same time. This makes database changes more delicate than in a single-server deployment: both application versions must work with the same database while the deployment is in progress." +msgstr "Rolling updates mantêm instâncias antigas e novas da aplicação rodando ao mesmo tempo. Isso torna as mudanças no banco de dados mais delicadas do que em um deploy em um único servidor: as duas versões da aplicação precisam funcionar com o mesmo banco de dados enquanto o deploy está em andamento." + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "The safe rule is:" +msgstr "A regra segura é:" + +#. type: Bullet: '1. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Apply database changes that are compatible with the current production code." +msgstr "Aplique mudanças no banco de dados que sejam compatíveis com o código atual de produção." + +#. type: Bullet: '2. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Deploy code that starts using these database changes." +msgstr "Faça o deploy do código que passa a usar essas mudanças no banco de dados." + +#. type: Bullet: '3. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Remove obsolete database structures only after every old application instance is gone." +msgstr "Remova estruturas obsoletas do banco de dados só depois que todas as instâncias antigas da aplicação tiverem saído." + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "This is often called the expand and contract pattern. First expand the schema so both versions can use it. Then move the application code. Finally contract the schema in a later deployment." +msgstr "Isso costuma ser chamado de padrão expand and contract. Primeiro expanda o schema para que as duas versões possam usá-lo. Depois atualize o código da aplicação. Por fim, contraia o schema em um deploy posterior." + +#. type: Title ## +#: ../src/cookbook/deployment/rolling-update-migrations.md +#, no-wrap +msgid "Why this matters" +msgstr "Por que isso importa" + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "During a rolling update, requests may be served by different versions of the application:" +msgstr "Durante um rolling update, as requisições podem ser atendidas por versões diferentes da aplicação:" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "old code that does not know about the new schema;" +msgstr "código antigo, que não conhece o novo schema;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "new code that expects the new schema;" +msgstr "código novo, que espera o novo schema;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "background workers that may lag behind web instances;" +msgstr "workers em segundo plano, que podem ficar atrás das instâncias web;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "scheduled commands that may run during deployment." +msgstr "comandos agendados, que podem rodar durante o deploy." + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "If a migration drops or renames a column before all old instances stop using it, old code fails. If code that requires a new column is deployed before the column exists, new code fails. The migration plan must keep every intermediate state valid." +msgstr "Se uma migration remove ou renomeia uma coluna antes que todas as instâncias antigas parem de usá-la, o código antigo falha. Se o código que exige uma coluna nova vai para produção antes de a coluna existir, o código novo falha. O plano de migrations precisa manter válido cada estado intermediário." + +#. type: Title ## +#: ../src/cookbook/deployment/rolling-update-migrations.md +#, no-wrap +msgid "Deployment flow" +msgstr "Fluxo de deploy" + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Use this flow for changes that must not interrupt production traffic:" +msgstr "Use este fluxo para mudanças que não podem interromper o tráfego de produção:" + +#. type: Bullet: '1. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Create a migration that only adds compatible schema." +msgstr "Crie uma migration que apenas adiciona schema compatível." + +#. type: Bullet: '2. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Apply this migration to production while the current application version is still running." +msgstr "Aplique essa migration em produção enquanto a versão atual da aplicação ainda está rodando." + +#. type: Bullet: '3. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Deploy the new application version with a rolling update." +msgstr "Faça o deploy da nova versão da aplicação com um rolling update." + +#. type: Bullet: '4. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Verify that all instances and workers run the new version." +msgstr "Verifique se todas as instâncias e workers rodam a nova versão." + +#. type: Bullet: '5. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "In a later release, apply cleanup migrations that remove old columns, indexes, tables, or compatibility code." +msgstr "Em uma release posterior, aplique as migrations de limpeza que removem colunas, índices, tabelas ou código de compatibilidade antigos." + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "For Yii applications, run migrations with the same command you use in regular deployments, for example:" +msgstr "Em aplicações Yii, rode as migrations com o mesmo comando que você usa nos deploys normais, por exemplo:" + +#. type: Fenced code block (shell) +#: ../src/cookbook/deployment/rolling-update-migrations.md +#, no-wrap +msgid "./yii migrate\n" +msgstr "./yii migrate\n" + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Run migrations from a single deployment job or one dedicated console container. Do not let every rolling application instance run migrations on startup." +msgstr "Rode as migrations a partir de um único job de deploy ou de um container de console dedicado. Não deixe cada instância do rolling update rodar migrations na inicialização." + +#. type: Title ## +#: ../src/cookbook/deployment/rolling-update-migrations.md +#, no-wrap +msgid "Adding a column" +msgstr "Adicionando uma coluna" + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Adding a nullable column is usually compatible with old code:" +msgstr "Adicionar uma coluna que aceita nulo normalmente é compatível com o código antigo:" + +#. type: Fenced code block (php) +#: ../src/cookbook/deployment/rolling-update-migrations.md +#, no-wrap +msgid "" +"public function up(MigrationBuilder $b): void\n" +"{\n" +" $cb = $b->columnBuilder();\n" +"\n" +" $b->addColumn('user', 'display_name', $cb::string());\n" +"}\n" +msgstr "" +"public function up(MigrationBuilder $b): void\n" +"{\n" +" $cb = $b->columnBuilder();\n" +"\n" +" $b->addColumn('user', 'display_name', $cb::string());\n" +"}\n" + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Then deploy code that writes and reads `display_name`." +msgstr "Depois, faça o deploy do código que grava e lê `display_name`." + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "If the column must eventually be required:" +msgstr "Se a coluna precisar ser obrigatória no futuro:" + +#. type: Bullet: '1. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Add it as nullable." +msgstr "Adicione-a como coluna que aceita nulo." + +#. type: Bullet: '2. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Deploy code that writes it for new and updated rows." +msgstr "Faça o deploy do código que a preenche em linhas novas e atualizadas." + +#. type: Bullet: '3. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Backfill existing rows in batches." +msgstr "Preencha as linhas existentes em lotes." + +#. type: Bullet: '4. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Add a `NOT NULL` constraint in a later migration." +msgstr "Adicione uma restrição `NOT NULL` em uma migration posterior." + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Do not add a `NOT NULL` column without a database default while old code still inserts rows without that column." +msgstr "Não adicione uma coluna `NOT NULL` sem um valor padrão no banco de dados enquanto o código antigo ainda insere linhas sem essa coluna." + +#. type: Title ## +#: ../src/cookbook/deployment/rolling-update-migrations.md +#, no-wrap +msgid "Renaming a column" +msgstr "Renomeando uma coluna" + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Renaming is not compatible because old code uses the old name and new code uses the new name. Use a multi-release change instead:" +msgstr "Renomear não é compatível, porque o código antigo usa o nome antigo e o código novo usa o nome novo. Em vez disso, faça a mudança ao longo de várias releases:" + +#. type: Bullet: '1. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Add the new column." +msgstr "Adicione a nova coluna." + +#. type: Bullet: '2. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Backfill it from the old column." +msgstr "Preencha-a a partir da coluna antiga." + +#. type: Bullet: '3. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Deploy code that writes both columns and reads the new column with a fallback to the old one." +msgstr "Faça o deploy do código que grava nas duas colunas e lê a nova coluna, com fallback para a antiga." + +#. type: Bullet: '4. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Wait until all old code is gone." +msgstr "Espere até que todo o código antigo tenha saído." + +#. type: Bullet: '5. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Deploy code that uses only the new column." +msgstr "Faça o deploy do código que usa só a nova coluna." + +#. type: Bullet: '6. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Drop the old column in a later cleanup migration." +msgstr "Remova a coluna antiga em uma migration de limpeza posterior." + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "The same approach works for moving data to a different table." +msgstr "A mesma abordagem funciona para mover dados para outra tabela." + +#. type: Title ## +#: ../src/cookbook/deployment/rolling-update-migrations.md +#, no-wrap +msgid "Changing a column type" +msgstr "Mudando o tipo de uma coluna" + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Changing a column type in place may lock the table or break either the old or new code. Prefer a new column:" +msgstr "Mudar o tipo de uma coluna no lugar pode travar a tabela ou quebrar o código antigo ou o novo. Prefira uma coluna nova:" + +#. type: Bullet: '1. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Add a column with the target type." +msgstr "Adicione uma coluna com o tipo desejado." + +#. type: Bullet: '2. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Backfill it in batches." +msgstr "Preencha-a em lotes." + +#. type: Bullet: '3. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Deploy code that writes both columns." +msgstr "Faça o deploy do código que grava nas duas colunas." + +#. type: Bullet: '4. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Deploy code that reads the new column." +msgstr "Faça o deploy do código que lê a nova coluna." + +#. type: Bullet: '5. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Drop the old column after all code uses the new one." +msgstr "Remova a coluna antiga depois que todo o código usar a nova." + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "For small tables, an in-place type change may be acceptable. For production tables with traffic, verify locking behavior on the exact database engine and version before applying it." +msgstr "Em tabelas pequenas, mudar o tipo no lugar pode ser aceitável. Em tabelas de produção com tráfego, verifique o comportamento de locks no motor e na versão exatos do banco de dados antes de aplicar a mudança." + +#. type: Title ## +#: ../src/cookbook/deployment/rolling-update-migrations.md +#, no-wrap +msgid "Dropping columns and tables" +msgstr "Removendo colunas e tabelas" + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Dropping is a cleanup step, not the first step:" +msgstr "Remover é uma etapa de limpeza, não a primeira etapa:" + +#. type: Bullet: '1. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Deploy code that no longer reads or writes the column or table." +msgstr "Faça o deploy do código que não lê nem grava mais a coluna ou a tabela." + +#. type: Bullet: '2. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Confirm that old application instances, workers, and scheduled commands are stopped." +msgstr "Confirme que as instâncias antigas da aplicação, os workers e os comandos agendados pararam." + +#. type: Bullet: '3. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Confirm that no external reporting or maintenance scripts depend on it." +msgstr "Confirme que nenhum relatório externo ou script de manutenção depende dela." + +#. type: Bullet: '4. ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Drop it in a separate migration." +msgstr "Remova-a em uma migration separada." + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "This makes rollback safer. If you need to roll back application code before cleanup, the old schema is still available." +msgstr "Isso torna o rollback mais seguro. Se você precisar fazer rollback do código da aplicação antes da limpeza, o schema antigo ainda está disponível." + +#. type: Title ## +#: ../src/cookbook/deployment/rolling-update-migrations.md +#, no-wrap +msgid "Adding indexes and constraints" +msgstr "Adicionando índices e restrições" + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Indexes and constraints may be logically compatible but operationally risky because they can lock tables." +msgstr "Índices e restrições podem ser logicamente compatíveis, mas arriscados na operação, porque podem travar tabelas." + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "For indexes:" +msgstr "Para índices:" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "use online index creation when the database supports it;" +msgstr "use criação de índice online quando o banco de dados suportar;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "for PostgreSQL, consider `CREATE INDEX CONCURRENTLY` from a migration or command that is not wrapped in a transaction;" +msgstr "no PostgreSQL, considere `CREATE INDEX CONCURRENTLY` em uma migration ou comando que não esteja dentro de uma transação;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "for MySQL and MariaDB, check whether the operation can use online DDL for your table and engine." +msgstr "no MySQL e no MariaDB, verifique se a operação pode usar online DDL para a sua tabela e o seu motor." + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "For constraints:" +msgstr "Para restrições:" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "clean invalid data before adding the constraint;" +msgstr "limpe os dados inválidos antes de adicionar a restrição;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "add the constraint only after deployed code preserves it;" +msgstr "adicione a restrição só depois que o código em produção a respeitar;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "for PostgreSQL, consider adding foreign keys and check constraints as `NOT VALID`, then validating them separately." +msgstr "no PostgreSQL, considere adicionar chaves estrangeiras e check constraints como `NOT VALID` e validá-las separadamente depois." + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Keep long-running index creation and validation separate from unrelated schema changes so it is easier to monitor and retry them." +msgstr "Mantenha a criação de índices e as validações demoradas separadas de mudanças de schema não relacionadas, para facilitar o monitoramento e novas tentativas." + +#. type: Title ## +#: ../src/cookbook/deployment/rolling-update-migrations.md +#, no-wrap +msgid "Data migrations" +msgstr "Migrations de dados" + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Data migrations that touch many rows should be safe to run while the application is live:" +msgstr "Migrations de dados que mexem em muitas linhas precisam ser seguras para rodar com a aplicação no ar:" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "make them idempotent so rerunning them does not corrupt data;" +msgstr "torne-as idempotentes, para que rodar de novo não corrompa os dados;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "process rows in small batches;" +msgstr "processe as linhas em lotes pequenos;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "avoid depending on current application service or entity logic because that logic changes over time;" +msgstr "evite depender da lógica atual de serviços ou entidades da aplicação, porque essa lógica muda com o tempo;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "prefer forward-compatible values that both old and new code can handle;" +msgstr "prefira valores compatíveis com o futuro, que tanto o código antigo quanto o novo consigam tratar;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "store progress when a backfill is too large for a single migration run." +msgstr "guarde o progresso quando um preenchimento for grande demais para uma única execução de migration." + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "For very large backfills, use a console command or background job after the schema migration. The schema migration should prepare the database; the background process should move the data gradually." +msgstr "Para preenchimentos muito grandes, use um comando de console ou um job em segundo plano depois da migration de schema. A migration de schema deve preparar o banco de dados; o processo em segundo plano deve mover os dados aos poucos." + +#. type: Title ## +#: ../src/cookbook/deployment/rolling-update-migrations.md +#, no-wrap +msgid "Reverting" +msgstr "Revertendo" + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "In production rolling deployments, reverting a destructive migration is often harder than deploying a corrective migration. Treat `down()` methods for destructive operations as a local-development convenience, not as the main production rollback plan." +msgstr "Em deploys com rolling update em produção, reverter uma migration destrutiva costuma ser mais difícil do que fazer o deploy de uma migration corretiva. Trate os métodos `down()` de operações destrutivas como uma conveniência para o desenvolvimento local, não como o principal plano de rollback em produção." + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "A practical rollback plan is:" +msgstr "Um plano de rollback prático é:" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "before cleanup, roll back code only because old schema is still present;" +msgstr "antes da limpeza, faça rollback apenas do código, porque o schema antigo ainda existe;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "after cleanup, deploy a new forward migration that restores the required structure or compatibility;" +msgstr "depois da limpeza, faça o deploy de uma nova migration que restaure a estrutura ou a compatibilidade necessária;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "restore from backup only when data was actually lost and no forward repair is possible." +msgstr "restaure um backup só quando dados foram realmente perdidos e nenhum reparo por uma nova migration é possível." + +#. type: Title ## +#: ../src/cookbook/deployment/rolling-update-migrations.md +#, no-wrap +msgid "Checklist" +msgstr "Checklist" + +#. type: Plain text +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "Before applying a production migration, verify that:" +msgstr "Antes de aplicar uma migration em produção, verifique que:" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "the current production code works after the migration;" +msgstr "o código atual de produção funciona depois da migration;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "the new code works before and after all instances are updated;" +msgstr "o código novo funciona antes e depois de todas as instâncias serem atualizadas;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "old workers and scheduled commands are covered;" +msgstr "workers antigos e comandos agendados foram considerados;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "inserts and updates keep required columns valid in every deployment phase;" +msgstr "inserts e updates mantêm as colunas obrigatórias válidas em todas as fases do deploy;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "long-running schema operations will not block production traffic unexpectedly;" +msgstr "operações de schema demoradas não vão bloquear o tráfego de produção de forma inesperada;" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/rolling-update-migrations.md +msgid "cleanup happens in a separate release after the rollout is complete." +msgstr "a limpeza acontece em uma release separada, depois que o rollout terminou." diff --git a/_translations/po/pt-BR/cookbook_disabling-csrf-protection.md.po b/_translations/po/pt-BR/cookbook_disabling-csrf-protection.md.po new file mode 100644 index 00000000..61943478 --- /dev/null +++ b/_translations/po/pt-BR/cookbook_disabling-csrf-protection.md.po @@ -0,0 +1,350 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-06-29 17:10+0000\n" +"PO-Revision-Date: 2026-06-29 17:10+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md ../src/cookbook/disabling-csrf-protection.md +#, no-wrap +msgid "Security considerations" +msgstr "Considerações de segurança" + +#. type: Title # +#: ../src/cookbook/disabling-csrf-protection.md +#, no-wrap +msgid "Disabling CSRF protection" +msgstr "Desativando a proteção CSRF" + +#. type: Title ## +#: ../src/cookbook/disabling-csrf-protection.md +#, no-wrap +msgid "What is CSRF protection?" +msgstr "O que é a proteção CSRF?" + +#. type: Plain text +#: ../src/cookbook/disabling-csrf-protection.md +msgid "Cross-Site Request Forgery (CSRF) protection is a security mechanism that prevents malicious websites from making unauthorized requests on behalf of authenticated users. Yii3 includes built-in CSRF protection through the `Yiisoft\\Yii\\Web\\Middleware\\CsrfTokenMiddleware` middleware." +msgstr "A proteção contra Cross-Site Request Forgery (CSRF) é um mecanismo de segurança que impede sites maliciosos de fazer requisições não autorizadas em nome de usuários autenticados. O Yii3 inclui proteção CSRF nativa por meio do middleware `Yiisoft\\Yii\\Web\\Middleware\\CsrfTokenMiddleware`." + +#. type: Plain text +#: ../src/cookbook/disabling-csrf-protection.md +msgid "For a comprehensive understanding of CSRF attacks and protection mechanisms, see the [Security best practices](../guide/security/best-practices.md#avoiding-csrf) section in the main guide." +msgstr "Para entender a fundo os ataques CSRF e os mecanismos de proteção, veja a seção [Boas práticas de segurança](../guide/security/best-practices.md#evitando-csrf) do guia principal." + +#. type: Title ## +#: ../src/cookbook/disabling-csrf-protection.md +#, no-wrap +msgid "When to disable CSRF protection" +msgstr "Quando desativar a proteção CSRF" + +#. type: Plain text +#: ../src/cookbook/disabling-csrf-protection.md +msgid "While CSRF protection should generally remain enabled for web applications, there are specific scenarios where you might need to disable it:" +msgstr "Embora a proteção CSRF deva, em geral, continuar ativada em aplicações web, há cenários específicos em que você pode precisar desativá-la:" + +#. type: Title ### +#: ../src/cookbook/disabling-csrf-protection.md +#, no-wrap +msgid "When external systems cannot provide CSRF tokens" +msgstr "Quando sistemas externos não conseguem fornecer tokens CSRF" + +#. type: Plain text +#: ../src/cookbook/disabling-csrf-protection.md +msgid "When building APIs or handling automated requests from external systems, CSRF protection can interfere with legitimate requests since these systems cannot provide valid CSRF tokens:" +msgstr "Ao construir APIs ou tratar requisições automatizadas de sistemas externos, a proteção CSRF pode atrapalhar requisições legítimas, já que esses sistemas não conseguem fornecer tokens CSRF válidos:" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Third-party integrations**: External services cannot provide valid CSRF tokens" +msgstr "**Integrações de terceiros**: serviços externos não conseguem fornecer tokens CSRF válidos" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Mobile applications**: Native mobile apps typically don't use cookies or sessions in the same way as web browsers" +msgstr "**Aplicativos móveis**: apps móveis nativos normalmente não usam cookies ou sessões da mesma forma que os navegadores" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Server-to-server communication**: API endpoints designed for machine-to-machine communication" +msgstr "**Comunicação entre servidores**: endpoints de API projetados para comunicação máquina a máquina" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Payment processors**: PayPal, Stripe, and other payment systems send webhook notifications" +msgstr "**Processadores de pagamento**: PayPal, Stripe e outros sistemas de pagamento enviam notificações por webhook" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Version control systems**: GitHub, GitLab webhooks for CI/CD pipelines" +msgstr "**Sistemas de controle de versão**: webhooks do GitHub e do GitLab para pipelines de CI/CD" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Social media platforms**: Twitter, Facebook webhook notifications" +msgstr "**Redes sociais**: notificações por webhook do Twitter e do Facebook" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Communication services**: Slack, Discord bot integrations" +msgstr "**Serviços de comunicação**: integrações com bots do Slack e do Discord" + +#. type: Title ## +#: ../src/cookbook/disabling-csrf-protection.md +#, no-wrap +msgid "How to disable CSRF protection" +msgstr "Como desativar a proteção CSRF" + +#. type: Plain text +#: ../src/cookbook/disabling-csrf-protection.md +msgid "First, you need to remove CSRF middleware from your main application middleware list in `config/web/di/application.php`:" +msgstr "Primeiro, remova o middleware de CSRF da lista principal de middlewares da aplicação em `config/web/di/application.php`:" + +#. type: Fenced code block (php) +#: ../src/cookbook/disabling-csrf-protection.md +#, no-wrap +msgid "" +"return [\n" +" Application::class => [\n" +" '__construct()' => [\n" +" 'dispatcher' => DynamicReference::to([\n" +" 'class' => MiddlewareDispatcher::class,\n" +" 'withMiddlewares()' => [\n" +" [\n" +" ErrorCatcher::class,\n" +" SessionMiddleware::class,\n" +" CsrfTokenMiddleware::class, // <- Remove this line \n" +msgstr "" +"return [\n" +" Application::class => [\n" +" '__construct()' => [\n" +" 'dispatcher' => DynamicReference::to([\n" +" 'class' => MiddlewareDispatcher::class,\n" +" 'withMiddlewares()' => [\n" +" [\n" +" ErrorCatcher::class,\n" +" SessionMiddleware::class,\n" +" CsrfTokenMiddleware::class, // <- Remova esta linha \n" + +#. type: Plain text +#: ../src/cookbook/disabling-csrf-protection.md +msgid "Now, if you need to leave CSRF on for specific routes or route groups, you can do so by adding the `CsrfTokenMiddleware` middleware to the router configuration in `config/common/routes.php`. For a group that would be the following:" +msgstr "Agora, se você precisar manter o CSRF ativo para rotas ou grupos de rotas específicos, adicione o middleware `CsrfTokenMiddleware` na configuração do router em `config/common/routes.php`. Para um grupo, fica assim:" + +#. type: Fenced code block (php) +#: ../src/cookbook/disabling-csrf-protection.md +#, no-wrap +msgid "" +"return [\n" +" Group::create()\n" +" ->middleware(CsrfTokenMiddleware::class)\n" +" ->routes(\n" +msgstr "" +"return [\n" +" Group::create()\n" +" ->middleware(CsrfTokenMiddleware::class)\n" +" ->routes(\n" + +#. type: Plain text +#: ../src/cookbook/disabling-csrf-protection.md +msgid "For a single route, you can add the middleware directly to the route:" +msgstr "Para uma única rota, você pode adicionar o middleware diretamente nela:" + +#. type: Fenced code block (php) +#: ../src/cookbook/disabling-csrf-protection.md +#, no-wrap +msgid "" +"Route::methods([Method::GET, Method::POST], '/say[/{test}]')\n" +" ->action(\\App\\Controller\\Echo\\Action::class)\n" +" ->name('echo/say')\n" +" ->middleware(CsrfTokenMiddleware::class)\n" +msgstr "" +"Route::methods([Method::GET, Method::POST], '/say[/{test}]')\n" +" ->action(\\App\\Controller\\Echo\\Action::class)\n" +" ->name('echo/say')\n" +" ->middleware(CsrfTokenMiddleware::class)\n" + +#. type: Plain text +#: ../src/cookbook/disabling-csrf-protection.md +msgid "When disabling CSRF protection, keep these security considerations in mind:" +msgstr "Ao desativar a proteção CSRF, tenha em mente estas considerações de segurança:" + +#. type: Title ### +#: ../src/cookbook/disabling-csrf-protection.md +#, no-wrap +msgid "Alternative authentication methods" +msgstr "Métodos alternativos de autenticação" + +#. type: Plain text +#: ../src/cookbook/disabling-csrf-protection.md +msgid "For API endpoints, implement proper authentication mechanisms:" +msgstr "Para endpoints de API, implemente mecanismos de autenticação adequados:" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**API keys**: Require API keys for authentication" +msgstr "**Chaves de API**: exija chaves de API para autenticação" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Bearer tokens**: Use JWT or similar token-based authentication" +msgstr "**Bearer tokens**: use JWT ou autenticação similar baseada em token" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**OAuth 2.0**: Implement OAuth 2.0 for third-party access" +msgstr "**OAuth 2.0**: implemente OAuth 2.0 para acesso de terceiros" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**IP whitelisting**: Restrict access to known IP addresses for webhooks" +msgstr "**Lista de IPs permitidos**: restrinja o acesso de webhooks a endereços IP conhecidos" + +#. type: Title ### +#: ../src/cookbook/disabling-csrf-protection.md +#, no-wrap +msgid "Request validation" +msgstr "Validação da requisição" + +#. type: Plain text +#: ../src/cookbook/disabling-csrf-protection.md +msgid "Implement additional validation for requests without CSRF protection:" +msgstr "Implemente validação adicional para requisições sem proteção CSRF:" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Signature verification**: Verify webhook signatures (e.g., GitHub's X-Hub-Signature)" +msgstr "**Verificação de assinatura**: verifique assinaturas de webhooks (por exemplo, o X-Hub-Signature do GitHub)" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Timestamp validation**: Check request timestamps to prevent replay attacks" +msgstr "**Validação de timestamp**: confira o timestamp das requisições para evitar ataques de replay" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Rate limiting**: Implement rate limiting to prevent abuse" +msgstr "**Rate limiting**: implemente limite de requisições para evitar abuso" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Input validation**: Strictly validate all input parameters" +msgstr "**Validação de entrada**: valide rigorosamente todos os parâmetros de entrada" + +#. type: Title ### +#: ../src/cookbook/disabling-csrf-protection.md +#, no-wrap +msgid "Example: Webhook signature verification" +msgstr "Exemplo: verificação de assinatura de webhook" + +#. type: Fenced code block (php) +#: ../src/cookbook/disabling-csrf-protection.md +#, no-wrap +msgid "" +"getHeaderLine('X-Webhook-Signature');\n" +" $payload = (string) $request->getBody();\n" +" $expectedSignature = hash_hmac('sha256', $payload, $this->webhookSecret);\n" +" \n" +" if (!hash_equals($signature, $expectedSignature)) {\n" +" throw new \\RuntimeException('Invalid webhook signature');\n" +" }\n" +" \n" +" // Process webhook payload\n" +" // ...\n" +" }\n" +"}\n" +msgstr "" +"getHeaderLine('X-Webhook-Signature');\n" +" $payload = (string) $request->getBody();\n" +" $expectedSignature = hash_hmac('sha256', $payload, $this->webhookSecret);\n" +" \n" +" if (!hash_equals($signature, $expectedSignature)) {\n" +" throw new \\RuntimeException('Invalid webhook signature');\n" +" }\n" +" \n" +" // Processa o payload do webhook\n" +" // ...\n" +" }\n" +"}\n" + +#. type: Title ## +#: ../src/cookbook/disabling-csrf-protection.md +#, no-wrap +msgid "Best practices" +msgstr "Boas práticas" + +#. type: Bullet: '1. ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Minimize exposure**: Only disable CSRF protection where absolutely necessary" +msgstr "**Minimize a exposição**: desative a proteção CSRF apenas onde for realmente necessário" + +#. type: Bullet: '2. ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Use HTTPS**: Always use HTTPS for API endpoints and webhooks" +msgstr "**Use HTTPS**: sempre use HTTPS para endpoints de API e webhooks" + +#. type: Bullet: '3. ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Monitor logs**: Log all requests to API endpoints for security monitoring" +msgstr "**Monitore os logs**: registre em log todas as requisições aos endpoints de API para monitoramento de segurança" + +#. type: Bullet: '4. ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Regular security audits**: Periodically review your API endpoints and their security measures" +msgstr "**Auditorias de segurança regulares**: revise periodicamente seus endpoints de API e as medidas de segurança deles" + +#. type: Bullet: '5. ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Documentation**: Clearly document which endpoints have CSRF protection disabled and why" +msgstr "**Documentação**: documente claramente quais endpoints têm a proteção CSRF desativada e por quê" + +#. type: Title ## +#: ../src/cookbook/disabling-csrf-protection.md +#, no-wrap +msgid "Conclusion" +msgstr "Conclusão" + +#. type: Plain text +#: ../src/cookbook/disabling-csrf-protection.md +msgid "While CSRF protection is crucial for web applications, there are legitimate scenarios where it needs to be disabled, particularly for external APIs and webhooks. When disabling CSRF protection, always implement alternative security measures and follow security best practices to maintain the overall security of your application." +msgstr "Embora a proteção CSRF seja essencial para aplicações web, há cenários legítimos em que ela precisa ser desativada, principalmente para APIs externas e webhooks. Ao desativá-la, sempre implemente medidas de segurança alternativas e siga as boas práticas de segurança para manter a segurança geral da sua aplicação." + +#. type: Plain text +#: ../src/cookbook/disabling-csrf-protection.md +msgid "Remember that disabling CSRF protection increases security risks, so careful consideration and proper implementation of alternative security measures are essential." +msgstr "Lembre-se de que desativar a proteção CSRF aumenta os riscos de segurança, então é essencial avaliar com cuidado e implementar corretamente as medidas de segurança alternativas." diff --git a/_translations/po/pt-BR/cookbook_index.md.po b/_translations/po/pt-BR/cookbook_index.md.po new file mode 100644 index 00000000..04c869ee --- /dev/null +++ b/_translations/po/pt-BR/cookbook_index.md.po @@ -0,0 +1,147 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-10-15 11:09+0000\n" +"PO-Revision-Date: 2026-10-15 11:09+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/cookbook/index.md +#, no-wrap +msgid "Yii3 community cookbook" +msgstr "Cookbook da comunidade Yii3" + +#. type: Plain text +#: ../src/cookbook/index.md +msgid "Yii3 Community Cookbook is an OpenSource book full of tips and tricks about the [Yii3](https://www.yiiframework.com/) PHP framework." +msgstr "O Cookbook da comunidade Yii3 é um livro de código aberto cheio de dicas e truques sobre o framework PHP [Yii3](https://www.yiiframework.com/)." + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "The Yii community creates the cookbook." +msgstr "A comunidade Yii escreve o cookbook." + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md ../src/cookbook/third-party-integrations/index.md +msgid "Yii core team members curate and edit it." +msgstr "Membros do time principal do Yii fazem a curadoria e a edição." + +#. type: Plain text +#: ../src/cookbook/index.md ../src/cookbook/third-party-integrations/index.md +msgid "Feel free to pull-request your own writings. Team members will review it, give feedback and merge the best possible way." +msgstr "Fique à vontade para enviar seus próprios textos via pull request. Os membros do time vão revisar, dar feedback e fazer o merge da melhor forma possível." + +#. type: Plain text +#: ../src/cookbook/index.md +msgid "This book conforms to the [Terms of Yii Documentation](https://www.yiiframework.com/license#docs)." +msgstr "Este livro segue os [Termos da documentação do Yii](https://www.yiiframework.com/license#docs)." + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "[Preface](preface.md)" +msgstr "[Prefácio](preface.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "[Making HTTP requests](making-http-requests.md)" +msgstr "[Fazendo requisições HTTP](making-http-requests.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "[Using htmx for partial page reloads](using-htmx-for-partial-reloads.md)" +msgstr "[Usando htmx para recarregar partes da página](using-htmx-for-partial-reloads.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "[Disabling CSRF protection](disabling-csrf-protection.md)" +msgstr "[Desativando a proteção CSRF](disabling-csrf-protection.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "[Sentry integration](sentry-integration.md)" +msgstr "[Integração com o Sentry](sentry-integration.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "[Using a custom migration template](custom-migration-template.md)" +msgstr "[Usando um template de migration personalizado](custom-migration-template.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "[Custom hydrator type casters](custom-hydrator-type-casters.md)" +msgstr "[Type casters personalizados para o hydrator](custom-hydrator-type-casters.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "[Using Yii in third-party applications](using-yii-in-third-party-apps.md)" +msgstr "[Usando o Yii em aplicações de terceiros](using-yii-in-third-party-apps.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "[Third-party integrations](third-party-integrations/index.md)" +msgstr "[Integrações com terceiros](third-party-integrations/index.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "[Working on Windows](working-on-windows.md)" +msgstr "[Trabalhando no Windows](working-on-windows.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "[Opening files directly in PhpStorm](opening-files-in-phpstorm.md)" +msgstr "[Abrindo arquivos direto no PhpStorm](opening-files-in-phpstorm.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "[Configuring Xdebug](configuring-xdebug.md)" +msgstr "[Configurando o Xdebug](configuring-xdebug.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "[Configuring webservers](configuring-webservers/general.md)" +msgstr "[Configurando servidores web](configuring-webservers/general.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "[Structuring code by use-case with vertical slices](organizing-code/structuring-by-use-case-with-vertical-slices.md)" +msgstr "[Estruturando o código por caso de uso com vertical slices](organizing-code/structuring-by-use-case-with-vertical-slices.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "[Domain](organizing-code/domain.md)" +msgstr "[Domínio](organizing-code/domain.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "[Service components](organizing-code/service.md)" +msgstr "[Componentes de serviço](organizing-code/service.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "[Deploying to Docker Swarm](deployment/docker-swarm.md)" +msgstr "[Deploy com Docker Swarm](deployment/docker-swarm.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "[Deploying Yii applications with Angie Docker Proxy](deployment/angie-docker-proxy.md)" +msgstr "[Deploy de aplicações Yii com Angie Docker Proxy](deployment/angie-docker-proxy.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "[Configuring an application for autoscaling](deployment/autoscaling.md)" +msgstr "[Configurando uma aplicação para autoscaling](deployment/autoscaling.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "[Applying migrations during rolling updates](deployment/rolling-update-migrations.md)" +msgstr "[Aplicando migrations durante rolling updates](deployment/rolling-update-migrations.md)" diff --git a/_translations/po/pt-BR/cookbook_making-http-requests.md.po b/_translations/po/pt-BR/cookbook_making-http-requests.md.po new file mode 100644 index 00000000..04e25044 --- /dev/null +++ b/_translations/po/pt-BR/cookbook_making-http-requests.md.po @@ -0,0 +1,435 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-05-06 19:16+0000\n" +"PO-Revision-Date: 2026-05-06 19:16+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/cookbook/making-http-requests.md +#, no-wrap +msgid "Making HTTP requests" +msgstr "Fazendo requisições HTTP" + +#. type: Plain text +#: ../src/cookbook/making-http-requests.md +msgid "Yii doesn't include its own HTTP client implementation. Use a client that implements [PSR-18](https://www.php-fig.org/psr/psr-18/) and depend on PSR interfaces in your application code." +msgstr "O Yii não inclui uma implementação própria de cliente HTTP. Use um cliente que implemente a [PSR-18](https://www.php-fig.org/psr/psr-18/) e dependa das interfaces PSR no código da sua aplicação." + +#. type: Plain text +#: ../src/cookbook/making-http-requests.md +msgid "This recipe uses [Guzzle](https://docs.guzzlephp.org/) as the HTTP client. Guzzle provides a PSR-18 client and uses PSR-7 messages." +msgstr "Esta receita usa o [Guzzle](https://docs.guzzlephp.org/) como cliente HTTP. O Guzzle fornece um cliente PSR-18 e usa mensagens PSR-7." + +#. type: Title ## +#: ../src/cookbook/making-http-requests.md ../src/cookbook/sentry-integration.md ../src/guide/tutorial/using-yii-with-frankenphp.md ../src/guide/tutorial/using-yii-with-roadrunner.md ../src/guide/tutorial/using-yii-with-swoole.md ../src/guide/views/asset.md ../src/guide/views/view.md ../src/guide/views/widget.md +#, no-wrap +msgid "Installation" +msgstr "Instalação" + +#. type: Plain text +#: ../src/cookbook/making-http-requests.md +msgid "Install Guzzle:" +msgstr "Instale o Guzzle:" + +#. type: Fenced code block (shell) +#: ../src/cookbook/making-http-requests.md +#, no-wrap +msgid "composer require guzzlehttp/guzzle\n" +msgstr "composer require guzzlehttp/guzzle\n" + +#. type: Plain text +#: ../src/cookbook/making-http-requests.md +msgid "The package installs the PSR HTTP interfaces and `guzzlehttp/psr7`, which provides PSR-7 messages and PSR-17 factories." +msgstr "O pacote instala as interfaces HTTP da PSR e o `guzzlehttp/psr7`, que fornece mensagens PSR-7 e factories PSR-17." + +#. type: Title ## +#: ../src/cookbook/making-http-requests.md +#, no-wrap +msgid "Configure the container" +msgstr "Configure o container" + +#. type: Plain text +#: ../src/cookbook/making-http-requests.md +msgid "Create `config/common/di/http-client.php`:" +msgstr "Crie `config/common/di/http-client.php`:" + +#. type: Fenced code block (php) +#: ../src/cookbook/making-http-requests.md +#, no-wrap +msgid "" +" [\n" +" 'class' => Client::class,\n" +" '__construct()' => [\n" +" 'config' => [\n" +" 'timeout' => 10.0,\n" +" 'connect_timeout' => 3.0,\n" +" ],\n" +" ],\n" +" ],\n" +"\n" +" HttpFactory::class => HttpFactory::class,\n" +" RequestFactoryInterface::class => Reference::to(HttpFactory::class),\n" +" ResponseFactoryInterface::class => Reference::to(HttpFactory::class),\n" +" StreamFactoryInterface::class => Reference::to(HttpFactory::class),\n" +" UriFactoryInterface::class => Reference::to(HttpFactory::class),\n" +"];\n" +msgstr "" +" [\n" +" 'class' => Client::class,\n" +" '__construct()' => [\n" +" 'config' => [\n" +" 'timeout' => 10.0,\n" +" 'connect_timeout' => 3.0,\n" +" ],\n" +" ],\n" +" ],\n" +"\n" +" HttpFactory::class => HttpFactory::class,\n" +" RequestFactoryInterface::class => Reference::to(HttpFactory::class),\n" +" ResponseFactoryInterface::class => Reference::to(HttpFactory::class),\n" +" StreamFactoryInterface::class => Reference::to(HttpFactory::class),\n" +" UriFactoryInterface::class => Reference::to(HttpFactory::class),\n" +"];\n" + +#. type: Plain text +#: ../src/cookbook/making-http-requests.md +msgid "Use `ClientInterface` for sending requests and PSR-17 factories for creating requests, streams, and URIs." +msgstr "Use `ClientInterface` para enviar requisições e as factories PSR-17 para criar requisições, streams e URIs." + +#. type: Title ## +#: ../src/cookbook/making-http-requests.md +#, no-wrap +msgid "Send a GET request" +msgstr "Envie uma requisição GET" + +#. type: Plain text +#: ../src/cookbook/making-http-requests.md +msgid "Inject `Psr\\Http\\Client\\ClientInterface` and `Psr\\Http\\Message\\RequestFactoryInterface` into the service that talks to the external API:" +msgstr "Injete `Psr\\Http\\Client\\ClientInterface` e `Psr\\Http\\Message\\RequestFactoryInterface` no serviço que conversa com a API externa:" + +#. type: Fenced code block (php) +#: ../src/cookbook/making-http-requests.md +#, no-wrap +msgid "" +"\n" +" */\n" +" public function latest(string $owner, string $repository): array\n" +" {\n" +" $request = $this->requestFactory\n" +" ->createRequest(\n" +" 'GET',\n" +" sprintf(\n" +" 'https://api.github.com/repos/%s/%s/releases/latest',\n" +" rawurlencode($owner),\n" +" rawurlencode($repository),\n" +" ),\n" +" )\n" +" ->withHeader('Accept', 'application/vnd.github+json');\n" +"\n" +" try {\n" +" $response = $this->httpClient->sendRequest($request);\n" +" } catch (ClientExceptionInterface $e) {\n" +" throw new RuntimeException('GitHub request failed.', previous: $e);\n" +" }\n" +"\n" +" if ($response->getStatusCode() !== 200) {\n" +" throw new RuntimeException(sprintf(\n" +" 'GitHub returned HTTP %d.',\n" +" $response->getStatusCode(),\n" +" ));\n" +" }\n" +"\n" +" return json_decode((string) $response->getBody(), true, 512, JSON_THROW_ON_ERROR);\n" +" }\n" +"}\n" +msgstr "" +"\n" +" */\n" +" public function latest(string $owner, string $repository): array\n" +" {\n" +" $request = $this->requestFactory\n" +" ->createRequest(\n" +" 'GET',\n" +" sprintf(\n" +" 'https://api.github.com/repos/%s/%s/releases/latest',\n" +" rawurlencode($owner),\n" +" rawurlencode($repository),\n" +" ),\n" +" )\n" +" ->withHeader('Accept', 'application/vnd.github+json');\n" +"\n" +" try {\n" +" $response = $this->httpClient->sendRequest($request);\n" +" } catch (ClientExceptionInterface $e) {\n" +" throw new RuntimeException('GitHub request failed.', previous: $e);\n" +" }\n" +"\n" +" if ($response->getStatusCode() !== 200) {\n" +" throw new RuntimeException(sprintf(\n" +" 'GitHub returned HTTP %d.',\n" +" $response->getStatusCode(),\n" +" ));\n" +" }\n" +"\n" +" return json_decode((string) $response->getBody(), true, 512, JSON_THROW_ON_ERROR);\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/cookbook/making-http-requests.md +msgid "PSR-18 clients throw `ClientExceptionInterface` for request sending errors. HTTP status codes such as `404` and `500` are valid responses, so check the status code in your service." +msgstr "Clientes PSR-18 lançam `ClientExceptionInterface` para erros no envio da requisição. Códigos de status HTTP como `404` e `500` são respostas válidas, então verifique o código de status no seu serviço." + +#. type: Title ## +#: ../src/cookbook/making-http-requests.md +#, no-wrap +msgid "Send JSON" +msgstr "Envie JSON" + +#. type: Plain text +#: ../src/cookbook/making-http-requests.md +msgid "Use `StreamFactoryInterface` when you need a request body:" +msgstr "Use `StreamFactoryInterface` quando precisar de um corpo na requisição:" + +#. type: Fenced code block (php) +#: ../src/cookbook/making-http-requests.md +#, no-wrap +msgid "" +" $payload\n" +" */\n" +" public function send(array $payload): void\n" +" {\n" +" $body = $this->streamFactory->createStream(json_encode($payload, JSON_THROW_ON_ERROR));\n" +"\n" +" $request = $this->requestFactory\n" +" ->createRequest('POST', 'https://api.example.com/webhooks')\n" +" ->withHeader('Content-Type', 'application/json')\n" +" ->withHeader('Accept', 'application/json')\n" +" ->withBody($body);\n" +"\n" +" $this->httpClient->sendRequest($request);\n" +" }\n" +"}\n" +msgstr "" +" $payload\n" +" */\n" +" public function send(array $payload): void\n" +" {\n" +" $body = $this->streamFactory->createStream(json_encode($payload, JSON_THROW_ON_ERROR));\n" +"\n" +" $request = $this->requestFactory\n" +" ->createRequest('POST', 'https://api.example.com/webhooks')\n" +" ->withHeader('Content-Type', 'application/json')\n" +" ->withHeader('Accept', 'application/json')\n" +" ->withBody($body);\n" +"\n" +" $this->httpClient->sendRequest($request);\n" +" }\n" +"}\n" + +#. type: Title ### +#: ../src/cookbook/making-http-requests.md ../src/guide/index.md ../src/guide/tutorial/docker.md +#, no-wrap +msgid "Testing" +msgstr "Testes" + +#. type: Plain text +#: ../src/cookbook/making-http-requests.md +msgid "For unit tests, pass a client configured with Guzzle's `MockHandler`:" +msgstr "Para testes unitários, passe um cliente configurado com o `MockHandler` do Guzzle:" + +#. type: Fenced code block (php) +#: ../src/cookbook/making-http-requests.md +#, no-wrap +msgid "" +" '1.0.0'], JSON_THROW_ON_ERROR)),\n" +" ]);\n" +"\n" +" $client = new Client(['handler' => HandlerStack::create($handler)]);\n" +" $factory = new HttpFactory();\n" +"\n" +" $releaseClient = new ReleaseClient($client, $factory);\n" +"\n" +" $release = $releaseClient->latest('yiisoft', 'docs');\n" +"\n" +" $this->assertSame('1.0.0', $release['tag_name']);\n" +" }\n" +"}\n" +msgstr "" +" '1.0.0'], JSON_THROW_ON_ERROR)),\n" +" ]);\n" +"\n" +" $client = new Client(['handler' => HandlerStack::create($handler)]);\n" +" $factory = new HttpFactory();\n" +"\n" +" $releaseClient = new ReleaseClient($client, $factory);\n" +"\n" +" $release = $releaseClient->latest('yiisoft', 'docs');\n" +"\n" +" $this->assertSame('1.0.0', $release['tag_name']);\n" +" }\n" +"}\n" + +#. type: Title ## +#: ../src/cookbook/making-http-requests.md +#, no-wrap +msgid "When to use Guzzle directly" +msgstr "Quando usar o Guzzle diretamente" + +#. type: Plain text +#: ../src/cookbook/making-http-requests.md +msgid "Depend on PSR interfaces for regular application services. Use `GuzzleHttp\\Client` directly in infrastructure code that needs Guzzle-only features such as asynchronous requests, handler stacks, or middleware." +msgstr "Dependa das interfaces PSR nos serviços comuns da aplicação. Use `GuzzleHttp\\Client` diretamente em código de infraestrutura que precise de recursos exclusivos do Guzzle, como requisições assíncronas, handler stacks ou middleware." diff --git a/_translations/po/pt-BR/cookbook_opening-files-in-phpstorm.md.po b/_translations/po/pt-BR/cookbook_opening-files-in-phpstorm.md.po new file mode 100644 index 00000000..2fb4b200 --- /dev/null +++ b/_translations/po/pt-BR/cookbook_opening-files-in-phpstorm.md.po @@ -0,0 +1,263 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-05-06 19:23+0000\n" +"PO-Revision-Date: 2026-05-06 19:23+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/cookbook/opening-files-in-phpstorm.md +#, no-wrap +msgid "Opening files directly in PhpStorm" +msgstr "Abrindo arquivos diretamente no PhpStorm" + +#. type: Plain text +#: ../src/cookbook/opening-files-in-phpstorm.md +msgid "Yii error pages can show links that open stack trace files in PhpStorm at the failing line. This is useful in local development when the error page runs in a browser and the project is open in the IDE." +msgstr "As páginas de erro do Yii podem mostrar links que abrem os arquivos do stack trace no PhpStorm, na linha que falhou. Isso é útil no desenvolvimento local, quando a página de erro roda no navegador e o projeto está aberto na IDE." + +#. type: Title ## +#: ../src/cookbook/opening-files-in-phpstorm.md +#, no-wrap +msgid "Check Toolbox links" +msgstr "Verifique os links do Toolbox" + +#. type: Plain text +#: ../src/cookbook/opening-files-in-phpstorm.md +#, no-wrap +msgid "" +"PhpStorm supports Toolbox URLs that use the `jetbrains://` protocol. To get the `project` value and path format,\n" +"right-click a project file in the Project tool window and select **Copy Path/Reference** > **Toolbox URL**.\n" +"If the copied URL has `origin`, keep the `origin` parameter and its value in your links.\n" +msgstr "" +"O PhpStorm suporta URLs do Toolbox que usam o protocolo `jetbrains://`. Para obter o valor de `project` e o formato do caminho,\n" +"clique com o botão direito em um arquivo do projeto na janela Project e selecione **Copy Path/Reference** > **Toolbox URL**.\n" +"Se a URL copiada tiver `origin`, mantenha o parâmetro `origin` e o valor dele nos seus links.\n" + +#. type: Plain text +#: ../src/cookbook/opening-files-in-phpstorm.md +msgid "On Linux, check that Toolbox registered the protocol handler:" +msgstr "No Linux, verifique se o Toolbox registrou o handler do protocolo:" + +#. type: Fenced code block (shell) +#: ../src/cookbook/opening-files-in-phpstorm.md +#, no-wrap +msgid "xdg-mime query default x-scheme-handler/jetbrains\n" +msgstr "xdg-mime query default x-scheme-handler/jetbrains\n" + +#. type: Plain text +#: ../src/cookbook/opening-files-in-phpstorm.md +msgid "The command should print a Toolbox or JetBrains daemon desktop file, for example `jetbrainsd.desktop`." +msgstr "O comando deve imprimir um arquivo desktop do Toolbox ou do daemon da JetBrains, por exemplo `jetbrainsd.desktop`." + +#. type: Plain text +#: ../src/cookbook/opening-files-in-phpstorm.md +msgid "PhpStorm should be running with the project open when you click stack trace links." +msgstr "O PhpStorm deve estar rodando com o projeto aberto quando você clicar nos links do stack trace." + +#. type: Title ## +#: ../src/cookbook/opening-files-in-phpstorm.md +#, no-wrap +msgid "Configure error trace links" +msgstr "Configure os links do stack trace" + +#. type: Plain text +#: ../src/cookbook/opening-files-in-phpstorm.md +msgid "The Yii application template configures `Yiisoft\\ErrorHandler\\Renderer\\HtmlRenderer` in `config/common/di/error-handler.php`. It reads a `traceLink` parameter and uses it for stack trace file links." +msgstr "O template de aplicação do Yii configura o `Yiisoft\\ErrorHandler\\Renderer\\HtmlRenderer` em `config/common/di/error-handler.php`. Ele lê um parâmetro `traceLink` e o usa nos links de arquivos do stack trace." + +#. type: Plain text +#: ../src/cookbook/opening-files-in-phpstorm.md +msgid "Add the parameter to `config/common/params.php`:" +msgstr "Adicione o parâmetro em `config/common/params.php`:" + +#. type: Fenced code block (php) +#: ../src/cookbook/opening-files-in-phpstorm.md +#, no-wrap +msgid "" +" 'jetbrains://phpstorm/navigate/reference?project=my-app&path={file}:{line}',\n" +" // Other parameters.\n" +"];\n" +msgstr "" +" 'jetbrains://phpstorm/navigate/reference?project=my-app&path={file}:{line}',\n" +" // Outros parâmetros.\n" +"];\n" + +#. type: Plain text +#: ../src/cookbook/opening-files-in-phpstorm.md +msgid "Replace `my-app` with the `project` value from the Toolbox URL. If the Toolbox URL uses `origin`, keep `origin` in the link template and use its value." +msgstr "Substitua `my-app` pelo valor de `project` da URL do Toolbox. Se a URL do Toolbox usar `origin`, mantenha `origin` no template do link e use o valor dele." + +#. type: Plain text +#: ../src/cookbook/opening-files-in-phpstorm.md +msgid "After that, open a debug error page and click a file link in the stack trace." +msgstr "Depois disso, abra uma página de erro em modo debug e clique em um link de arquivo no stack trace." + +#. type: Title ## +#: ../src/cookbook/opening-files-in-phpstorm.md +#, no-wrap +msgid "Map Docker paths to host paths" +msgstr "Mapeie os caminhos do Docker para os caminhos do host" + +#. type: Plain text +#: ../src/cookbook/opening-files-in-phpstorm.md +msgid "When the application runs in Docker, stack traces usually contain container paths such as `/app/src/...`. PhpStorm needs the matching host path." +msgstr "Quando a aplicação roda no Docker, os stack traces geralmente contêm caminhos do container, como `/app/src/...`. O PhpStorm precisa do caminho correspondente no host." + +#. type: Plain text +#: ../src/cookbook/opening-files-in-phpstorm.md +msgid "Set `APP_HOST_PATH` in `docker/dev/override.env` to the project path on the host machine. Set `APP_IDE_PROJECT` to the `project` value from a Toolbox URL. If the URL uses `origin`, store the `origin` value instead and use `origin` in the final URL template:" +msgstr "Defina `APP_HOST_PATH` em `docker/dev/override.env` com o caminho do projeto na máquina host. Defina `APP_IDE_PROJECT` com o valor de `project` de uma URL do Toolbox. Se a URL usar `origin`, guarde o valor de `origin` e use `origin` no template final da URL:" + +#. type: Fenced code block (dotenv) +#: ../src/cookbook/opening-files-in-phpstorm.md +#, no-wrap +msgid "" +"APP_HOST_PATH=/home/user/projects/my-app\n" +"APP_IDE_PROJECT=my-app\n" +msgstr "" +"APP_HOST_PATH=/home/user/projects/my-app\n" +"APP_IDE_PROJECT=my-app\n" + +#. type: Plain text +#: ../src/cookbook/opening-files-in-phpstorm.md +msgid "`docker/dev/override.env` is for developer-specific settings and shouldn't be committed. See [Override env files](../guide/tutorial/docker.md#override-env-files) for details." +msgstr "O `docker/dev/override.env` é para configurações específicas de cada desenvolvedor e não deve ser commitado. Veja [Arquivos env de override](../guide/tutorial/docker.md#arquivos-env-de-override) para mais detalhes." + +#. type: Plain text +#: ../src/cookbook/opening-files-in-phpstorm.md +msgid "In the application parameters, expose these environment values as `$params['app']['hostPath']` and `$params['app']['ideProject']`." +msgstr "Nos parâmetros da aplicação, exponha esses valores de ambiente como `$params['app']['hostPath']` e `$params['app']['ideProject']`." + +#. type: Plain text +#: ../src/cookbook/opening-files-in-phpstorm.md +msgid "With the default application template, `/app/src/Web/HomePage/Action.php` will be linked as `/home/user/projects/my-app/src/Web/HomePage/Action.php`." +msgstr "Com o template de aplicação padrão, `/app/src/Web/HomePage/Action.php` será linkado como `/home/user/projects/my-app/src/Web/HomePage/Action.php`." + +#. type: Title ## +#: ../src/cookbook/opening-files-in-phpstorm.md +#, no-wrap +msgid "Configure `HtmlRenderer` manually" +msgstr "Configure o `HtmlRenderer` manualmente" + +#. type: Plain text +#: ../src/cookbook/opening-files-in-phpstorm.md +msgid "If your application doesn't have the template's `error-handler.php` configuration, configure `HtmlRenderer` directly:" +msgstr "Se a sua aplicação não tiver a configuração `error-handler.php` do template, configure o `HtmlRenderer` diretamente:" + +#. type: Fenced code block (php) +#: ../src/cookbook/opening-files-in-phpstorm.md +#, no-wrap +msgid "" +" [\n" +" '__construct()' => [\n" +" 'traceLink' => 'jetbrains://phpstorm/navigate/reference?project=my-app&path={file}:{line}',\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +" [\n" +" '__construct()' => [\n" +" 'traceLink' => 'jetbrains://phpstorm/navigate/reference?project=my-app&path={file}:{line}',\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/cookbook/opening-files-in-phpstorm.md +msgid "For Docker, use a closure to map the container path to the host path:" +msgstr "Para o Docker, use uma closure para mapear o caminho do container para o caminho do host:" + +#. type: Fenced code block (php) +#: ../src/cookbook/opening-files-in-phpstorm.md +#, no-wrap +msgid "" +" [\n" +" '__construct()' => [\n" +" 'traceLink' => static function (string $file, ?int $line) use ($hostPath, $project): string {\n" +" $file = preg_replace('~^/app/~', $hostPath, $file);\n" +" $path = $line === null ? $file : $file . ':' . $line;\n" +"\n" +" return str_replace(\n" +" ['{project}', '{path}'],\n" +" [$project, $path],\n" +" 'jetbrains://phpstorm/navigate/reference?project={project}&path={path}',\n" +" );\n" +" },\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +" [\n" +" '__construct()' => [\n" +" 'traceLink' => static function (string $file, ?int $line) use ($hostPath, $project): string {\n" +" $file = preg_replace('~^/app/~', $hostPath, $file);\n" +" $path = $line === null ? $file : $file . ':' . $line;\n" +"\n" +" return str_replace(\n" +" ['{project}', '{path}'],\n" +" [$project, $path],\n" +" 'jetbrains://phpstorm/navigate/reference?project={project}&path={path}',\n" +" );\n" +" },\n" +" ],\n" +" ],\n" +"];\n" diff --git a/_translations/po/pt-BR/cookbook_organizing-code_domain.md.po b/_translations/po/pt-BR/cookbook_organizing-code_domain.md.po new file mode 100644 index 00000000..32987fa4 --- /dev/null +++ b/_translations/po/pt-BR/cookbook_organizing-code_domain.md.po @@ -0,0 +1,193 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-10-11 10:37+0000\n" +"PO-Revision-Date: 2026-10-11 10:37+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/cookbook/organizing-code/domain.md +#, no-wrap +msgid "Domain" +msgstr "Domínio" + +#. type: Plain text +#: ../src/cookbook/organizing-code/domain.md +#, no-wrap +msgid "" +"The Domain or domain model is what makes the project unique. With requirements and terminology of the problem being solved\n" +"in mind (the problem context), you build an abstraction that consists of entities, their relationships, and logic that\n" +"operates these entities. To focus on the complex part of the problem, domain is, ideally, separated from\n" +" the infrastructure part of the system (that's how to save data into a database, how to form HTTP response, etc.).\n" +msgstr "" +"O domínio, ou modelo de domínio, é o que torna o projeto único. Com os requisitos e a terminologia do problema a ser resolvido\n" +"em mente (o contexto do problema), você constrói uma abstração composta por entidades, seus relacionamentos e a lógica que\n" +"opera essas entidades. Para focar na parte complexa do problema, o domínio, idealmente, fica separado da\n" +" parte de infraestrutura do sistema (como salvar dados no banco de dados, como montar a resposta HTTP etc.).\n" + +#. type: Plain text +#: ../src/cookbook/organizing-code/domain.md +#, no-wrap +msgid "" +"> [!NOTE]\n" +"> Such isolation is suitable for complex systems. If your project domain is basically create/read/update/delete\n" +"> for a set of records with not much complex logic, it makes no sense to apply a complex solution to a simple problem.\n" +"> The individual concepts of domain design below could be applied separately, so make sure to check these even if your\n" +"> project isn't that complicated. \n" +msgstr "" +"> [!NOTE]\n" +"> Esse isolamento é adequado para sistemas complexos. Se o domínio do seu projeto é basicamente criar/ler/atualizar/excluir\n" +"> um conjunto de registros sem muita lógica complexa, não faz sentido aplicar uma solução complexa a um problema simples.\n" +"> Os conceitos individuais de design de domínio abaixo podem ser aplicados separadamente, então vale conferi-los mesmo que o seu\n" +"> projeto não seja tão complicado. \n" + +#. type: Title ## +#: ../src/cookbook/organizing-code/domain.md +#, no-wrap +msgid "Bounded context" +msgstr "Bounded context" + +#. type: Plain text +#: ../src/cookbook/organizing-code/domain.md +msgid "It's nearly impossible to build a model that solves multiple problems that aren't too complicated by itself. Therefore, it's a good practice to divide the domain into several use-cases and have a separate model for each use-case. Such separated models are called \"bounded contexts.\"" +msgstr "É quase impossível construir um modelo que resolva vários problemas sem que ele mesmo fique complicado demais. Por isso, é uma boa prática dividir o domínio em vários casos de uso e ter um modelo separado para cada um. Esses modelos separados são chamados de \"bounded contexts\"." + +#. type: Title ## +#: ../src/cookbook/organizing-code/domain.md +#, no-wrap +msgid "Building blocks" +msgstr "Blocos de construção" + +#. type: Plain text +#: ../src/cookbook/organizing-code/domain.md +msgid "There are various building blocks that are typically used when describing domain models. It isn't mandatory to use them all." +msgstr "Existem vários blocos de construção normalmente usados para descrever modelos de domínio. Não é obrigatório usar todos." + +#. type: Bullet: '- ' +#: ../src/cookbook/organizing-code/domain.md ../src/cookbook/organizing-code/service.md +#, no-wrap +msgid "Entity" +msgstr "Entidade" + +#. type: Plain text +#: ../src/cookbook/organizing-code/domain.md +msgid "Entity is a uniquely identifiable object such as user, product, payment, etc. When comparing them, you're checking ID, not the attribute values. If there are two objects with different attributes but the same ID, they're considered being the same thing." +msgstr "Entidade é um objeto identificável de forma única, como um usuário, um produto, um pagamento etc. Ao comparar entidades, você verifica o ID, não os valores dos atributos. Se dois objetos têm atributos diferentes, mas o mesmo ID, eles são considerados a mesma coisa." + +#. type: Title ### +#: ../src/cookbook/organizing-code/domain.md +#, no-wrap +msgid "Value object" +msgstr "Value object" + +#. type: Plain text +#: ../src/cookbook/organizing-code/domain.md +msgid "Value object describes an object by its characteristics. For example, a price that consists of value and currency. When comparing such objects, you're checking actual values. If they match, an object is considered to be the same." +msgstr "Um value object descreve um objeto por suas características. Por exemplo, um preço composto por valor e moeda. Ao comparar esses objetos, você verifica os valores de fato. Se eles coincidem, os objetos são considerados iguais." + +#. type: Title ### +#: ../src/cookbook/organizing-code/domain.md +#, no-wrap +msgid "Aggregate" +msgstr "Agregado" + +#. type: Plain text +#: ../src/cookbook/organizing-code/domain.md +msgid "Aggregate is a set of domain objects such as entities and value objects and additional data that could be treated as a single unit. It usually represents a compound object from a domain model such as shop order or HR person dossier." +msgstr "Agregado é um conjunto de objetos de domínio, como entidades e value objects, e dados adicionais que podem ser tratados como uma única unidade. Ele geralmente representa um objeto composto do modelo de domínio, como um pedido de loja ou o dossiê de uma pessoa no RH." + +#. type: Plain text +#: ../src/cookbook/organizing-code/domain.md +msgid "One of the components of an aggregate is called a root. The root identifies an aggregate as a whole and should be used to access it." +msgstr "Um dos componentes de um agregado é chamado de raiz. A raiz identifica o agregado como um todo e deve ser usada para acessá-lo." + +#. type: Title ### +#: ../src/cookbook/organizing-code/domain.md +#, no-wrap +msgid "Domain event" +msgstr "Evento de domínio" + +#. type: Plain text +#: ../src/cookbook/organizing-code/domain.md +msgid "An aggregate, while processed, may raise events. For example, when order is confirmed, `OrderConfirmed` event would be risen so other parts of the system may react on these." +msgstr "Um agregado, ao ser processado, pode disparar eventos. Por exemplo, quando um pedido é confirmado, o evento `OrderConfirmed` é disparado para que outras partes do sistema possam reagir a ele." + +#. type: Title ### +#: ../src/cookbook/organizing-code/domain.md +#, no-wrap +msgid "Data transfer object" +msgstr "Data transfer object" + +#. type: Plain text +#: ../src/cookbook/organizing-code/domain.md +msgid "Data transfer object or DTO is an object whose only purpose is to hold data as it is. It's commonly used to pass data between different services." +msgstr "Data transfer object, ou DTO, é um objeto cujo único propósito é guardar dados como estão. Ele é comumente usado para passar dados entre diferentes serviços." + +#. type: Title ### +#: ../src/cookbook/organizing-code/domain.md +#, no-wrap +msgid "Service" +msgstr "Serviço" + +#. type: Plain text +#: ../src/cookbook/organizing-code/domain.md +msgid "Service is a class that contains a standalone operation within the context of your domain model. See \"[service components](service.md)\"." +msgstr "Serviço é uma classe que contém uma operação independente dentro do contexto do seu modelo de domínio. Veja \"[componentes de serviço](service.md)\"." + +#. type: Title ## +#: ../src/cookbook/organizing-code/domain.md ../src/cookbook/organizing-code/service.md ../src/guide/start/databases.md +#, no-wrap +msgid "Repository" +msgstr "Repositório" + +#. type: Plain text +#: ../src/cookbook/organizing-code/domain.md +msgid "The repository task is to abstract away how domain objects are obtained. These are usually separated into two parts: an interface that stays in the domain layer and an implementation that's situated in the infrastructure layer. In such a way, domain doesn't care how data is obtained and saved and may be focused around the complicated business logic instead." +msgstr "A tarefa do repositório é abstrair como os objetos de domínio são obtidos. Ele geralmente é dividido em duas partes: uma interface, que fica na camada de domínio, e uma implementação, que fica na camada de infraestrutura. Dessa forma, o domínio não se importa com como os dados são obtidos e salvos e pode se concentrar na lógica de negócio complicada." + +#. type: Plain text +#: ../src/cookbook/organizing-code/domain.md +msgid "Repository is usually implemented as a service." +msgstr "O repositório geralmente é implementado como um serviço." + +#. type: Title ### +#: ../src/cookbook/organizing-code/domain.md +#, no-wrap +msgid "Instantiating building blocks" +msgstr "Instanciando os blocos de construção" + +#. type: Plain text +#: ../src/cookbook/organizing-code/domain.md +msgid "Entity, value object, aggregate, and domain events aren't services and shouldn't be instantiated through DI container. Using `new` is the way to go with these." +msgstr "Entidades, value objects, agregados e eventos de domínio não são serviços e não devem ser instanciados pelo container de DI. Use `new` para criá-los." + +#. type: Title ## +#: ../src/cookbook/organizing-code/domain.md ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md ../src/guide/concept/autoloading.md ../src/guide/concept/di-container.md ../src/guide/security/best-practices.md ../src/guide/tutorial/console-applications.md ../src/internals/004-namespaces.md ../src/internals/007-exceptions.md ../src/internals/008-interfaces.md +#, no-wrap +msgid "References" +msgstr "Referências" + +#. type: Bullet: '- ' +#: ../src/cookbook/organizing-code/domain.md +msgid "[BoundedContext by Martin Fowler](https://martinfowler.com/bliki/BoundedContext.html)" +msgstr "[BoundedContext, por Martin Fowler](https://martinfowler.com/bliki/BoundedContext.html)" + +#. type: Bullet: '- ' +#: ../src/cookbook/organizing-code/domain.md +msgid "[ValueObject by Martin Fowler](https://martinfowler.com/bliki/ValueObject.html)" +msgstr "[ValueObject, por Martin Fowler](https://martinfowler.com/bliki/ValueObject.html)" + +#. type: Bullet: '- ' +#: ../src/cookbook/organizing-code/domain.md +msgid "[Aggregate by Marting Fowler](https://martinfowler.com/bliki/DDD_Aggregate.html)" +msgstr "[Aggregate, por Martin Fowler](https://martinfowler.com/bliki/DDD_Aggregate.html)" diff --git a/_translations/po/pt-BR/cookbook_organizing-code_service.md.po b/_translations/po/pt-BR/cookbook_organizing-code_service.md.po new file mode 100644 index 00000000..289d4b3c --- /dev/null +++ b/_translations/po/pt-BR/cookbook_organizing-code_service.md.po @@ -0,0 +1,247 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-10-11 10:37+0000\n" +"PO-Revision-Date: 2026-10-11 10:37+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Bullet: '- ' +#: ../src/cookbook/organizing-code/domain.md ../src/cookbook/organizing-code/service.md +#, no-wrap +msgid "Entity" +msgstr "Entidade" + +#. type: Title ## +#: ../src/cookbook/organizing-code/domain.md ../src/cookbook/organizing-code/service.md ../src/guide/start/databases.md +#, no-wrap +msgid "Repository" +msgstr "Repositório" + +#. type: Title # +#: ../src/cookbook/organizing-code/service.md +#, no-wrap +msgid "Service components" +msgstr "Componentes de serviço" + +#. type: Plain text +#: ../src/cookbook/organizing-code/service.md +msgid "Application may get complicated, so it makes sense to extract focused parts of business logic or infrastructure into service components. They're typically injected into other components or action handlers. It's usually done via autowiring:" +msgstr "A aplicação pode ficar complicada, então faz sentido extrair partes focadas da lógica de negócio ou da infraestrutura para componentes de serviço. Eles normalmente são injetados em outros componentes ou em action handlers. Isso geralmente é feito por autowiring:" + +#. type: Fenced code block (php) +#: ../src/cookbook/organizing-code/service.md +#, no-wrap +msgid "" +"public function actionIndex(CurrentRoute $route, MyService $myService): ResponseInterface\n" +"{\n" +" $id = $route->getArgument('id');\n" +" \n" +" // ...\n" +" $extraData = $myService->getExtraData($id);\n" +" \n" +" // ...\n" +"}\n" +msgstr "" +"public function actionIndex(CurrentRoute $route, MyService $myService): ResponseInterface\n" +"{\n" +" $id = $route->getArgument('id');\n" +" \n" +" // ...\n" +" $extraData = $myService->getExtraData($id);\n" +" \n" +" // ...\n" +"}\n" + +#. type: Plain text +#: ../src/cookbook/organizing-code/service.md +msgid "Yii3 doesn't technically imply any limitations on how you build services. In general, there's no need to extend from a base class or implement a certain interface:" +msgstr "Tecnicamente, o Yii3 não impõe nenhuma limitação sobre como você constrói serviços. Em geral, não é preciso estender uma classe base nem implementar uma interface específica:" + +#. type: Fenced code block (php) +#: ../src/cookbook/organizing-code/service.md +#, no-wrap +msgid "" +"final readonly class MyService\n" +"{\n" +" public function __construct(\n" +" private ExtraDataStorage $extraDataStorage\n" +" )\n" +" {\n" +" }\n" +"\n" +" public function getExtraData(string $id): array\n" +" {\n" +" return $this->extraDataStorage->get($id);\n" +" }\n" +"}\n" +msgstr "" +"final readonly class MyService\n" +"{\n" +" public function __construct(\n" +" private ExtraDataStorage $extraDataStorage\n" +" )\n" +" {\n" +" }\n" +"\n" +" public function getExtraData(string $id): array\n" +" {\n" +" return $this->extraDataStorage->get($id);\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/cookbook/organizing-code/service.md +msgid "Services either perform a task or return data. They're created once, put into a DI container and then could be used multiple times. Because of that, it's a good idea to keep your services stateless that's both service itself and any of its dependencies shouldn't hold state. You can ensure it by using `readonly` PHP keyword at class level." +msgstr "Serviços executam uma tarefa ou retornam dados. Eles são criados uma vez, colocados em um container de DI e então podem ser usados várias vezes. Por isso, é uma boa ideia manter seus serviços sem estado: nem o próprio serviço nem qualquer uma de suas dependências devem guardar estado. Você pode garantir isso usando a palavra-chave `readonly` do PHP no nível da classe." + +#. type: Title ## +#: ../src/cookbook/organizing-code/service.md +#, no-wrap +msgid "Service dependencies and configuration" +msgstr "Dependências e configuração de serviços" + +#. type: Plain text +#: ../src/cookbook/organizing-code/service.md +msgid "Services should always define all their dependencies on other services via `__construct()`. It both allows you to use a service right away after it's created and serves as an indicator of a service doing too much if there are too many dependencies." +msgstr "Serviços devem sempre declarar todas as suas dependências de outros serviços via `__construct()`. Isso permite usar o serviço logo depois de criado e também serve como indicador de que o serviço faz coisas demais, quando há dependências demais." + +#. type: Bullet: '- ' +#: ../src/cookbook/organizing-code/service.md +msgid "After the service is created, it shouldn't be re-configured in runtime." +msgstr "Depois de criado, o serviço não deve ser reconfigurado em tempo de execução." + +#. type: Bullet: '- ' +#: ../src/cookbook/organizing-code/service.md +msgid "DI container instance usually **shouldn't** be injected as a dependency. Prefer concrete interfaces." +msgstr "A instância do container de DI geralmente **não deve** ser injetada como dependência. Prefira interfaces concretas." + +#. type: Bullet: '- ' +#: ../src/cookbook/organizing-code/service.md +msgid "In case of complicated or \"heavy\" initialization, try to postpone it until the service method is called." +msgstr "Em caso de inicialização complicada ou \"pesada\", tente adiá-la até que o método do serviço seja chamado." + +#. type: Plain text +#: ../src/cookbook/organizing-code/service.md +msgid "The same is valid for configuration values. They should be provided as a constructor argument. Related values could be grouped together into value objects. For example, database connection usually requires DSN string, username and password. These three could be combined into Dsn class:" +msgstr "O mesmo vale para valores de configuração. Eles devem ser fornecidos como argumento do construtor. Valores relacionados podem ser agrupados em value objects. Por exemplo, uma conexão com banco de dados geralmente exige a string DSN, o nome de usuário e a senha. Esses três podem ser combinados em uma classe Dsn:" + +#. type: Fenced code block (php) +#: ../src/cookbook/organizing-code/service.md +#, no-wrap +msgid "" +"final readonly class Dsn\n" +"{\n" +" public function __construct(\n" +" public string $dsn,\n" +" public string $username,\n" +" public string $password\n" +" )\n" +" {\n" +" if (!$this->isValidDsn($dsn)) {\n" +" throw new \\InvalidArgumentException('DSN provided is not valid.');\n" +" }\n" +" }\n" +" \n" +" private function isValidDsn(string $dsn): bool\n" +" {\n" +" // check DSN validity \n" +" }\n" +"}\n" +msgstr "" +"final readonly class Dsn\n" +"{\n" +" public function __construct(\n" +" public string $dsn,\n" +" public string $username,\n" +" public string $password\n" +" )\n" +" {\n" +" if (!$this->isValidDsn($dsn)) {\n" +" throw new \\InvalidArgumentException('DSN provided is not valid.');\n" +" }\n" +" }\n" +" \n" +" private function isValidDsn(string $dsn): bool\n" +" {\n" +" // verifica se o DSN é válido \n" +" }\n" +"}\n" + +#. type: Title ## +#: ../src/cookbook/organizing-code/service.md +#, no-wrap +msgid "Service methods" +msgstr "Métodos de serviço" + +#. type: Plain text +#: ../src/cookbook/organizing-code/service.md +msgid "Service method usually does something. It could be a simple thing repeated exactly, but usually it depends on the context. For example:" +msgstr "Um método de serviço geralmente faz alguma coisa. Pode ser algo simples repetido exatamente igual, mas normalmente depende do contexto. Por exemplo:" + +#. type: Fenced code block (php) +#: ../src/cookbook/organizing-code/service.md +#, no-wrap +msgid "" +"final readonly class PostPersister\n" +"{\n" +" public function __construct(\n" +" private Storage $db\n" +" )\n" +" {\n" +" }\n" +" \n" +" public function persist(Post $post)\n" +" {\n" +" $this->db->insertOrUpdate('post', $post); \n" +" }\n" +"}\n" +msgstr "" +"final readonly class PostPersister\n" +"{\n" +" public function __construct(\n" +" private Storage $db\n" +" )\n" +" {\n" +" }\n" +" \n" +" public function persist(Post $post)\n" +" {\n" +" $this->db->insertOrUpdate('post', $post); \n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/cookbook/organizing-code/service.md +msgid "There's a service that is saving posts into permanent storage such as a database. An object allowing communication with a concrete storage is always the same, so it's injected using constructor while the post saved could vary, so it's passed as a method argument." +msgstr "Aqui há um serviço que salva posts em um armazenamento permanente, como um banco de dados. O objeto que permite a comunicação com um armazenamento concreto é sempre o mesmo, então é injetado pelo construtor, enquanto o post salvo pode variar, então é passado como argumento do método." + +#. type: Title ## +#: ../src/cookbook/organizing-code/service.md +#, no-wrap +msgid "Is everything a service?" +msgstr "Tudo é um serviço?" + +#. type: Plain text +#: ../src/cookbook/organizing-code/service.md +msgid "Often it makes sense to choose another class type to place your code into. Check:" +msgstr "Muitas vezes faz sentido escolher outro tipo de classe para colocar seu código. Confira:" + +#. type: Bullet: '- ' +#: ../src/cookbook/organizing-code/service.md +msgid "Widget" +msgstr "Widget" + +#. type: Bullet: '- ' +#: ../src/cookbook/organizing-code/service.md +msgid "[Middleware](../../guide/structure/middleware.md)" +msgstr "[Middleware](../../guide/structure/middleware.md)" diff --git a/_translations/po/pt-BR/cookbook_organizing-code_structuring-by-use-case-with-vertical-slices.md.po b/_translations/po/pt-BR/cookbook_organizing-code_structuring-by-use-case-with-vertical-slices.md.po new file mode 100644 index 00000000..b6ad47ee --- /dev/null +++ b/_translations/po/pt-BR/cookbook_organizing-code_structuring-by-use-case-with-vertical-slices.md.po @@ -0,0 +1,147 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-10-11 10:37+0000\n" +"PO-Revision-Date: 2026-10-11 10:37+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/organizing-code/domain.md ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md ../src/guide/concept/autoloading.md ../src/guide/concept/di-container.md ../src/guide/security/best-practices.md ../src/guide/tutorial/console-applications.md ../src/internals/004-namespaces.md ../src/internals/007-exceptions.md ../src/internals/008-interfaces.md +#, no-wrap +msgid "References" +msgstr "Referências" + +#. type: Title # +#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md +#, no-wrap +msgid "Structuring code by use-case with vertical slices" +msgstr "Estruturando o código por caso de uso com vertical slices" + +#. type: Plain text +#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md +msgid "When building an application, it's important to organize the code in a way that makes it easy to understand, support, and scale. One popular approach is to structure the code by use-case with vertical slices." +msgstr "Ao construir uma aplicação, é importante organizar o código de forma que ele seja fácil de entender, manter e escalar. Uma abordagem popular é estruturar o código por caso de uso com vertical slices." + +#. type: Plain text +#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md +msgid "Vertical slices are self-contained pieces of functionality that cover the entire stack, from the user interface to the data access layer. Developer organizes each slice around a specific use case, such as creating a new user or updating a product." +msgstr "Vertical slices são partes autocontidas de funcionalidade que cobrem toda a stack, da interface do usuário à camada de acesso a dados. O desenvolvedor organiza cada slice em torno de um caso de uso específico, como criar um novo usuário ou atualizar um produto." + +#. type: Plain text +#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md +msgid "When structuring code classically by type (such as models, views, controllers, helpers, etc.), it can be easy to lose sight of the bigger picture and how different pieces of code interact to support specific features or use cases. This can lead to code duplication, tight coupling, and poor maintainability as the application grows." +msgstr "Ao estruturar o código da forma clássica, por tipo (models, views, controllers, helpers etc.), é fácil perder de vista o quadro geral e como as diferentes partes do código interagem para atender funcionalidades ou casos de uso específicos. Isso pode levar a duplicação de código, acoplamento forte e manutenção difícil à medida que a aplicação cresce." + +#. type: Plain text +#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md +msgid "On the other hand, structuring code by use-case makes developers focus on a specific feature or workflow and understand how different pieces of code work together to support that feature. This approach also helps to keep related code together in a single directory, making it easier to navigate and support. Vertical slicing also encourages the use of domain-driven design concepts, such as entities, repositories, and services, which can help to promote good separation of concerns and modularity." +msgstr "Por outro lado, estruturar o código por caso de uso faz os desenvolvedores focarem em uma funcionalidade ou fluxo específico e entenderem como as diferentes partes do código trabalham juntas para atendê-lo. Essa abordagem também ajuda a manter o código relacionado junto, em um único diretório, o que facilita a navegação e a manutenção. O vertical slicing também incentiva o uso de conceitos de domain-driven design, como entidades, repositórios e serviços, que ajudam a promover uma boa separação de responsabilidades e modularidade." + +#. type: Plain text +#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md +msgid "Additionally, structuring code by use-case can make it easier to test and debug the application since use-case namespace encapsulates each feature or workflow in its own directory with clear boundaries and well-defined interfaces." +msgstr "Além disso, estruturar o código por caso de uso pode facilitar os testes e o debug da aplicação, já que o namespace do caso de uso encapsula cada funcionalidade ou fluxo em seu próprio diretório, com limites claros e interfaces bem definidas." + +#. type: Plain text +#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md +msgid "Here's an example directory structure for a PHP application organized using vertical slices:" +msgstr "Veja um exemplo de estrutura de diretórios de uma aplicação PHP organizada com vertical slices:" + +#. type: Fenced code block +#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md +#, no-wrap +msgid "" +"src/\n" +"└── Blog/\n" +" ├── Model/\n" +" │ ├── Comment.php\n" +" │ ├── CommentRepository.php\n" +" │ ├── Post.php\n" +" │ └── PostRepository.php\n" +" ├── Service/ \n" +" │ └── MarkdownProcessor.php\n" +" ├── UseCase/\n" +" │ ├── CreateComment/\n" +" │ │ ├── CreateCommentAction.php\n" +" │ │ ├── CreateCommentRequest.php\n" +" │ ├── CreatePost/\n" +" │ │ ├── CreatePostAction.php\n" +" │ │ ├── CreatePostRequest.php\n" +" │ ├── DeleteComment/\n" +" │ │ ├── DeleteCommentAction.php\n" +" │ │ ├── DeleteCommentRequest.php\n" +" │ ├── DeletePost/\n" +" │ │ ├── DeletePostAction.php\n" +" │ │ ├── DeletePostRequest.php\n" +" │ ├── ListComments/\n" +" │ │ ├── ListCommentsAction.php\n" +" │ ├── ListPosts/\n" +" │ │ ├── ListPostsAction.php\n" +" │ ├── UpdatePost/\n" +" │ │ ├── UpdatePostAction.php\n" +" │ │ ├── UpdatePostRequest.php\n" +" │ ├── ViewPost/\n" +" │ │ ├── ViewPostAction.php\n" +" │ ├── Rss/\n" +" │ │ ├── RssAction.php\n" +" | | ├── RssBuilder.php\n" +msgstr "" +"src/\n" +"└── Blog/\n" +" ├── Model/\n" +" │ ├── Comment.php\n" +" │ ├── CommentRepository.php\n" +" │ ├── Post.php\n" +" │ └── PostRepository.php\n" +" ├── Service/ \n" +" │ └── MarkdownProcessor.php\n" +" ├── UseCase/\n" +" │ ├── CreateComment/\n" +" │ │ ├── CreateCommentAction.php\n" +" │ │ ├── CreateCommentRequest.php\n" +" │ ├── CreatePost/\n" +" │ │ ├── CreatePostAction.php\n" +" │ │ ├── CreatePostRequest.php\n" +" │ ├── DeleteComment/\n" +" │ │ ├── DeleteCommentAction.php\n" +" │ │ ├── DeleteCommentRequest.php\n" +" │ ├── DeletePost/\n" +" │ │ ├── DeletePostAction.php\n" +" │ │ ├── DeletePostRequest.php\n" +" │ ├── ListComments/\n" +" │ │ ├── ListCommentsAction.php\n" +" │ ├── ListPosts/\n" +" │ │ ├── ListPostsAction.php\n" +" │ ├── UpdatePost/\n" +" │ │ ├── UpdatePostAction.php\n" +" │ │ ├── UpdatePostRequest.php\n" +" │ ├── ViewPost/\n" +" │ │ ├── ViewPostAction.php\n" +" │ ├── Rss/\n" +" │ │ ├── RssAction.php\n" +" | | ├── RssBuilder.php\n" + +#. type: Plain text +#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md +msgid "Each vertical slice has its own directory, which has code associated with the use case." +msgstr "Cada vertical slice tem seu próprio diretório, que contém o código associado ao caso de uso." + +#. type: Plain text +#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md +msgid "The use-case subdirectories and their respective classes are organized by type within each directory, omitting a directory if there's a single class of the type. If code is shared between multiple use-cases, it's moved one level up such as `Model` or `Service`." +msgstr "Os subdiretórios de caso de uso e suas respectivas classes são organizados por tipo dentro de cada diretório, omitindo o diretório quando há uma única classe daquele tipo. Se um código é compartilhado entre vários casos de uso, ele sobe um nível, como em `Model` ou `Service`." + +#. type: Bullet: '- ' +#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md +msgid "[Application structure overview](../../guide/structure/overview.md)" +msgstr "[Visão geral da estrutura da aplicação](../../guide/structure/overview.md)" diff --git a/_translations/po/pt-BR/cookbook_preface.md.po b/_translations/po/pt-BR/cookbook_preface.md.po new file mode 100644 index 00000000..603b8c24 --- /dev/null +++ b/_translations/po/pt-BR/cookbook_preface.md.po @@ -0,0 +1,80 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 08:02+0000\n" +"PO-Revision-Date: 2025-12-24 08:02+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/en/cookbook/deployment/docker-swarm.md ../src/en/cookbook/preface.md +#, no-wrap +msgid "Prerequisites" +msgstr "Pré-requisitos" + +#. type: Title # +#: ../src/en/cookbook/preface.md +#, no-wrap +msgid "Preface" +msgstr "Prefácio" + +#. type: Plain text +#: ../src/en/cookbook/preface.md ../src/en/guide/intro/what-is-yii.md +msgid "Yii is a high-performance, package-based PHP framework for developing modern applications. The name Yii (pronounced `Yee` or `[ji:]`) means \"simple and evolutionary\" in Chinese. You can also think about it as an acronym for **Yes It Is**!" +msgstr "O Yii é um framework PHP de alto desempenho, baseado em pacotes, para desenvolver aplicações modernas. O nome Yii (pronuncia-se `Yee` ou `[ji:]`) significa \"simples e evolutivo\" em chinês. Você também pode pensar nele como um acrônimo de **Yes It Is**!" + +#. type: Plain text +#: ../src/en/cookbook/preface.md ../src/en/guide/intro/what-is-yii.md +msgid "Yii is a generic Web programming framework. You can use it for developing all kinds of Web applications using PHP. Because of its architecture and sophisticated caching support, it's especially suitable for developing large-scale applications such as portals, content management systems, e-commerce, REST APIs, etc." +msgstr "O Yii é um framework genérico de programação web. Você pode usá-lo para desenvolver todo tipo de aplicação web com PHP. Por causa da sua arquitetura e do suporte sofisticado a cache, ele é especialmente indicado para aplicações de grande porte, como portais, sistemas de gerenciamento de conteúdo, e-commerce, APIs REST etc." + +#. type: Plain text +#: ../src/en/cookbook/preface.md +msgid "With comprehensive documentation and an enthusiastic user community, Yii can significantly reduce your development time in the long run." +msgstr "Com uma documentação abrangente e uma comunidade de usuários entusiasmada, o Yii pode reduzir bastante o seu tempo de desenvolvimento a longo prazo." + +#. type: Title ## +#: ../src/en/cookbook/preface.md +#, no-wrap +msgid "What's the book about" +msgstr "Sobre o que é este livro" + +#. type: Plain text +#: ../src/en/cookbook/preface.md +msgid "This book is for you if you're familiar with Yii3, building Yii applications, and read the official Yii3 guide. It covers fundamentally important development concepts, application architecture approaches, integrating third party services with Yii3, etc." +msgstr "Este livro é para você se já conhece o Yii3, constrói aplicações Yii e leu o guia oficial do Yii3. Ele cobre conceitos de desenvolvimento fundamentais, abordagens de arquitetura de aplicações, integração de serviços de terceiros com o Yii3 etc." + +#. type: Plain text +#: ../src/en/cookbook/preface.md +msgid "The book consists of individual recipes gathered from Yii experts that you can apply in your applications. These go by topic, but you are free to read them in any order as there is no dependency between them." +msgstr "O livro é formado por receitas individuais reunidas por especialistas em Yii, que você pode aplicar nas suas aplicações. Elas são organizadas por tema, mas você pode lê-las em qualquer ordem, já que não há dependência entre elas." + +#. type: Bullet: '- ' +#: ../src/en/cookbook/preface.md +msgid "You should have Yii3 installed." +msgstr "Você deve ter o Yii3 instalado." + +#. type: Bullet: '- ' +#: ../src/en/cookbook/preface.md +msgid "You should be familiar with the framework basics and the official guide." +msgstr "Você deve conhecer o básico do framework e o guia oficial." + +#. type: Title ## +#: ../src/en/cookbook/preface.md +#, no-wrap +msgid "How to participate" +msgstr "Como participar" + +#. type: Plain text +#: ../src/en/cookbook/preface.md +msgid "If you've found any errata, wrong information, want to improve something or have a good recipe, create an issue or make a pull request in [the book GitHub repository](https://github.com/yiisoft/docs)." +msgstr "Se você encontrou alguma errata ou informação errada, quer melhorar algo ou tem uma boa receita, crie uma issue ou abra um pull request no [repositório do livro no GitHub](https://github.com/yiisoft/docs)." diff --git a/_translations/po/pt-BR/cookbook_sentry-integration.md.po b/_translations/po/pt-BR/cookbook_sentry-integration.md.po new file mode 100644 index 00000000..6c7e3e18 --- /dev/null +++ b/_translations/po/pt-BR/cookbook_sentry-integration.md.po @@ -0,0 +1,284 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 08:02+0000\n" +"PO-Revision-Date: 2025-12-24 08:02+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/en/cookbook/making-http-requests.md ../src/en/cookbook/sentry-integration.md ../src/en/guide/tutorial/using-yii-with-roadrunner.md ../src/en/guide/tutorial/using-yii-with-swoole.md ../src/en/guide/views/asset.md ../src/en/guide/views/view.md ../src/en/guide/views/widget.md +#, no-wrap +msgid "Installation" +msgstr "Instalação" + +#. type: Title # +#: ../src/en/cookbook/sentry-integration.md +#, no-wrap +msgid "Sentry integration" +msgstr "Integração com o Sentry" + +#. type: Title ## +#: ../src/en/cookbook/sentry-integration.md +#, no-wrap +msgid "What is Sentry" +msgstr "O que é o Sentry" + +#. type: Plain text +#: ../src/en/cookbook/sentry-integration.md +#, no-wrap +msgid "" +"[Sentry](https://sentry.io/) is a tool for monitoring and debugging application stability and performance.\n" +"Sentry gives you access to the events that you send there from your application.\n" +msgstr "" +"O [Sentry](https://sentry.io/) é uma ferramenta para monitorar e depurar a estabilidade e o desempenho de aplicações.\n" +"O Sentry dá acesso aos eventos que você envia para ele a partir da sua aplicação.\n" + +#. type: Plain text +#: ../src/en/cookbook/sentry-integration.md +msgid "Most often, Sentry is used for monitoring errors (exceptions). You can enrich errors with context to better understand the problem: - Request arguments - Tags for grouping exceptions - Environment state: environment variables, application state, and other global attributes" +msgstr "Na maioria das vezes, o Sentry é usado para monitorar erros (exceções). Você pode enriquecer os erros com contexto para entender melhor o problema: - Argumentos da requisição - Tags para agrupar exceções - Estado do ambiente: variáveis de ambiente, estado da aplicação e outros atributos globais" + +#. type: Plain text +#: ../src/en/cookbook/sentry-integration.md +msgid "You can find the full list of features on the official website: https://sentry.io/welcome/" +msgstr "Você encontra a lista completa de funcionalidades no site oficial: https://sentry.io/welcome/" + +#. type: Title ### +#: ../src/en/cookbook/sentry-integration.md +#, no-wrap +msgid "Install the package" +msgstr "Instale o pacote" + +#. type: Plain text +#: ../src/en/cookbook/sentry-integration.md +msgid "Install the required package `yiisoft/yii-sentry` with the following command:" +msgstr "Instale o pacote necessário `yiisoft/yii-sentry` com o seguinte comando:" + +#. type: Fenced code block (shell) +#: ../src/en/cookbook/sentry-integration.md +#, no-wrap +msgid "composer require yiisoft/yii-sentry --prefer-dist\n" +msgstr "composer require yiisoft/yii-sentry --prefer-dist\n" + +#. type: Title ### +#: ../src/en/cookbook/sentry-integration.md +#, no-wrap +msgid "Install an HTTP driver" +msgstr "Instale um driver HTTP" + +#. type: Plain text +#: ../src/en/cookbook/sentry-integration.md +msgid "The [`getsentry/sentry-php`](https://github.com/getsentry/sentry-php) library requires the `php-http/httplug` package and any HTTP driver. In the example below we’ll use the Guzzle adapter." +msgstr "A biblioteca [`getsentry/sentry-php`](https://github.com/getsentry/sentry-php) exige o pacote `php-http/httplug` e algum driver HTTP. No exemplo abaixo, vamos usar o adaptador do Guzzle." + +#. type: Plain text +#: ../src/en/cookbook/sentry-integration.md +#, no-wrap +msgid "> You can find the list of all adapters on [this page](https://docs.php-http.org/en/latest/clients.html#clients-adapters).\n" +msgstr "> Você encontra a lista de todos os adaptadores [nesta página](https://docs.php-http.org/en/latest/clients.html#clients-adapters).\n" + +#. type: Plain text +#: ../src/en/cookbook/sentry-integration.md +msgid "To install the packages, run the following command:" +msgstr "Para instalar os pacotes, execute o seguinte comando:" + +#. type: Fenced code block (shell) +#: ../src/en/cookbook/sentry-integration.md +#, no-wrap +msgid "composer require php-http/httplug php-http/guzzle7-adapter --prefer-dist\n" +msgstr "composer require php-http/httplug php-http/guzzle7-adapter --prefer-dist\n" + +#. type: Title ## +#: ../src/en/cookbook/sentry-integration.md ../src/en/guide/concept/configuration.md ../src/en/guide/tutorial/using-yii-with-roadrunner.md ../src/en/guide/views/view-injections.md +#, no-wrap +msgid "Configuration" +msgstr "Configuração" + +#. type: Title ### +#: ../src/en/cookbook/sentry-integration.md +#, no-wrap +msgid "Get and store the token" +msgstr "Obtenha e guarde o token" + +#. type: Plain text +#: ../src/en/cookbook/sentry-integration.md +msgid "Next, configure the application." +msgstr "Em seguida, configure a aplicação." + +#. type: Plain text +#: ../src/en/cookbook/sentry-integration.md +msgid "First, register at [Sentry](https://sentry.io) and create a project." +msgstr "Primeiro, cadastre-se no [Sentry](https://sentry.io) e crie um projeto." + +#. type: Plain text +#: ../src/en/cookbook/sentry-integration.md +msgid "Then, in the project settings on the “General Settings” tab, find the “Security Token” field and copy its value." +msgstr "Depois, nas configurações do projeto, na aba “General Settings”, encontre o campo “Security Token” e copie o valor dele." + +#. type: Plain text +#: ../src/en/cookbook/sentry-integration.md +#, no-wrap +msgid "" +"Now put this token into the package configuration. By default, the config is located at `config/packages/yiisoft/yii-sentry/config/params.php`.\n" +"Set the copied token as the value of the array element at `yiisoft/yii-sentry` => `options` => `dsn`. Example:\n" +msgstr "" +"Agora coloque esse token na configuração do pacote. Por padrão, a configuração fica em `config/packages/yiisoft/yii-sentry/config/params.php`.\n" +"Defina o token copiado como valor do elemento do array em `yiisoft/yii-sentry` => `options` => `dsn`. Exemplo:\n" + +#. type: Fenced code block (diff) +#: ../src/en/cookbook/sentry-integration.md +#, no-wrap +msgid "" +"'yiisoft/yii-sentry' => [\n" +" 'enabled' => true,\n" +" 'options' => [\n" +"- 'dsn' => '',\n" +"+ 'dsn' => 'TOKEN',\n" +" ],\n" +"],\n" +msgstr "" +"'yiisoft/yii-sentry' => [\n" +" 'enabled' => true,\n" +" 'options' => [\n" +"- 'dsn' => '',\n" +"+ 'dsn' => 'TOKEN',\n" +" ],\n" +"],\n" + +#. type: Title ### +#: ../src/en/cookbook/sentry-integration.md +#, no-wrap +msgid "Configure the HTTP client" +msgstr "Configure o cliente HTTP" + +#. type: Plain text +#: ../src/en/cookbook/sentry-integration.md +msgid "After installing the HTTP client, configure it." +msgstr "Depois de instalar o cliente HTTP, configure-o." + +#. type: Plain text +#: ../src/en/cookbook/sentry-integration.md +msgid "Create the file `config/common/sentry.php` and put the following code into it:" +msgstr "Crie o arquivo `config/common/sentry.php` e coloque nele o seguinte código:" + +#. type: Fenced code block (php) +#: ../src/en/cookbook/sentry-integration.md +#, no-wrap +msgid "" +" \\GuzzleHttp\\Client::class,\n" +" \\Http\\Client\\HttpAsyncClient::class => [\n" +" 'class' => \\Http\\Adapter\\Guzzle7\\Client::class,\n" +" '__construct()' => [\n" +" \\Yiisoft\\Factory\\Definition\\Reference::to(\\Http\\Client\\HttpClient::class),\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +" \\GuzzleHttp\\Client::class,\n" +" \\Http\\Client\\HttpAsyncClient::class => [\n" +" 'class' => \\Http\\Adapter\\Guzzle7\\Client::class,\n" +" '__construct()' => [\n" +" \\Yiisoft\\Factory\\Definition\\Reference::to(\\Http\\Client\\HttpClient::class),\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Title # +#: ../src/en/cookbook/sentry-integration.md +#, no-wrap +msgid "Integration" +msgstr "Integração" + +#. type: Title ### +#: ../src/en/cookbook/sentry-integration.md +#, no-wrap +msgid "Web" +msgstr "Web" + +#. type: Plain text +#: ../src/en/cookbook/sentry-integration.md +msgid "Sentry support for `web` is implemented as middleware." +msgstr "O suporte do Sentry para `web` é implementado como middleware." + +#. type: Plain text +#: ../src/en/cookbook/sentry-integration.md +msgid "That means you only need to add `SentryMiddleware` to the global middleware list in `config/web/application.php`:" +msgstr "Isso significa que você só precisa adicionar o `SentryMiddleware` à lista global de middlewares em `config/web/application.php`:" + +#. type: Fenced code block (diff) +#: ../src/en/cookbook/sentry-integration.md +#, no-wrap +msgid "" +"return [\n" +" Yiisoft\\Yii\\Web\\Application::class => [\n" +" '__construct()' => [\n" +" 'dispatcher' => DynamicReference::to(static function (Injector $injector) {\n" +" return ($injector->make(MiddlewareDispatcher::class))\n" +" ->withMiddlewares(\n" +" [\n" +" Router::class,\n" +" SubFolder::class,\n" +"+ SentryMiddleware::class,\n" +" ErrorCatcher::class,\n" +" ]\n" +" );\n" +" }),\n" +" 'fallbackHandler' => Reference::to(NotFoundHandler::class),\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +"return [\n" +" Yiisoft\\Yii\\Web\\Application::class => [\n" +" '__construct()' => [\n" +" 'dispatcher' => DynamicReference::to(static function (Injector $injector) {\n" +" return ($injector->make(MiddlewareDispatcher::class))\n" +" ->withMiddlewares(\n" +" [\n" +" Router::class,\n" +" SubFolder::class,\n" +"+ SentryMiddleware::class,\n" +" ErrorCatcher::class,\n" +" ]\n" +" );\n" +" }),\n" +" 'fallbackHandler' => Reference::to(NotFoundHandler::class),\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Title ## +#: ../src/en/cookbook/sentry-integration.md ../src/en/internals/003-roadmap.md +#, no-wrap +msgid "Console" +msgstr "Console" + +#. type: Plain text +#: ../src/en/cookbook/sentry-integration.md +msgid "Sentry supports `console` via a handler for the [ConsoleEvents::ERROR](https://symfony.com/doc/current/components/console/events.html#the-consoleevents-error-event) event." +msgstr "O Sentry suporta o `console` por meio de um handler para o evento [ConsoleEvents::ERROR](https://symfony.com/doc/current/components/console/events.html#the-consoleevents-error-event)." + +#. type: Plain text +#: ../src/en/cookbook/sentry-integration.md +msgid "The package provides a configuration file that automatically subscribes the application to this event." +msgstr "O pacote fornece um arquivo de configuração que inscreve a aplicação nesse evento automaticamente." diff --git a/_translations/po/pt-BR/cookbook_third-party-integrations_index.md.po b/_translations/po/pt-BR/cookbook_third-party-integrations_index.md.po new file mode 100644 index 00000000..c2531abe --- /dev/null +++ b/_translations/po/pt-BR/cookbook_third-party-integrations_index.md.po @@ -0,0 +1,52 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-10-07 20:23+0000\n" +"PO-Revision-Date: 2026-10-07 20:23+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md ../src/cookbook/third-party-integrations/index.md +msgid "Yii core team members curate and edit it." +msgstr "Membros do time principal do Yii fazem a curadoria e a edição." + +#. type: Plain text +#: ../src/cookbook/index.md ../src/cookbook/third-party-integrations/index.md +msgid "Feel free to pull-request your own writings. Team members will review it, give feedback and merge the best possible way." +msgstr "Fique à vontade para enviar seus próprios textos via pull request. Os membros do time vão revisar, dar feedback e fazer o merge da melhor forma possível." + +#. type: Title # +#: ../src/cookbook/third-party-integrations/index.md +#, no-wrap +msgid "Third-Party Integrations" +msgstr "Integrações de terceiros" + +#. type: Plain text +#: ../src/cookbook/third-party-integrations/index.md +msgid "This is a collection of community-contributed guides for integrating third-party packages with Yii3." +msgstr "Esta é uma coleção de guias, contribuídos pela comunidade, para integrar pacotes de terceiros com o Yii3." + +#. type: Bullet: '- ' +#: ../src/cookbook/third-party-integrations/index.md +msgid "The Yii community creates the guides." +msgstr "Os guias são criados pela comunidade Yii." + +#. type: Bullet: '- ' +#: ../src/cookbook/third-party-integrations/index.md +msgid "[Symfony Messenger integration guide](symfony-messenger-integration-guide.md)" +msgstr "[Guia de integração com o Symfony Messenger](symfony-messenger-integration-guide.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/third-party-integrations/index.md +msgid "[Symfony Scheduler integration guide](symfony-scheduler-integration-guide.md)" +msgstr "[Guia de integração com o Symfony Scheduler](symfony-scheduler-integration-guide.md)" diff --git a/_translations/po/pt-BR/cookbook_third-party-integrations_symfony-messenger-integration-guide.md.po b/_translations/po/pt-BR/cookbook_third-party-integrations_symfony-messenger-integration-guide.md.po new file mode 100644 index 00000000..31313d57 --- /dev/null +++ b/_translations/po/pt-BR/cookbook_third-party-integrations_symfony-messenger-integration-guide.md.po @@ -0,0 +1,738 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-09-25 14:35+0000\n" +"PO-Revision-Date: 2026-09-25 14:35+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/making-http-requests.md ../src/cookbook/sentry-integration.md ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md ../src/guide/tutorial/using-yii-with-frankenphp.md ../src/guide/tutorial/using-yii-with-roadrunner.md ../src/guide/tutorial/using-yii-with-swoole.md ../src/guide/views/asset.md ../src/guide/views/view.md ../src/guide/views/widget.md +#, no-wrap +msgid "Installation" +msgstr "Instalação" + +#. type: Title # +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +#, no-wrap +msgid "Symfony Messenger integration guide" +msgstr "Guia de integração com o Symfony Messenger" + +#. type: Plain text +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +msgid "The [Symfony Messenger](https://symfony.com/doc/current/components/messenger.html) component helps applications send and receive messages to/from other applications or via message queues." +msgstr "O componente [Symfony Messenger](https://symfony.com/doc/current/components/messenger.html) ajuda as aplicações a enviar e receber mensagens de/para outras aplicações ou por meio de filas de mensagens." + +#. type: Fenced code block (shell) +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +#, no-wrap +msgid "composer require symfony/messenger\n" +msgstr "composer require symfony/messenger\n" + +#. type: Title ## +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +#, no-wrap +msgid "How to use with Yii" +msgstr "Como usar com o Yii" + +#. type: Title ### +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +#, no-wrap +msgid "1. Create a Message and Handler." +msgstr "1. Crie uma Message e um Handler." + +#. type: Fenced code block (php) +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +#, no-wrap +msgid "" +"namespace App\\Messages;\n" +"\n" +"final readonly class MyMessage\n" +"{\n" +" public function __construct(public string $content)\n" +" {\n" +" }\n" +"}\n" +msgstr "" +"namespace App\\Messages;\n" +"\n" +"final readonly class MyMessage\n" +"{\n" +" public function __construct(public string $content)\n" +" {\n" +" }\n" +"}\n" + +#. type: Fenced code block (php) +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +#, no-wrap +msgid "" +"namespace App\\Messages;\n" +"\n" +"use Psr\\Log\\LoggerInterface;\n" +"\n" +"final readonly class MyMessageHandler\n" +"{\n" +" public function __construct(private LoggerInterface $logger)\n" +" {\n" +" }\n" +" public function __invoke(MyMessage $message): void\n" +" {\n" +" // ...\n" +" $this->logger->info(\"The message with the content '$message->content' has been received.\");\n" +" }\n" +"}\n" +msgstr "" +"namespace App\\Messages;\n" +"\n" +"use Psr\\Log\\LoggerInterface;\n" +"\n" +"final readonly class MyMessageHandler\n" +"{\n" +" public function __construct(private LoggerInterface $logger)\n" +" {\n" +" }\n" +" public function __invoke(MyMessage $message): void\n" +" {\n" +" // ...\n" +" $this->logger->info(\"The message with the content '$message->content' has been received.\");\n" +" }\n" +"}\n" + +#. type: Title ### +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +#, no-wrap +msgid "2. Implement the ServiceProviderInterface." +msgstr "2. Implemente a ServiceProviderInterface." + +#. type: Plain text +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +msgid "This instance of the ServiceProviderInterface is used to configure certain Symfony Messenger commands." +msgstr "Essa instância da ServiceProviderInterface é usada para configurar alguns comandos do Symfony Messenger." + +#. type: Fenced code block (php) +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +#, no-wrap +msgid "" +"namespace App\\Services;\n" +"\n" +"use Psr\\Container\\ContainerInterface;\n" +"use Symfony\\Contracts\\Service\\ServiceProviderInterface;\n" +"\n" +"final readonly class ServiceProvider implements ServiceProviderInterface\n" +"{\n" +" /**\n" +" * @param ContainerInterface $container\n" +" * @param array $serviceMap\n" +" */\n" +" public function __construct(\n" +" private ContainerInterface $container,\n" +" private array $serviceMap)\n" +" {\n" +" }\n" +"\n" +" /**\n" +" * @inheritDoc\n" +" */\n" +" public function get(string $id): mixed\n" +" {\n" +" return $this->container->get($id);\n" +" }\n" +"\n" +" public function has(string $id): bool\n" +" {\n" +" return $this->container->has($id);\n" +" }\n" +"\n" +" /**\n" +" * @inheritDoc\n" +" */\n" +" public function getProvidedServices(): array\n" +" {\n" +" return $this->serviceMap;\n" +" }\n" +"}\n" +msgstr "" +"namespace App\\Services;\n" +"\n" +"use Psr\\Container\\ContainerInterface;\n" +"use Symfony\\Contracts\\Service\\ServiceProviderInterface;\n" +"\n" +"final readonly class ServiceProvider implements ServiceProviderInterface\n" +"{\n" +" /**\n" +" * @param ContainerInterface $container\n" +" * @param array $serviceMap\n" +" */\n" +" public function __construct(\n" +" private ContainerInterface $container,\n" +" private array $serviceMap)\n" +" {\n" +" }\n" +"\n" +" /**\n" +" * @inheritDoc\n" +" */\n" +" public function get(string $id): mixed\n" +" {\n" +" return $this->container->get($id);\n" +" }\n" +"\n" +" public function has(string $id): bool\n" +" {\n" +" return $this->container->has($id);\n" +" }\n" +"\n" +" /**\n" +" * @inheritDoc\n" +" */\n" +" public function getProvidedServices(): array\n" +" {\n" +" return $this->serviceMap;\n" +" }\n" +"}\n" + +#. type: Title ### +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +#, no-wrap +msgid "3. Configure the Symfony Messenger." +msgstr "3. Configure o Symfony Messenger." + +#. type: Plain text +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +msgid "Example uses the [symfony/doctrine-messenger](https://packagist.org/packages/symfony/doctrine-messenger) package for transport:" +msgstr "O exemplo usa o pacote [symfony/doctrine-messenger](https://packagist.org/packages/symfony/doctrine-messenger) como transporte:" + +#. type: Plain text +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +msgid "Add the Doctrine packages to the `composer.json`:" +msgstr "Adicione os pacotes do Doctrine ao `composer.json`:" + +#. type: Fenced code block (json) +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +#, no-wrap +msgid "" +"{\n" +" // ...\n" +" \"require\": {\n" +" // ...\n" +" \"doctrine/orm\": \"^3\",\n" +" \"doctrine/dbal\": \"^4\",\n" +" \"symfony/cache\": \"^7\"\n" +" },\n" +"}\n" +msgstr "" +"{\n" +" // ...\n" +" \"require\": {\n" +" // ...\n" +" \"doctrine/orm\": \"^3\",\n" +" \"doctrine/dbal\": \"^4\",\n" +" \"symfony/cache\": \"^7\"\n" +" },\n" +"}\n" + +#. type: Plain text +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +msgid "Install Doctrine:" +msgstr "Instale o Doctrine:" + +#. type: Fenced code block (shell) +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +#, no-wrap +msgid "composer install\n" +msgstr "composer install\n" + +#. type: Plain text +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +msgid "Configure the Doctrine connection in the `config/common/params.php`:" +msgstr "Configure a conexão do Doctrine em `config/common/params.php`:" + +#. type: Fenced code block (php) +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +#, no-wrap +msgid "" +"return [\n" +" // ...\n" +" 'doctrine' => [\n" +" 'paths' => [\n" +" ],\n" +" 'isDevMode' => false,\n" +" 'connection' => [\n" +" 'driver' => 'pdo_mysql',\n" +" 'user' => 'site1',\n" +" 'password' => 'secret',\n" +" 'dbname' => 'site3'\n" +" ]\n" +" ],\n" +"];\n" +msgstr "" +"return [\n" +" // ...\n" +" 'doctrine' => [\n" +" 'paths' => [\n" +" ],\n" +" 'isDevMode' => false,\n" +" 'connection' => [\n" +" 'driver' => 'pdo_mysql',\n" +" 'user' => 'site1',\n" +" 'password' => 'secret',\n" +" 'dbname' => 'site3'\n" +" ]\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +msgid "Install the Symfony Doctrine Messenger package:" +msgstr "Instale o pacote Symfony Doctrine Messenger:" + +#. type: Fenced code block (shell) +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +#, no-wrap +msgid "composer require symfony/doctrine-messenger\n" +msgstr "composer require symfony/doctrine-messenger\n" + +#. type: Plain text +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +msgid "Configure the Doctrine and Symfony Messenger dependencies in the `config/common/di/application.php`:" +msgstr "Configure as dependências do Doctrine e do Symfony Messenger em `config/common/di/application.php`:" + +#. type: Fenced code block (php) +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +#, no-wrap +msgid "" +"use App\\Messages\\MyMessage;\n" +"use App\\Messages\\MyMessageHandler;\n" +"use App\\Services\\ServiceProvider;\n" +"use Doctrine\\DBAL\\DriverManager;\n" +"use Doctrine\\ORM\\Configuration;\n" +"use Doctrine\\ORM\\EntityManager;\n" +"use Doctrine\\ORM\\EntityManagerInterface;\n" +"use Doctrine\\ORM\\ORMSetup;\n" +"use Doctrine\\ORM\\Proxy\\ProxyFactory;\n" +"use Doctrine\\ORM\\Tools\\Console\\EntityManagerProvider;\n" +"use Doctrine\\ORM\\Tools\\Console\\EntityManagerProvider\\SingleManagerProvider;\n" +"use Psr\\Cache\\CacheItemPoolInterface;\n" +"use Psr\\Container\\ContainerInterface;\n" +"use Psr\\Log\\LoggerInterface;\n" +"use Symfony\\Component\\Cache\\Adapter\\FilesystemAdapter;\n" +"use Symfony\\Component\\EventDispatcher\\EventDispatcher;\n" +"use Symfony\\Component\\EventDispatcher\\EventDispatcherInterface;\n" +"use Symfony\\Component\\Messenger\\Bridge\\Doctrine\\Transport\\Connection;\n" +"use Symfony\\Component\\Messenger\\Bridge\\Doctrine\\Transport\\DoctrineTransport;\n" +"use Symfony\\Component\\Messenger\\Command\\ConsumeMessagesCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\DebugCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\FailedMessagesRemoveCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\FailedMessagesRetryCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\FailedMessagesShowCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\SetupTransportsCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\StatsCommand;\n" +"use Symfony\\Component\\Messenger\\EventListener\\StopWorkerOnRestartSignalListener;\n" +"use Symfony\\Component\\Messenger\\Handler\\HandlersLocator;\n" +"use Symfony\\Component\\Messenger\\MessageBus;\n" +"use Symfony\\Component\\Messenger\\Middleware\\HandleMessageMiddleware;\n" +"use Symfony\\Component\\Messenger\\Middleware\\SendMessageMiddleware;\n" +"use Symfony\\Component\\Messenger\\RoutableMessageBus;\n" +"use Symfony\\Component\\Messenger\\Transport\\Sender\\SendersLocator;\n" +"use Symfony\\Component\\Messenger\\Transport\\Serialization\\PhpSerializer;\n" +"use Symfony\\Component\\Messenger\\Transport\\Serialization\\SerializerInterface;\n" +"use Symfony\\Contracts\\Service\\ServiceProviderInterface;\n" +"use Yiisoft\\Aliases\\Aliases;\n" +"use Yiisoft\\Definitions\\Reference;\n" +"\n" +"class_alias(MessageBus::class, 'MyMessageBus');\n" +"\n" +"return [\n" +" // ...\n" +" CacheItemPoolInterface::class => static function (ContainerInterface $container) {\n" +" return new FilesystemAdapter(directory: $container->get(Aliases::class)->get('@runtime'));\n" +" }, //One of the following adapters can be used instead: Psr16Adapter, RedisAdapter, MemcachedAdapter, DoctrineDbalAdapter, and so forth.\n" +"\n" +" Configuration::class => static function (ContainerInterface $container) use ($params) {\n" +" $config = ORMSetup::createAttributeMetadataConfiguration( // on PHP >= 8.4, use ORMSetup::createAttributeMetadataConfig()\n" +" paths: $params['doctrine']['paths'],\n" +" isDevMode: $params['doctrine']['isDevMode'],\n" +" cache: $container->get(CacheItemPoolInterface::class));\n" +" $config->setAutoGenerateProxyClasses(ProxyFactory::AUTOGENERATE_FILE_NOT_EXISTS_OR_CHANGED);\n" +" return $config;\n" +" },\n" +"\n" +" EntityManagerInterface::class => static function (ContainerInterface $container) use ($params) {\n" +" $configuration = $container->get(Configuration::class);\n" +" return new EntityManager(\n" +" DriverManager::getConnection(\n" +" $params['doctrine']['connection'],\n" +" $configuration\n" +" ),\n" +" $configuration);\n" +" },\n" +" EntityManagerProvider::class => SingleManagerProvider::class,\n" +"\n" +" SerializerInterface::class => PhpSerializer::class,\n" +" 'DoctrineTransport' => static function (ContainerInterface $container) use ($params) {\n" +" $configuration = $container->get(Configuration::class);\n" +" $connection = new Connection([], DriverManager::getConnection(\n" +" $params['doctrine']['connection'],\n" +" $configuration\n" +" ));\n" +" return new DoctrineTransport($connection, $container->get(SerializerInterface::class));\n" +" },\n" +"\n" +" MyMessageBus::class => static function (ContainerInterface $container) {\n" +" return new MyMessageBus([\n" +" new SendMessageMiddleware(sendersLocator: new SendersLocator([\n" +" MyMessage::class => ['DoctrineTransport']\n" +" ], $container)),\n" +" new HandleMessageMiddleware(new HandlersLocator([\n" +" MyMessage::class => [$container->get(MyMessageHandler::class)]\n" +" ])),\n" +" ]);\n" +" },\n" +"\n" +" EventDispatcherInterface::class => static function (ContainerInterface $container) {\n" +" $eventDispatcher = new EventDispatcher();\n" +" $eventDispatcher->addSubscriber($container->get(StopWorkerOnRestartSignalListener::class));\n" +" return $eventDispatcher;\n" +" },\n" +" ServiceProviderInterface::class => [\n" +" 'class' => ServiceProvider::class,\n" +" '__construct()' => [\n" +" 'container' => Reference::to(ContainerInterface::class),\n" +" 'serviceMap' => [\n" +" 'DoctrineTransport' => DoctrineTransport::class\n" +" ]\n" +" ],\n" +" ],\n" +"\n" +" ConsumeMessagesCommand::class => static function (ContainerInterface $container) {\n" +" return new ConsumeMessagesCommand(\n" +" $container->get(RoutableMessageBus::class),\n" +" $container,\n" +" $container->get(EventDispatcherInterface::class),\n" +" $container->get(LoggerInterface::class),\n" +" array_keys($container->get(ServiceProviderInterface::class)->getProvidedServices())\n" +" );\n" +" },\n" +" DebugCommand::class => [\n" +" '__construct()' => [\n" +" 'mapping' => [\n" +" MyMessageBus::class => [Reference::to(MyMessageHandler::class)]\n" +" ]\n" +" ],\n" +" ],\n" +" FailedMessagesRemoveCommand::class => [\n" +" '__construct()' => [\n" +" 'globalFailureReceiverName' => null,\n" +" 'failureTransports' => Reference::to(ServiceProviderInterface::class)\n" +" ],\n" +" ],\n" +" FailedMessagesRetryCommand::class => [\n" +" '__construct()' => [\n" +" 'globalReceiverName' => null,\n" +" 'failureTransports' => Reference::to(ServiceProviderInterface::class),\n" +" 'messageBus' => Reference::to(MyMessageBus::class),\n" +" 'eventDispatcher' => Reference::to(EventDispatcherInterface::class),\n" +" 'logger' => Reference::to(LoggerInterface::class),\n" +" ],\n" +" ],\n" +" FailedMessagesShowCommand::class => [\n" +" '__construct()' => [\n" +" 'globalFailureReceiverName' => null,\n" +" 'failureTransports' => Reference::to(ServiceProviderInterface::class)\n" +" ],\n" +" ],\n" +" SetupTransportsCommand::class => static function (ContainerInterface $container) {\n" +" return new SetupTransportsCommand(\n" +" $container,\n" +" array_keys($container->get(ServiceProviderInterface::class)->getProvidedServices())\n" +" );\n" +" },\n" +" StatsCommand::class => static function (ContainerInterface $container) {\n" +" return new StatsCommand(\n" +" $container,\n" +" array_keys($container->get(ServiceProviderInterface::class)->getProvidedServices())\n" +" );\n" +" },\n" +"];\n" +msgstr "" +"use App\\Messages\\MyMessage;\n" +"use App\\Messages\\MyMessageHandler;\n" +"use App\\Services\\ServiceProvider;\n" +"use Doctrine\\DBAL\\DriverManager;\n" +"use Doctrine\\ORM\\Configuration;\n" +"use Doctrine\\ORM\\EntityManager;\n" +"use Doctrine\\ORM\\EntityManagerInterface;\n" +"use Doctrine\\ORM\\ORMSetup;\n" +"use Doctrine\\ORM\\Proxy\\ProxyFactory;\n" +"use Doctrine\\ORM\\Tools\\Console\\EntityManagerProvider;\n" +"use Doctrine\\ORM\\Tools\\Console\\EntityManagerProvider\\SingleManagerProvider;\n" +"use Psr\\Cache\\CacheItemPoolInterface;\n" +"use Psr\\Container\\ContainerInterface;\n" +"use Psr\\Log\\LoggerInterface;\n" +"use Symfony\\Component\\Cache\\Adapter\\FilesystemAdapter;\n" +"use Symfony\\Component\\EventDispatcher\\EventDispatcher;\n" +"use Symfony\\Component\\EventDispatcher\\EventDispatcherInterface;\n" +"use Symfony\\Component\\Messenger\\Bridge\\Doctrine\\Transport\\Connection;\n" +"use Symfony\\Component\\Messenger\\Bridge\\Doctrine\\Transport\\DoctrineTransport;\n" +"use Symfony\\Component\\Messenger\\Command\\ConsumeMessagesCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\DebugCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\FailedMessagesRemoveCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\FailedMessagesRetryCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\FailedMessagesShowCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\SetupTransportsCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\StatsCommand;\n" +"use Symfony\\Component\\Messenger\\EventListener\\StopWorkerOnRestartSignalListener;\n" +"use Symfony\\Component\\Messenger\\Handler\\HandlersLocator;\n" +"use Symfony\\Component\\Messenger\\MessageBus;\n" +"use Symfony\\Component\\Messenger\\Middleware\\HandleMessageMiddleware;\n" +"use Symfony\\Component\\Messenger\\Middleware\\SendMessageMiddleware;\n" +"use Symfony\\Component\\Messenger\\RoutableMessageBus;\n" +"use Symfony\\Component\\Messenger\\Transport\\Sender\\SendersLocator;\n" +"use Symfony\\Component\\Messenger\\Transport\\Serialization\\PhpSerializer;\n" +"use Symfony\\Component\\Messenger\\Transport\\Serialization\\SerializerInterface;\n" +"use Symfony\\Contracts\\Service\\ServiceProviderInterface;\n" +"use Yiisoft\\Aliases\\Aliases;\n" +"use Yiisoft\\Definitions\\Reference;\n" +"\n" +"class_alias(MessageBus::class, 'MyMessageBus');\n" +"\n" +"return [\n" +" // ...\n" +" CacheItemPoolInterface::class => static function (ContainerInterface $container) {\n" +" return new FilesystemAdapter(directory: $container->get(Aliases::class)->get('@runtime'));\n" +" }, //One of the following adapters can be used instead: Psr16Adapter, RedisAdapter, MemcachedAdapter, DoctrineDbalAdapter, and so forth.\n" +"\n" +" Configuration::class => static function (ContainerInterface $container) use ($params) {\n" +" $config = ORMSetup::createAttributeMetadataConfiguration( // on PHP >= 8.4, use ORMSetup::createAttributeMetadataConfig()\n" +" paths: $params['doctrine']['paths'],\n" +" isDevMode: $params['doctrine']['isDevMode'],\n" +" cache: $container->get(CacheItemPoolInterface::class));\n" +" $config->setAutoGenerateProxyClasses(ProxyFactory::AUTOGENERATE_FILE_NOT_EXISTS_OR_CHANGED);\n" +" return $config;\n" +" },\n" +"\n" +" EntityManagerInterface::class => static function (ContainerInterface $container) use ($params) {\n" +" $configuration = $container->get(Configuration::class);\n" +" return new EntityManager(\n" +" DriverManager::getConnection(\n" +" $params['doctrine']['connection'],\n" +" $configuration\n" +" ),\n" +" $configuration);\n" +" },\n" +" EntityManagerProvider::class => SingleManagerProvider::class,\n" +"\n" +" SerializerInterface::class => PhpSerializer::class,\n" +" 'DoctrineTransport' => static function (ContainerInterface $container) use ($params) {\n" +" $configuration = $container->get(Configuration::class);\n" +" $connection = new Connection([], DriverManager::getConnection(\n" +" $params['doctrine']['connection'],\n" +" $configuration\n" +" ));\n" +" return new DoctrineTransport($connection, $container->get(SerializerInterface::class));\n" +" },\n" +"\n" +" MyMessageBus::class => static function (ContainerInterface $container) {\n" +" return new MyMessageBus([\n" +" new SendMessageMiddleware(sendersLocator: new SendersLocator([\n" +" MyMessage::class => ['DoctrineTransport']\n" +" ], $container)),\n" +" new HandleMessageMiddleware(new HandlersLocator([\n" +" MyMessage::class => [$container->get(MyMessageHandler::class)]\n" +" ])),\n" +" ]);\n" +" },\n" +"\n" +" EventDispatcherInterface::class => static function (ContainerInterface $container) {\n" +" $eventDispatcher = new EventDispatcher();\n" +" $eventDispatcher->addSubscriber($container->get(StopWorkerOnRestartSignalListener::class));\n" +" return $eventDispatcher;\n" +" },\n" +" ServiceProviderInterface::class => [\n" +" 'class' => ServiceProvider::class,\n" +" '__construct()' => [\n" +" 'container' => Reference::to(ContainerInterface::class),\n" +" 'serviceMap' => [\n" +" 'DoctrineTransport' => DoctrineTransport::class\n" +" ]\n" +" ],\n" +" ],\n" +"\n" +" ConsumeMessagesCommand::class => static function (ContainerInterface $container) {\n" +" return new ConsumeMessagesCommand(\n" +" $container->get(RoutableMessageBus::class),\n" +" $container,\n" +" $container->get(EventDispatcherInterface::class),\n" +" $container->get(LoggerInterface::class),\n" +" array_keys($container->get(ServiceProviderInterface::class)->getProvidedServices())\n" +" );\n" +" },\n" +" DebugCommand::class => [\n" +" '__construct()' => [\n" +" 'mapping' => [\n" +" MyMessageBus::class => [Reference::to(MyMessageHandler::class)]\n" +" ]\n" +" ],\n" +" ],\n" +" FailedMessagesRemoveCommand::class => [\n" +" '__construct()' => [\n" +" 'globalFailureReceiverName' => null,\n" +" 'failureTransports' => Reference::to(ServiceProviderInterface::class)\n" +" ],\n" +" ],\n" +" FailedMessagesRetryCommand::class => [\n" +" '__construct()' => [\n" +" 'globalReceiverName' => null,\n" +" 'failureTransports' => Reference::to(ServiceProviderInterface::class),\n" +" 'messageBus' => Reference::to(MyMessageBus::class),\n" +" 'eventDispatcher' => Reference::to(EventDispatcherInterface::class),\n" +" 'logger' => Reference::to(LoggerInterface::class),\n" +" ],\n" +" ],\n" +" FailedMessagesShowCommand::class => [\n" +" '__construct()' => [\n" +" 'globalFailureReceiverName' => null,\n" +" 'failureTransports' => Reference::to(ServiceProviderInterface::class)\n" +" ],\n" +" ],\n" +" SetupTransportsCommand::class => static function (ContainerInterface $container) {\n" +" return new SetupTransportsCommand(\n" +" $container,\n" +" array_keys($container->get(ServiceProviderInterface::class)->getProvidedServices())\n" +" );\n" +" },\n" +" StatsCommand::class => static function (ContainerInterface $container) {\n" +" return new StatsCommand(\n" +" $container,\n" +" array_keys($container->get(ServiceProviderInterface::class)->getProvidedServices())\n" +" );\n" +" },\n" +"];\n" + +#. type: Title ### +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +#, no-wrap +msgid "4. Integrate the Symfony Messenger commands into the Yii console." +msgstr "4. Integre os comandos do Symfony Messenger ao console do Yii." + +#. type: Plain text +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +msgid "Add the commands to `config/console/commands.php`:" +msgstr "Adicione os comandos em `config/console/commands.php`:" + +#. type: Fenced code block (php) +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +#, no-wrap +msgid "" +"use Symfony\\Component\\Messenger\\Command\\ConsumeMessagesCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\DebugCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\FailedMessagesRemoveCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\FailedMessagesRetryCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\FailedMessagesShowCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\SetupTransportsCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\StatsCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\StopWorkersCommand;\n" +"\n" +"return [\n" +" // ...\n" +" 'symfony:messenger:consume' => ConsumeMessagesCommand::class,\n" +" 'symfony:messenger:debug' => DebugCommand::class,\n" +" 'symfony:messenger:failed:remove' => FailedMessagesRemoveCommand::class,\n" +" 'symfony:messenger:failed:retry' => FailedMessagesRetryCommand::class,\n" +" 'symfony:messenger:failed:show' => FailedMessagesShowCommand::class,\n" +" 'symfony:messenger:setup-transports' => SetupTransportsCommand::class,\n" +" 'symfony:messenger:stats' => StatsCommand::class,\n" +" 'symfony:messenger:stop-workers' => StopWorkersCommand::class\n" +"];\n" +msgstr "" +"use Symfony\\Component\\Messenger\\Command\\ConsumeMessagesCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\DebugCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\FailedMessagesRemoveCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\FailedMessagesRetryCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\FailedMessagesShowCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\SetupTransportsCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\StatsCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\StopWorkersCommand;\n" +"\n" +"return [\n" +" // ...\n" +" 'symfony:messenger:consume' => ConsumeMessagesCommand::class,\n" +" 'symfony:messenger:debug' => DebugCommand::class,\n" +" 'symfony:messenger:failed:remove' => FailedMessagesRemoveCommand::class,\n" +" 'symfony:messenger:failed:retry' => FailedMessagesRetryCommand::class,\n" +" 'symfony:messenger:failed:show' => FailedMessagesShowCommand::class,\n" +" 'symfony:messenger:setup-transports' => SetupTransportsCommand::class,\n" +" 'symfony:messenger:stats' => StatsCommand::class,\n" +" 'symfony:messenger:stop-workers' => StopWorkersCommand::class\n" +"];\n" + +#. type: Title ### +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +#, no-wrap +msgid "5. Dispatch a message." +msgstr "5. Despache uma mensagem." + +#. type: Plain text +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +msgid "Example:" +msgstr "Exemplo:" + +#. type: Fenced code block (php) +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +#, no-wrap +msgid "" +"use App\\Messages\\MyMessage;\n" +"use MyMessageBus;\n" +"use Psr\\Http\\Message\\ResponseInterface;\n" +"\n" +"final readonly class MyController\n" +"{\n" +" public function __construct(private MyMessageBus $bus)\n" +" {\n" +" }\n" +" \n" +" public function sendMessage(): ResponseInterface\n" +" {\n" +" $this->bus->dispatch(new MyMessage('Hello Symfony Messenger!'));\n" +" // ...\n" +" }\n" +"}\n" +msgstr "" +"use App\\Messages\\MyMessage;\n" +"use MyMessageBus;\n" +"use Psr\\Http\\Message\\ResponseInterface;\n" +"\n" +"final readonly class MyController\n" +"{\n" +" public function __construct(private MyMessageBus $bus)\n" +" {\n" +" }\n" +" \n" +" public function sendMessage(): ResponseInterface\n" +" {\n" +" $this->bus->dispatch(new MyMessage('Hello Symfony Messenger!'));\n" +" // ...\n" +" }\n" +"}\n" + +#. type: Title ### +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +#, no-wrap +msgid "6. Consume messages." +msgstr "6. Consuma as mensagens." + +#. type: Fenced code block (bash) +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md +#, no-wrap +msgid "./yii symfony:messenger:consume DoctrineTransport --bus=MyMessageBus\n" +msgstr "./yii symfony:messenger:consume DoctrineTransport --bus=MyMessageBus\n" diff --git a/_translations/po/pt-BR/cookbook_third-party-integrations_symfony-scheduler-integration-guide.md.po b/_translations/po/pt-BR/cookbook_third-party-integrations_symfony-scheduler-integration-guide.md.po new file mode 100644 index 00000000..f61ae0a2 --- /dev/null +++ b/_translations/po/pt-BR/cookbook_third-party-integrations_symfony-scheduler-integration-guide.md.po @@ -0,0 +1,602 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-10-08 12:04+0000\n" +"PO-Revision-Date: 2026-10-08 12:04+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/making-http-requests.md ../src/cookbook/sentry-integration.md ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md ../src/guide/tutorial/using-yii-with-frankenphp.md ../src/guide/tutorial/using-yii-with-rapira.md ../src/guide/tutorial/using-yii-with-roadrunner.md ../src/guide/tutorial/using-yii-with-swoole.md ../src/guide/views/asset.md ../src/guide/views/view.md ../src/guide/views/widget.md +#, no-wrap +msgid "Installation" +msgstr "Instalação" + +#. type: Fenced code block (shell) +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md +#, no-wrap +msgid "composer require symfony/messenger\n" +msgstr "composer require symfony/messenger\n" + +#. type: Title ## +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md +#, no-wrap +msgid "How to use with Yii" +msgstr "Como usar com o Yii" + +#. type: Title ### +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md +#, no-wrap +msgid "1. Create a Message and Handler." +msgstr "1. Crie uma Message e um Handler." + +#. type: Fenced code block (php) +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md +#, no-wrap +msgid "" +"namespace App\\Messages;\n" +"\n" +"final readonly class MyMessage\n" +"{\n" +" public function __construct(public string $content)\n" +" {\n" +" }\n" +"}\n" +msgstr "" +"namespace App\\Messages;\n" +"\n" +"final readonly class MyMessage\n" +"{\n" +" public function __construct(public string $content)\n" +" {\n" +" }\n" +"}\n" + +#. type: Fenced code block (php) +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md +#, no-wrap +msgid "" +"namespace App\\Messages;\n" +"\n" +"use Psr\\Log\\LoggerInterface;\n" +"\n" +"final readonly class MyMessageHandler\n" +"{\n" +" public function __construct(private LoggerInterface $logger)\n" +" {\n" +" }\n" +" public function __invoke(MyMessage $message): void\n" +" {\n" +" // ...\n" +" $this->logger->info(\"The message with the content '$message->content' has been received.\");\n" +" }\n" +"}\n" +msgstr "" +"namespace App\\Messages;\n" +"\n" +"use Psr\\Log\\LoggerInterface;\n" +"\n" +"final readonly class MyMessageHandler\n" +"{\n" +" public function __construct(private LoggerInterface $logger)\n" +" {\n" +" }\n" +" public function __invoke(MyMessage $message): void\n" +" {\n" +" // ...\n" +" $this->logger->info(\"The message with the content '$message->content' has been received.\");\n" +" }\n" +"}\n" + +#. type: Fenced code block (php) +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md +#, no-wrap +msgid "" +"namespace App\\Services;\n" +"\n" +"use Psr\\Container\\ContainerInterface;\n" +"use Symfony\\Contracts\\Service\\ServiceProviderInterface;\n" +"\n" +"final readonly class ServiceProvider implements ServiceProviderInterface\n" +"{\n" +" /**\n" +" * @param ContainerInterface $container\n" +" * @param array $serviceMap\n" +" */\n" +" public function __construct(\n" +" private ContainerInterface $container,\n" +" private array $serviceMap)\n" +" {\n" +" }\n" +"\n" +" /**\n" +" * @inheritDoc\n" +" */\n" +" public function get(string $id): mixed\n" +" {\n" +" return $this->container->get($id);\n" +" }\n" +"\n" +" public function has(string $id): bool\n" +" {\n" +" return $this->container->has($id);\n" +" }\n" +"\n" +" /**\n" +" * @inheritDoc\n" +" */\n" +" public function getProvidedServices(): array\n" +" {\n" +" return $this->serviceMap;\n" +" }\n" +"}\n" +msgstr "" +"namespace App\\Services;\n" +"\n" +"use Psr\\Container\\ContainerInterface;\n" +"use Symfony\\Contracts\\Service\\ServiceProviderInterface;\n" +"\n" +"final readonly class ServiceProvider implements ServiceProviderInterface\n" +"{\n" +" /**\n" +" * @param ContainerInterface $container\n" +" * @param array $serviceMap\n" +" */\n" +" public function __construct(\n" +" private ContainerInterface $container,\n" +" private array $serviceMap)\n" +" {\n" +" }\n" +"\n" +" /**\n" +" * @inheritDoc\n" +" */\n" +" public function get(string $id): mixed\n" +" {\n" +" return $this->container->get($id);\n" +" }\n" +"\n" +" public function has(string $id): bool\n" +" {\n" +" return $this->container->has($id);\n" +" }\n" +"\n" +" /**\n" +" * @inheritDoc\n" +" */\n" +" public function getProvidedServices(): array\n" +" {\n" +" return $this->serviceMap;\n" +" }\n" +"}\n" + +#. type: Title ### +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md +#, no-wrap +msgid "4. Integrate the Symfony Messenger commands into the Yii console." +msgstr "4. Integre os comandos do Symfony Messenger ao console do Yii." + +#. type: Plain text +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md +msgid "Add the commands to `config/console/commands.php`:" +msgstr "Adicione os comandos em `config/console/commands.php`:" + +#. type: Fenced code block (php) +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md +#, no-wrap +msgid "" +"use Symfony\\Component\\Messenger\\Command\\ConsumeMessagesCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\DebugCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\FailedMessagesRemoveCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\FailedMessagesRetryCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\FailedMessagesShowCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\SetupTransportsCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\StatsCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\StopWorkersCommand;\n" +"\n" +"return [\n" +" // ...\n" +" 'symfony:messenger:consume' => ConsumeMessagesCommand::class,\n" +" 'symfony:messenger:debug' => DebugCommand::class,\n" +" 'symfony:messenger:failed:remove' => FailedMessagesRemoveCommand::class,\n" +" 'symfony:messenger:failed:retry' => FailedMessagesRetryCommand::class,\n" +" 'symfony:messenger:failed:show' => FailedMessagesShowCommand::class,\n" +" 'symfony:messenger:setup-transports' => SetupTransportsCommand::class,\n" +" 'symfony:messenger:stats' => StatsCommand::class,\n" +" 'symfony:messenger:stop-workers' => StopWorkersCommand::class\n" +"];\n" +msgstr "" +"use Symfony\\Component\\Messenger\\Command\\ConsumeMessagesCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\DebugCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\FailedMessagesRemoveCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\FailedMessagesRetryCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\FailedMessagesShowCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\SetupTransportsCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\StatsCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\StopWorkersCommand;\n" +"\n" +"return [\n" +" // ...\n" +" 'symfony:messenger:consume' => ConsumeMessagesCommand::class,\n" +" 'symfony:messenger:debug' => DebugCommand::class,\n" +" 'symfony:messenger:failed:remove' => FailedMessagesRemoveCommand::class,\n" +" 'symfony:messenger:failed:retry' => FailedMessagesRetryCommand::class,\n" +" 'symfony:messenger:failed:show' => FailedMessagesShowCommand::class,\n" +" 'symfony:messenger:setup-transports' => SetupTransportsCommand::class,\n" +" 'symfony:messenger:stats' => StatsCommand::class,\n" +" 'symfony:messenger:stop-workers' => StopWorkersCommand::class\n" +"];\n" + +#. type: Plain text +#: ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md +msgid "Example:" +msgstr "Exemplo:" + +#. type: Title # +#: ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md +#, no-wrap +msgid "Symfony Scheduler integration guide" +msgstr "Guia de integração com o Symfony Scheduler" + +#. type: Plain text +#: ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md +msgid "The [Symfony Scheduler](https://symfony.com/doc/current/scheduler.html) component manages task scheduling within your PHP application, like running a task each night at 3 AM, every two weeks except for holidays or any other custom schedule you might need." +msgstr "O componente [Symfony Scheduler](https://symfony.com/doc/current/scheduler.html) gerencia o agendamento de tarefas na sua aplicação PHP, como rodar uma tarefa toda noite às 3h, a cada duas semanas exceto em feriados, ou qualquer outro agendamento personalizado de que você precise." + +#. type: Fenced code block (shell) +#: ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md +#, no-wrap +msgid "composer require symfony/scheduler\n" +msgstr "composer require symfony/scheduler\n" + +#. type: Title ### +#: ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md +#, no-wrap +msgid "2. Attaching Recurring Messages to a Schedule." +msgstr "2. Associe mensagens recorrentes a um Schedule." + +#. type: Fenced code block (php) +#: ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md +#, no-wrap +msgid "" +"namespace App\\Scheduler;\n" +"\n" +"use App\\Messages\\MyMessage;\n" +"use Symfony\\Component\\Scheduler\\RecurringMessage;\n" +"use Symfony\\Component\\Scheduler\\Schedule;\n" +"use Symfony\\Component\\Scheduler\\ScheduleProviderInterface;\n" +"\n" +"class MyScheduleProvider implements ScheduleProviderInterface\n" +"{\n" +" public function getSchedule(): Schedule\n" +" {\n" +" return (new Schedule())\n" +" ->with(\n" +" RecurringMessage::every(\n" +" '10 seconds',\n" +" new MyMessage('Hello Symfony Scheduler!'))\n" +" );\n" +" }\n" +"}\n" +msgstr "" +"namespace App\\Scheduler;\n" +"\n" +"use App\\Messages\\MyMessage;\n" +"use Symfony\\Component\\Scheduler\\RecurringMessage;\n" +"use Symfony\\Component\\Scheduler\\Schedule;\n" +"use Symfony\\Component\\Scheduler\\ScheduleProviderInterface;\n" +"\n" +"class MyScheduleProvider implements ScheduleProviderInterface\n" +"{\n" +" public function getSchedule(): Schedule\n" +" {\n" +" return (new Schedule())\n" +" ->with(\n" +" RecurringMessage::every(\n" +" '10 seconds',\n" +" new MyMessage('Hello Symfony Scheduler!'))\n" +" );\n" +" }\n" +"}\n" + +#. type: Title ### +#: ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md +#, no-wrap +msgid "3. Configure the Symfony Scheduler." +msgstr "3. Configure o Symfony Scheduler." + +#. type: Plain text +#: ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md +msgid "Depending on your needs, the Symfony Scheduler component offers two ways to consume messages: using the `messenger:consume` command or [creating a worker programmatically](https://symfony.com/doc/current/scheduler.html#creating-a-consumer-programmatically). The example uses the [symfony/messenger](https://packagist.org/packages/symfony/messenger) package to consume messages." +msgstr "Dependendo das suas necessidades, o componente Symfony Scheduler oferece duas formas de consumir mensagens: usando o comando `messenger:consume` ou [criando um worker programaticamente](https://symfony.com/doc/current/scheduler.html#creating-a-consumer-programmatically). O exemplo usa o pacote [symfony/messenger](https://packagist.org/packages/symfony/messenger) para consumir as mensagens." + +#. type: Plain text +#: ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md +msgid "Install the Symfony Messenger package:" +msgstr "Instale o pacote Symfony Messenger:" + +#. type: Plain text +#: ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md +msgid "Install the Symfony Cache package:" +msgstr "Instale o pacote Symfony Cache:" + +#. type: Fenced code block (shell) +#: ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md +#, no-wrap +msgid "composer require symfony/cache\n" +msgstr "composer require symfony/cache\n" + +#. type: Plain text +#: ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md +msgid "Implement the ServiceProviderInterface. This instance of the ServiceProviderInterface is used to configure certain Symfony Messenger commands." +msgstr "Implemente a ServiceProviderInterface. Essa instância da ServiceProviderInterface é usada para configurar alguns comandos do Symfony Messenger." + +#. type: Plain text +#: ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md +msgid "Configure the Symfony Scheduler and Symfony Messenger dependencies in the `config/common/di/application.php`:" +msgstr "Configure as dependências do Symfony Scheduler e do Symfony Messenger em `config/common/di/application.php`:" + +#. type: Fenced code block (php) +#: ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md +#, no-wrap +msgid "" +"use App\\Messages\\MyMessage;\n" +"use App\\Messages\\MyMessageHandler;\n" +"use App\\Scheduler\\MyScheduleProvider;\n" +"use App\\Services\\ServiceProvider;\n" +"use Psr\\Cache\\CacheItemPoolInterface;\n" +"use Psr\\Container\\ContainerInterface;\n" +"use Psr\\EventDispatcher\\EventDispatcherInterface;\n" +"use Psr\\Log\\LoggerInterface;\n" +"use Symfony\\Component\\Cache\\Adapter\\FilesystemAdapter;\n" +"use Symfony\\Component\\EventDispatcher\\EventDispatcher;\n" +"use Symfony\\Component\\Messenger\\Command\\ConsumeMessagesCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\DebugCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\FailedMessagesRemoveCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\FailedMessagesRetryCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\FailedMessagesShowCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\SetupTransportsCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\StatsCommand;\n" +"use Symfony\\Component\\Messenger\\EventListener\\StopWorkerOnRestartSignalListener;\n" +"use Symfony\\Component\\Messenger\\Handler\\HandlersLocator;\n" +"use Symfony\\Component\\Messenger\\MessageBus;\n" +"use Symfony\\Component\\Messenger\\Middleware\\HandleMessageMiddleware;\n" +"use Symfony\\Component\\Messenger\\RoutableMessageBus;\n" +"use Symfony\\Component\\Scheduler\\Generator\\MessageGenerator;\n" +"use Symfony\\Component\\Scheduler\\Messenger\\SchedulerTransport;\n" +"use Symfony\\Contracts\\Service\\ServiceProviderInterface;\n" +"use Yiisoft\\Aliases\\Aliases;\n" +"use Yiisoft\\Definitions\\Reference;\n" +"\n" +"class_alias(MessageBus::class, 'MyMessageBus');\n" +"\n" +"return [\n" +" // ...\n" +" CacheItemPoolInterface::class => static function (ContainerInterface $container) {\n" +" return new FilesystemAdapter(directory: $container->get(Aliases::class)->get('@runtime'));\n" +" }, //One of the following adapters can be used instead: Psr16Adapter, RedisAdapter, MemcachedAdapter, DoctrineDbalAdapter, and so forth.\n" +"\n" +"\n" +" 'SchedulerTransport' => static function () {\n" +" return new SchedulerTransport(\n" +" new MessageGenerator(\n" +" new MyScheduleProvider(),\n" +" 'MySchedule'\n" +" )\n" +" );\n" +" },\n" +"\n" +" MyMessageBus::class => static function (ContainerInterface $container) {\n" +" return new MyMessageBus([\n" +" new HandleMessageMiddleware(new HandlersLocator([\n" +" MyMessage::class => [$container->get(MyMessageHandler::class)]\n" +" ])),\n" +" ]);\n" +" },\n" +"\n" +" EventDispatcherInterface::class => static function (ContainerInterface $container) {\n" +" $eventDispatcher = new EventDispatcher();\n" +" $eventDispatcher->addSubscriber($container->get(StopWorkerOnRestartSignalListener::class));\n" +" return $eventDispatcher;\n" +" },\n" +" ServiceProviderInterface::class => [\n" +" 'class' => ServiceProvider::class,\n" +" '__construct()' => [\n" +" 'container' => Reference::to(ContainerInterface::class),\n" +" 'serviceMap' => [\n" +" 'SchedulerTransport' => SchedulerTransport::class\n" +" ]\n" +" ],\n" +" ],\n" +"\n" +" ConsumeMessagesCommand::class => static function (ContainerInterface $container) {\n" +" return new ConsumeMessagesCommand(\n" +" $container->get(RoutableMessageBus::class),\n" +" $container,\n" +" $container->get(EventDispatcherInterface::class),\n" +" $container->get(LoggerInterface::class),\n" +" array_keys($container->get(ServiceProviderInterface::class)->getProvidedServices())\n" +" );\n" +" },\n" +" DebugCommand::class => [\n" +" '__construct()' => [\n" +" 'mapping' => [\n" +" MyMessageBus::class => [Reference::to(MyMessageHandler::class)]\n" +" ]\n" +" ],\n" +" ],\n" +" FailedMessagesRemoveCommand::class => [\n" +" '__construct()' => [\n" +" 'globalFailureReceiverName' => null,\n" +" 'failureTransports' => Reference::to(ServiceProviderInterface::class)\n" +" ],\n" +" ],\n" +" FailedMessagesRetryCommand::class => [\n" +" '__construct()' => [\n" +" 'globalReceiverName' => null,\n" +" 'failureTransports' => Reference::to(ServiceProviderInterface::class),\n" +" 'messageBus' => Reference::to(MyMessageBus::class),\n" +" 'eventDispatcher' => Reference::to(EventDispatcherInterface::class),\n" +" 'logger' => Reference::to(LoggerInterface::class),\n" +" ],\n" +" ],\n" +" FailedMessagesShowCommand::class => [\n" +" '__construct()' => [\n" +" 'globalFailureReceiverName' => null,\n" +" 'failureTransports' => Reference::to(ServiceProviderInterface::class)\n" +" ],\n" +" ],\n" +" SetupTransportsCommand::class => static function (ContainerInterface $container) {\n" +" return new SetupTransportsCommand(\n" +" $container,\n" +" array_keys($container->get(ServiceProviderInterface::class)->getProvidedServices())\n" +" );\n" +" },\n" +" StatsCommand::class => static function (ContainerInterface $container) {\n" +" return new StatsCommand(\n" +" $container,\n" +" array_keys($container->get(ServiceProviderInterface::class)->getProvidedServices())\n" +" );\n" +" },\n" +"];\n" +msgstr "" +"use App\\Messages\\MyMessage;\n" +"use App\\Messages\\MyMessageHandler;\n" +"use App\\Scheduler\\MyScheduleProvider;\n" +"use App\\Services\\ServiceProvider;\n" +"use Psr\\Cache\\CacheItemPoolInterface;\n" +"use Psr\\Container\\ContainerInterface;\n" +"use Psr\\EventDispatcher\\EventDispatcherInterface;\n" +"use Psr\\Log\\LoggerInterface;\n" +"use Symfony\\Component\\Cache\\Adapter\\FilesystemAdapter;\n" +"use Symfony\\Component\\EventDispatcher\\EventDispatcher;\n" +"use Symfony\\Component\\Messenger\\Command\\ConsumeMessagesCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\DebugCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\FailedMessagesRemoveCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\FailedMessagesRetryCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\FailedMessagesShowCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\SetupTransportsCommand;\n" +"use Symfony\\Component\\Messenger\\Command\\StatsCommand;\n" +"use Symfony\\Component\\Messenger\\EventListener\\StopWorkerOnRestartSignalListener;\n" +"use Symfony\\Component\\Messenger\\Handler\\HandlersLocator;\n" +"use Symfony\\Component\\Messenger\\MessageBus;\n" +"use Symfony\\Component\\Messenger\\Middleware\\HandleMessageMiddleware;\n" +"use Symfony\\Component\\Messenger\\RoutableMessageBus;\n" +"use Symfony\\Component\\Scheduler\\Generator\\MessageGenerator;\n" +"use Symfony\\Component\\Scheduler\\Messenger\\SchedulerTransport;\n" +"use Symfony\\Contracts\\Service\\ServiceProviderInterface;\n" +"use Yiisoft\\Aliases\\Aliases;\n" +"use Yiisoft\\Definitions\\Reference;\n" +"\n" +"class_alias(MessageBus::class, 'MyMessageBus');\n" +"\n" +"return [\n" +" // ...\n" +" CacheItemPoolInterface::class => static function (ContainerInterface $container) {\n" +" return new FilesystemAdapter(directory: $container->get(Aliases::class)->get('@runtime'));\n" +" }, //One of the following adapters can be used instead: Psr16Adapter, RedisAdapter, MemcachedAdapter, DoctrineDbalAdapter, and so forth.\n" +"\n" +"\n" +" 'SchedulerTransport' => static function () {\n" +" return new SchedulerTransport(\n" +" new MessageGenerator(\n" +" new MyScheduleProvider(),\n" +" 'MySchedule'\n" +" )\n" +" );\n" +" },\n" +"\n" +" MyMessageBus::class => static function (ContainerInterface $container) {\n" +" return new MyMessageBus([\n" +" new HandleMessageMiddleware(new HandlersLocator([\n" +" MyMessage::class => [$container->get(MyMessageHandler::class)]\n" +" ])),\n" +" ]);\n" +" },\n" +"\n" +" EventDispatcherInterface::class => static function (ContainerInterface $container) {\n" +" $eventDispatcher = new EventDispatcher();\n" +" $eventDispatcher->addSubscriber($container->get(StopWorkerOnRestartSignalListener::class));\n" +" return $eventDispatcher;\n" +" },\n" +" ServiceProviderInterface::class => [\n" +" 'class' => ServiceProvider::class,\n" +" '__construct()' => [\n" +" 'container' => Reference::to(ContainerInterface::class),\n" +" 'serviceMap' => [\n" +" 'SchedulerTransport' => SchedulerTransport::class\n" +" ]\n" +" ],\n" +" ],\n" +"\n" +" ConsumeMessagesCommand::class => static function (ContainerInterface $container) {\n" +" return new ConsumeMessagesCommand(\n" +" $container->get(RoutableMessageBus::class),\n" +" $container,\n" +" $container->get(EventDispatcherInterface::class),\n" +" $container->get(LoggerInterface::class),\n" +" array_keys($container->get(ServiceProviderInterface::class)->getProvidedServices())\n" +" );\n" +" },\n" +" DebugCommand::class => [\n" +" '__construct()' => [\n" +" 'mapping' => [\n" +" MyMessageBus::class => [Reference::to(MyMessageHandler::class)]\n" +" ]\n" +" ],\n" +" ],\n" +" FailedMessagesRemoveCommand::class => [\n" +" '__construct()' => [\n" +" 'globalFailureReceiverName' => null,\n" +" 'failureTransports' => Reference::to(ServiceProviderInterface::class)\n" +" ],\n" +" ],\n" +" FailedMessagesRetryCommand::class => [\n" +" '__construct()' => [\n" +" 'globalReceiverName' => null,\n" +" 'failureTransports' => Reference::to(ServiceProviderInterface::class),\n" +" 'messageBus' => Reference::to(MyMessageBus::class),\n" +" 'eventDispatcher' => Reference::to(EventDispatcherInterface::class),\n" +" 'logger' => Reference::to(LoggerInterface::class),\n" +" ],\n" +" ],\n" +" FailedMessagesShowCommand::class => [\n" +" '__construct()' => [\n" +" 'globalFailureReceiverName' => null,\n" +" 'failureTransports' => Reference::to(ServiceProviderInterface::class)\n" +" ],\n" +" ],\n" +" SetupTransportsCommand::class => static function (ContainerInterface $container) {\n" +" return new SetupTransportsCommand(\n" +" $container,\n" +" array_keys($container->get(ServiceProviderInterface::class)->getProvidedServices())\n" +" );\n" +" },\n" +" StatsCommand::class => static function (ContainerInterface $container) {\n" +" return new StatsCommand(\n" +" $container,\n" +" array_keys($container->get(ServiceProviderInterface::class)->getProvidedServices())\n" +" );\n" +" },\n" +"];\n" + +#. type: Title ### +#: ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md +#, no-wrap +msgid "5. Consume messages." +msgstr "5. Consuma as mensagens." + +#. type: Fenced code block (bash) +#: ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md +#, no-wrap +msgid "./yii symfony:messenger:consume SchedulerTransport --bus=MyMessageBus\n" +msgstr "./yii symfony:messenger:consume SchedulerTransport --bus=MyMessageBus\n" diff --git a/_translations/po/pt-BR/cookbook_using-htmx-for-partial-reloads.md.po b/_translations/po/pt-BR/cookbook_using-htmx-for-partial-reloads.md.po new file mode 100644 index 00000000..369fe9fa --- /dev/null +++ b/_translations/po/pt-BR/cookbook_using-htmx-for-partial-reloads.md.po @@ -0,0 +1,808 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-05-09 10:43+0000\n" +"PO-Revision-Date: 2026-05-09 10:43+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/cookbook/using-htmx-for-partial-reloads.md +#, no-wrap +msgid "Using htmx for partial page reloads" +msgstr "Usando htmx para recarregar partes da página" + +#. type: Plain text +#: ../src/cookbook/using-htmx-for-partial-reloads.md +#, no-wrap +msgid "" +"[htmx](https://htmx.org/) lets links and forms request HTML fragments and swap them into the current page. In a Yii\n" +"application, this works well for grids: sorting, filtering, and pagination can update only the grid while the rest of\n" +"the page stays in place.\n" +msgstr "" +"O [htmx](https://htmx.org/) permite que links e formulários requisitem fragmentos de HTML e os troquem na página atual. Em uma\n" +"aplicação Yii, isso funciona bem para grids: ordenação, filtros e paginação podem atualizar só o grid enquanto o resto\n" +"da página continua no lugar.\n" + +#. type: Plain text +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "This recipe uses `GridView` as an example because it has links and forms that naturally benefit from partial reloads. The same pattern works for any widget or page fragment: render the fragment separately, add htmx attributes to the controls that should refresh it, and return only that fragment for htmx requests." +msgstr "Esta receita usa o `GridView` como exemplo porque ele tem links e formulários que se beneficiam naturalmente de recargas parciais. O mesmo padrão funciona para qualquer widget ou fragmento de página: renderize o fragmento separadamente, adicione atributos do htmx aos controles que devem atualizá-lo e retorne apenas esse fragmento nas requisições do htmx." + +#. type: Title ## +#: ../src/cookbook/using-htmx-for-partial-reloads.md +#, no-wrap +msgid "Install GridView" +msgstr "Instale o GridView" + +#. type: Plain text +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "Install the data view package if the application doesn't use it yet:" +msgstr "Instale o pacote de data view, se a aplicação ainda não o usa:" + +#. type: Fenced code block (shell) +#: ../src/cookbook/using-htmx-for-partial-reloads.md +#, no-wrap +msgid "composer require yiisoft/yii-dataview\n" +msgstr "composer require yiisoft/yii-dataview\n" + +#. type: Title ## +#: ../src/cookbook/using-htmx-for-partial-reloads.md +#, no-wrap +msgid "Load htmx" +msgstr "Carregue o htmx" + +#. type: Plain text +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "The simplest setup is loading htmx from a CDN. Create `src/Web/Shared/Layout/Main/HtmxAsset.php`:" +msgstr "A configuração mais simples é carregar o htmx de uma CDN. Crie `src/Web/Shared/Layout/Main/HtmxAsset.php`:" + +#. type: Fenced code block (php) +#: ../src/cookbook/using-htmx-for-partial-reloads.md +#, no-wrap +msgid "" +" 'sha384-H5SrcfygHmAuTDZphMHqBJLc3FhssKjG7w/CeCpFReSfwBWDTKpkzPP8c+cLsK+V',\n" +" 'crossorigin' => 'anonymous',\n" +" ];\n" +"}\n" +msgstr "" +" 'sha384-H5SrcfygHmAuTDZphMHqBJLc3FhssKjG7w/CeCpFReSfwBWDTKpkzPP8c+cLsK+V',\n" +" 'crossorigin' => 'anonymous',\n" +" ];\n" +"}\n" + +#. type: Plain text +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "When updating the htmx version, update the URL and `integrity` value together." +msgstr "Ao atualizar a versão do htmx, atualize a URL e o valor de `integrity` juntos." + +#. type: Plain text +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "For production applications, consider serving htmx from your application assets to avoid depending on a third-party CDN. Download `htmx.min.js` into `assets/main/js/htmx.min.js` and use a local asset bundle:" +msgstr "Em aplicações de produção, considere servir o htmx a partir dos assets da sua aplicação para não depender de uma CDN de terceiros. Baixe o `htmx.min.js` para `assets/main/js/htmx.min.js` e use um asset bundle local:" + +#. type: Fenced code block (php) +#: ../src/cookbook/using-htmx-for-partial-reloads.md +#, no-wrap +msgid "" +" */\n" +" $pagination = OffsetPagination::widget();\n" +"\n" +" return GridView::widget()\n" +" ->containerAttributes([\n" +" 'id' => 'UsersGridView',\n" +" 'class' => 'mt-4 position-relative',\n" +" ])\n" +" ->dataReader($this->dataReader())\n" +" ->pageSizeConstraint(5)\n" +" ->paginationWidget($pagination)\n" +" ->columns(\n" +" new DataColumn('id', header: 'ID', filter: true),\n" +" new DataColumn('login', header: 'Login', filter: true),\n" +" new DataColumn('name', header: 'Name', filter: true),\n" +" new DataColumn('status', header: 'Status', filter: true),\n" +" )\n" +" ->render();\n" +" }\n" +"\n" +" private function dataReader(): IterableDataReader\n" +" {\n" +" return new IterableDataReader([\n" +" ['id' => 1, 'login' => 'admin', 'name' => 'Alice Adams', 'status' => 'Active'],\n" +" ['id' => 2, 'login' => 'editor', 'name' => 'Eve Editor', 'status' => 'Active'],\n" +" ['id' => 3, 'login' => 'author', 'name' => 'Arthur Author', 'status' => 'Active'],\n" +" ['id' => 4, 'login' => 'reviewer', 'name' => 'Rita Reviewer', 'status' => 'Inactive'],\n" +" ['id' => 5, 'login' => 'support', 'name' => 'Sam Support', 'status' => 'Active'],\n" +" ['id' => 6, 'login' => 'guest', 'name' => 'Grace Guest', 'status' => 'Inactive'],\n" +" ]);\n" +" }\n" +"}\n" +msgstr "" +" */\n" +" $pagination = OffsetPagination::widget();\n" +"\n" +" return GridView::widget()\n" +" ->containerAttributes([\n" +" 'id' => 'UsersGridView',\n" +" 'class' => 'mt-4 position-relative',\n" +" ])\n" +" ->dataReader($this->dataReader())\n" +" ->pageSizeConstraint(5)\n" +" ->paginationWidget($pagination)\n" +" ->columns(\n" +" new DataColumn('id', header: 'ID', filter: true),\n" +" new DataColumn('login', header: 'Login', filter: true),\n" +" new DataColumn('name', header: 'Name', filter: true),\n" +" new DataColumn('status', header: 'Status', filter: true),\n" +" )\n" +" ->render();\n" +" }\n" +"\n" +" private function dataReader(): IterableDataReader\n" +" {\n" +" return new IterableDataReader([\n" +" ['id' => 1, 'login' => 'admin', 'name' => 'Alice Adams', 'status' => 'Active'],\n" +" ['id' => 2, 'login' => 'editor', 'name' => 'Eve Editor', 'status' => 'Active'],\n" +" ['id' => 3, 'login' => 'author', 'name' => 'Arthur Author', 'status' => 'Active'],\n" +" ['id' => 4, 'login' => 'reviewer', 'name' => 'Rita Reviewer', 'status' => 'Inactive'],\n" +" ['id' => 5, 'login' => 'support', 'name' => 'Sam Support', 'status' => 'Active'],\n" +" ['id' => 6, 'login' => 'guest', 'name' => 'Grace Guest', 'status' => 'Inactive'],\n" +" ]);\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "For a real application, replace `dataReader()` with a reader backed by a database query or repository. Keep the widget responsible for rendering the grid fragment." +msgstr "Em uma aplicação real, substitua `dataReader()` por um reader baseado em uma consulta ao banco de dados ou em um repositório. Mantenha o widget responsável por renderizar o fragmento do grid." + +#. type: Plain text +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "Create `src/Web/Users/Index/template.php`:" +msgstr "Crie `src/Web/Users/Index/template.php`:" + +#. type: Fenced code block (php) +#: ../src/cookbook/using-htmx-for-partial-reloads.md +#, no-wrap +msgid "" +"setTitle('Users');\n" +"?>\n" +"

Users

\n" +"\n" +"\n" +msgstr "" +"setTitle('Users');\n" +"?>\n" +"

Users

\n" +"\n" +"\n" + +#. type: Plain text +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "Create `src/Web/Users/Index/Action.php`:" +msgstr "Crie `src/Web/Users/Index/Action.php`:" + +#. type: Fenced code block (php) +#: ../src/cookbook/using-htmx-for-partial-reloads.md +#, no-wrap +msgid "" +"viewRenderer->render(__DIR__ . '/template');\n" +" }\n" +"}\n" +msgstr "" +"viewRenderer->render(__DIR__ . '/template');\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "Add the action to `config/common/routes.php`:" +msgstr "Adicione a action em `config/common/routes.php`:" + +#. type: Fenced code block (php) +#: ../src/cookbook/using-htmx-for-partial-reloads.md +#, no-wrap +msgid "" +"routes(\n" +" Route::get('/')\n" +" ->action(Web\\HomePage\\Action::class)\n" +" ->name('home'),\n" +" Route::get('/users')\n" +" ->action(Web\\Users\\Index\\Action::class)\n" +" ->name('users/index'),\n" +" ),\n" +"];\n" +msgstr "" +"routes(\n" +" Route::get('/')\n" +" ->action(Web\\HomePage\\Action::class)\n" +" ->name('home'),\n" +" Route::get('/users')\n" +" ->action(Web\\Users\\Index\\Action::class)\n" +" ->name('users/index'),\n" +" ),\n" +"];\n" + +#. type: Plain text +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "Open `/users` and make sure sorting, filtering, and pagination work with full page reloads first." +msgstr "Abra `/users` e verifique primeiro se a ordenação, os filtros e a paginação funcionam com recarga completa da página." + +#. type: Title ## +#: ../src/cookbook/using-htmx-for-partial-reloads.md +#, no-wrap +msgid "Add htmx attributes to the grid" +msgstr "Adicione atributos do htmx ao grid" + +#. type: Plain text +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "Now update `UsersGrid` so the grid controls request a fragment and swap it into `#UsersGridView`:" +msgstr "Agora atualize o `UsersGrid` para que os controles do grid requisitem um fragmento e o troquem em `#UsersGridView`:" + +#. type: Fenced code block (php) +#: ../src/cookbook/using-htmx-for-partial-reloads.md +#, no-wrap +msgid "" +" '#UsersGridView',\n" +" 'hx-target' => '#UsersGridView',\n" +" 'hx-replace-url' => 'true',\n" +" 'hx-swap' => 'outerHTML',\n" +" ];\n" +"\n" +" /** @var PaginationWidgetInterface */\n" +" $pagination = OffsetPagination::widget()->addLinkAttributes([\n" +" 'hx-boost' => 'true',\n" +" ...$htmxLoadAttributes,\n" +" ]);\n" +"\n" +" return GridView::widget()\n" +" ->containerAttributes([\n" +" 'id' => 'UsersGridView',\n" +" 'class' => 'mt-4 position-relative',\n" +" ])\n" +" ->dataReader($this->dataReader())\n" +" ->pageSizeConstraint(5)\n" +" ->sortableLinkAttributes([\n" +" 'hx-boost' => 'true',\n" +" ...$htmxLoadAttributes,\n" +" ])\n" +" ->filterFormAttributes([\n" +" 'hx-boost' => 'true',\n" +" ...$htmxLoadAttributes,\n" +" ])\n" +" ->paginationWidget($pagination)\n" +" ->columns(\n" +" new DataColumn('id', header: 'ID', filter: true),\n" +" new DataColumn('login', header: 'Login', filter: true),\n" +" new DataColumn('name', header: 'Name', filter: true),\n" +" new DataColumn('status', header: 'Status', filter: true),\n" +" )\n" +" ->render();\n" +" }\n" +"\n" +" private function dataReader(): IterableDataReader\n" +" {\n" +" return new IterableDataReader([\n" +" ['id' => 1, 'login' => 'admin', 'name' => 'Alice Adams', 'status' => 'Active'],\n" +" ['id' => 2, 'login' => 'editor', 'name' => 'Eve Editor', 'status' => 'Active'],\n" +" ['id' => 3, 'login' => 'author', 'name' => 'Arthur Author', 'status' => 'Active'],\n" +" ['id' => 4, 'login' => 'reviewer', 'name' => 'Rita Reviewer', 'status' => 'Inactive'],\n" +" ['id' => 5, 'login' => 'support', 'name' => 'Sam Support', 'status' => 'Active'],\n" +" ['id' => 6, 'login' => 'guest', 'name' => 'Grace Guest', 'status' => 'Inactive'],\n" +" ]);\n" +" }\n" +"}\n" +msgstr "" +" '#UsersGridView',\n" +" 'hx-target' => '#UsersGridView',\n" +" 'hx-replace-url' => 'true',\n" +" 'hx-swap' => 'outerHTML',\n" +" ];\n" +"\n" +" /** @var PaginationWidgetInterface */\n" +" $pagination = OffsetPagination::widget()->addLinkAttributes([\n" +" 'hx-boost' => 'true',\n" +" ...$htmxLoadAttributes,\n" +" ]);\n" +"\n" +" return GridView::widget()\n" +" ->containerAttributes([\n" +" 'id' => 'UsersGridView',\n" +" 'class' => 'mt-4 position-relative',\n" +" ])\n" +" ->dataReader($this->dataReader())\n" +" ->pageSizeConstraint(5)\n" +" ->sortableLinkAttributes([\n" +" 'hx-boost' => 'true',\n" +" ...$htmxLoadAttributes,\n" +" ])\n" +" ->filterFormAttributes([\n" +" 'hx-boost' => 'true',\n" +" ...$htmxLoadAttributes,\n" +" ])\n" +" ->paginationWidget($pagination)\n" +" ->columns(\n" +" new DataColumn('id', header: 'ID', filter: true),\n" +" new DataColumn('login', header: 'Login', filter: true),\n" +" new DataColumn('name', header: 'Name', filter: true),\n" +" new DataColumn('status', header: 'Status', filter: true),\n" +" )\n" +" ->render();\n" +" }\n" +"\n" +" private function dataReader(): IterableDataReader\n" +" {\n" +" return new IterableDataReader([\n" +" ['id' => 1, 'login' => 'admin', 'name' => 'Alice Adams', 'status' => 'Active'],\n" +" ['id' => 2, 'login' => 'editor', 'name' => 'Eve Editor', 'status' => 'Active'],\n" +" ['id' => 3, 'login' => 'author', 'name' => 'Arthur Author', 'status' => 'Active'],\n" +" ['id' => 4, 'login' => 'reviewer', 'name' => 'Rita Reviewer', 'status' => 'Inactive'],\n" +" ['id' => 5, 'login' => 'support', 'name' => 'Sam Support', 'status' => 'Active'],\n" +" ['id' => 6, 'login' => 'guest', 'name' => 'Grace Guest', 'status' => 'Inactive'],\n" +" ]);\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "The important part is the shared `$htmxLoadAttributes` array:" +msgstr "A parte importante é o array compartilhado `$htmxLoadAttributes`:" + +#. type: Bullet: '- ' +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "`hx-boost=\"true\"` makes the grid links and filter form send htmx requests." +msgstr "`hx-boost=\"true\"` faz os links e o formulário de filtro do grid enviarem requisições htmx." + +#. type: Bullet: '- ' +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "`hx-target=\"#UsersGridView\"` tells htmx which element to replace." +msgstr "`hx-target=\"#UsersGridView\"` diz ao htmx qual elemento substituir." + +#. type: Bullet: '- ' +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "`hx-swap=\"outerHTML\"` replaces the whole grid container with the response." +msgstr "`hx-swap=\"outerHTML\"` substitui todo o container do grid pela resposta." + +#. type: Bullet: '- ' +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "`hx-replace-url=\"true\"` keeps the browser URL in sync with the current sort, filter, and page." +msgstr "`hx-replace-url=\"true\"` mantém a URL do navegador sincronizada com a ordenação, o filtro e a página atuais." + +#. type: Bullet: '- ' +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "`hx-indicator=\"#UsersGridView\"` marks the grid as the loading indicator element while the request is active." +msgstr "`hx-indicator=\"#UsersGridView\"` marca o grid como o elemento indicador de carregamento enquanto a requisição está ativa." + +#. type: Plain text +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "The target selector and the container `id` must match. In this example, both use `UsersGridView`." +msgstr "O seletor de destino e o `id` do container precisam coincidir. Neste exemplo, ambos usam `UsersGridView`." + +#. type: Title ## +#: ../src/cookbook/using-htmx-for-partial-reloads.md +#, no-wrap +msgid "Return partial HTML for htmx requests" +msgstr "Retorne HTML parcial para requisições do htmx" + +#. type: Plain text +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "htmx sends the `HX-Request` header with its requests." +msgstr "O htmx envia o header `HX-Request` nas suas requisições." + +#. type: Plain text +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "In the action, return only the widget when the header is present:" +msgstr "Na action, retorne apenas o widget quando o header estiver presente:" + +#. type: Fenced code block (php) +#: ../src/cookbook/using-htmx-for-partial-reloads.md +#, no-wrap +msgid "" +"getHeaderLine('HX-Request') === 'true'\n" +" ? $this->htmlResponseFactory->createResponse(UsersGrid::widget())\n" +" : $this->viewRenderer->render(__DIR__ . '/template');\n" +"\n" +" return $response->withAddedHeader('Vary', 'HX-Request');\n" +" }\n" +"}\n" +msgstr "" +"getHeaderLine('HX-Request') === 'true'\n" +" ? $this->htmlResponseFactory->createResponse(UsersGrid::widget())\n" +" : $this->viewRenderer->render(__DIR__ . '/template');\n" +"\n" +" return $response->withAddedHeader('Vary', 'HX-Request');\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "The `Vary` header matters when a browser, proxy, or CDN caches responses. The same URL can return a full page without `HX-Request` and a fragment with `HX-Request: true`, so caches must keep these responses separate." +msgstr "O header `Vary` importa quando um navegador, proxy ou CDN faz cache das respostas. A mesma URL pode retornar uma página completa sem `HX-Request` e um fragmento com `HX-Request: true`, então os caches precisam manter essas respostas separadas." + +#. type: Title ## +#: ../src/cookbook/using-htmx-for-partial-reloads.md +#, no-wrap +msgid "Try it" +msgstr "Experimente" + +#. type: Plain text +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "Open the list page and use sorting, filtering, or pagination. The browser URL should change, and only the grid HTML should be replaced." +msgstr "Abra a página da lista e use a ordenação, os filtros ou a paginação. A URL do navegador deve mudar, e apenas o HTML do grid deve ser substituído." + +#. type: Plain text +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "In the browser developer tools, the htmx requests should include the `HX-Request` header. Their responses should contain only the grid container." +msgstr "Nas ferramentas de desenvolvedor do navegador, as requisições do htmx devem incluir o header `HX-Request`. As respostas devem conter apenas o container do grid." + +#. type: Plain text +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "Use the same pattern for other widgets or page fragments:" +msgstr "Use o mesmo padrão para outros widgets ou fragmentos de página:" + +#. type: Bullet: '1. ' +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "Put the reloadable HTML into a widget or another small renderer." +msgstr "Coloque o HTML recarregável em um widget ou em outro pequeno renderizador." + +#. type: Bullet: '2. ' +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "Add htmx attributes to the links and forms that should refresh it." +msgstr "Adicione atributos do htmx aos links e formulários que devem atualizá-lo." + +#. type: Bullet: '3. ' +#: ../src/cookbook/using-htmx-for-partial-reloads.md +msgid "Return the fragment for htmx requests and the full page for regular requests." +msgstr "Retorne o fragmento para requisições do htmx e a página completa para requisições comuns." diff --git a/_translations/po/pt-BR/cookbook_using-yii-in-third-party-apps.md.po b/_translations/po/pt-BR/cookbook_using-yii-in-third-party-apps.md.po new file mode 100644 index 00000000..58cee2cf --- /dev/null +++ b/_translations/po/pt-BR/cookbook_using-yii-in-third-party-apps.md.po @@ -0,0 +1,359 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-06-05 22:11+0000\n" +"PO-Revision-Date: 2026-06-05 22:11+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Fenced code block (sh) +#: ../src/cookbook/custom-migration-template.md ../src/cookbook/using-yii-in-third-party-apps.md ../src/guide/structure/designing-packages.md ../src/guide/structure/module.md ../src/guide/structure/package.md ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "composer yii-config-rebuild\n" +msgstr "composer yii-config-rebuild\n" + +#. type: Title # +#: ../src/cookbook/using-yii-in-third-party-apps.md +#, no-wrap +msgid "Using Yii in third-party applications" +msgstr "Usando o Yii em aplicações de terceiros" + +#. type: Plain text +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "Sometimes a project already has an entry point owned by another framework, CMS, or legacy application, but you still want to reuse Yii services: configuration, DI definitions, domain services, logging, mailers, database connections, or console-oriented application code." +msgstr "Às vezes um projeto já tem um ponto de entrada controlado por outro framework, CMS ou aplicação legada, mas você ainda quer reaproveitar serviços do Yii: configuração, definições de DI, serviços de domínio, logs, mailers, conexões com banco de dados ou código de aplicação voltado ao console." + +#. type: Plain text +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "Yii3 has no global application singleton. Bootstrap the Yii container explicitly and pass the services you need to the third-party code." +msgstr "O Yii3 não tem um singleton global de aplicação. Inicialize o container do Yii explicitamente e passe os serviços de que você precisa ao código de terceiros." + +#. type: Title ## +#: ../src/cookbook/using-yii-in-third-party-apps.md +#, no-wrap +msgid "Bootstrap the Yii container" +msgstr "Inicialize o container do Yii" + +#. type: Plain text +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "Create a small adapter in the host application, for example `bootstrap-yii-services.php`:" +msgstr "Crie um pequeno adaptador na aplicação hospedeira, por exemplo `bootstrap-yii-services.php`:" + +#. type: Fenced code block (php) +#: ../src/cookbook/using-yii-in-third-party-apps.md +#, no-wrap +msgid "" +"withValidate(Environment::appDebug())\n" +" ->withDefinitions(array_merge(\n" +" $config->get('di-console'),\n" +" [ConfigInterface::class => $config],\n" +" ))\n" +" ->withProviders($config->get('di-providers-console'))\n" +" ->withDelegates($config->get('di-delegates-console'));\n" +"\n" +" if ($config->has('di-tags-console')) {\n" +" $containerConfig = $containerConfig->withTags($config->get('di-tags-console'));\n" +" }\n" +"\n" +" $container = new Container($containerConfig);\n" +"\n" +" foreach ($config->get('bootstrap-console') as $callback) {\n" +" if (!is_callable($callback)) {\n" +" throw new RuntimeException(sprintf(\n" +" 'Bootstrap callback must be callable, \"%s\" given.',\n" +" get_debug_type($callback),\n" +" ));\n" +" }\n" +"\n" +" $callback($container);\n" +" }\n" +"\n" +" return $container;\n" +"}\n" +msgstr "" +"withValidate(Environment::appDebug())\n" +" ->withDefinitions(array_merge(\n" +" $config->get('di-console'),\n" +" [ConfigInterface::class => $config],\n" +" ))\n" +" ->withProviders($config->get('di-providers-console'))\n" +" ->withDelegates($config->get('di-delegates-console'));\n" +"\n" +" if ($config->has('di-tags-console')) {\n" +" $containerConfig = $containerConfig->withTags($config->get('di-tags-console'));\n" +" }\n" +"\n" +" $container = new Container($containerConfig);\n" +"\n" +" foreach ($config->get('bootstrap-console') as $callback) {\n" +" if (!is_callable($callback)) {\n" +" throw new RuntimeException(sprintf(\n" +" 'Bootstrap callback must be callable, \"%s\" given.',\n" +" get_debug_type($callback),\n" +" ));\n" +" }\n" +"\n" +" $callback($container);\n" +" }\n" +"\n" +" return $container;\n" +"}\n" + +#. type: Plain text +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "The adapter builds only the Yii configuration and DI container, then runs the configured bootstrap callbacks. It does not create or run a Yii application runner, so the third-party application keeps ownership of the entry point and process lifecycle." +msgstr "O adaptador monta apenas a configuração e o container de DI do Yii e depois executa os callbacks de bootstrap configurados. Ele não cria nem executa um runner de aplicação do Yii, então a aplicação de terceiros continua dona do ponto de entrada e do ciclo de vida do processo." + +#. type: Plain text +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "Use console configuration groups when you need common services and console-safe services. Use web groups instead only when you intentionally need web-specific definitions from the `di-web` group, such as PSR-17 HTTP factories or web middleware dependencies." +msgstr "Use os grupos de configuração de console quando precisar de serviços comuns e serviços seguros para o console. Use os grupos web apenas quando precisar intencionalmente de definições específicas da web do grupo `di-web`, como as factories HTTP da PSR-17 ou dependências de middlewares web." + +#. type: Title ## +#: ../src/cookbook/using-yii-in-third-party-apps.md +#, no-wrap +msgid "Get Yii services from the host application" +msgstr "Obtenha serviços do Yii a partir da aplicação hospedeira" + +#. type: Plain text +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "Use the adapter from the third-party application:" +msgstr "Use o adaptador a partir da aplicação de terceiros:" + +#. type: Fenced code block (php) +#: ../src/cookbook/using-yii-in-third-party-apps.md +#, no-wrap +msgid "" +"get(ApplicationParams::class);\n" +"\n" +"echo $params->name;\n" +msgstr "" +"get(ApplicationParams::class);\n" +"\n" +"echo $params->name;\n" + +#. type: Plain text +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "In real integrations, prefer getting your own application services instead of framework infrastructure. For example, expose `InvoiceSender`, `ReportBuilder`, or `CatalogImporter` from Yii and call that service from the host application." +msgstr "Em integrações reais, prefira obter os serviços da sua própria aplicação em vez da infraestrutura do framework. Por exemplo, exponha `InvoiceSender`, `ReportBuilder` ou `CatalogImporter` a partir do Yii e chame esse serviço na aplicação hospedeira." + +#. type: Title ## +#: ../src/cookbook/using-yii-in-third-party-apps.md +#, no-wrap +msgid "Keep boundaries explicit" +msgstr "Mantenha os limites explícitos" + +#. type: Plain text +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "Avoid mixing request lifecycles. Let the host application continue to own its HTTP request and response. Let Yii provide services that do not assume Yii is handling the current request." +msgstr "Evite misturar ciclos de vida de requisição. Deixe a aplicação hospedeira continuar dona da requisição e da resposta HTTP. Deixe o Yii fornecer serviços que não pressupõem que o Yii está tratando a requisição atual." + +#. type: Plain text +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "Good candidates for reuse:" +msgstr "Bons candidatos para reaproveitamento:" + +#. type: Bullet: '- ' +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "domain services;" +msgstr "serviços de domínio;" + +#. type: Bullet: '- ' +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "repositories and database connections;" +msgstr "repositórios e conexões com banco de dados;" + +#. type: Bullet: '- ' +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "mailers and notification services;" +msgstr "mailers e serviços de notificação;" + +#. type: Bullet: '- ' +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "loggers;" +msgstr "loggers;" + +#. type: Bullet: '- ' +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "validators;" +msgstr "validadores;" + +#. type: Bullet: '- ' +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "queue producers;" +msgstr "produtores de fila;" + +#. type: Bullet: '- ' +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "command-like application services." +msgstr "serviços de aplicação no estilo de comandos." + +#. type: Plain text +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "Avoid pulling in Yii actions, middleware stacks, sessions, CSRF middleware, or view rendering unless the host application explicitly delegates that whole responsibility to Yii." +msgstr "Evite trazer actions, pilhas de middlewares, sessões, middleware de CSRF ou renderização de views do Yii, a menos que a aplicação hospedeira delegue explicitamente essa responsabilidade inteira ao Yii." + +#. type: Title ## +#: ../src/cookbook/using-yii-in-third-party-apps.md +#, no-wrap +msgid "Configuration groups" +msgstr "Grupos de configuração" + +#. type: Plain text +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "The default application template separates configuration by group:" +msgstr "O template de aplicação padrão separa a configuração por grupo:" + +#. type: Bullet: '- ' +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "`di` is shared by web and console entry points;" +msgstr "`di` é compartilhado pelos pontos de entrada web e de console;" + +#. type: Bullet: '- ' +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "`di-console` is console-specific and includes `di` in the template;" +msgstr "`di-console` é específico do console e inclui `di` no template;" + +#. type: Bullet: '- ' +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "`di-web` is web-specific and includes `di`;" +msgstr "`di-web` é específico da web e inclui `di`;" + +#. type: Bullet: '- ' +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "`params-console` and `params-web` extend common `params`." +msgstr "`params-console` e `params-web` estendem o `params` comum." + +#. type: Plain text +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "Choose the smallest group that contains the services you need. If the host application only needs domain services, keep those definitions in `config/common/di/*.php` so both Yii and the third-party app can use them without web-only dependencies." +msgstr "Escolha o menor grupo que contém os serviços de que você precisa. Se a aplicação hospedeira só precisa de serviços de domínio, mantenha essas definições em `config/common/di/*.php` para que tanto o Yii quanto a aplicação de terceiros possam usá-las sem dependências exclusivas da web." + +#. type: Plain text +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "After changing `config/configuration.php`, rebuild the merge plan:" +msgstr "Depois de alterar `config/configuration.php`, reconstrua o merge plan:" + +#. type: Title ## +#: ../src/cookbook/using-yii-in-third-party-apps.md +#, no-wrap +msgid "Error handling and logging" +msgstr "Tratamento de erros e logs" + +#. type: Plain text +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "The host application should remain responsible for top-level error handling. Catch exceptions at the integration boundary when the host app needs to convert them into its own response or error format." +msgstr "A aplicação hospedeira deve continuar responsável pelo tratamento de erros de nível mais alto. Capture as exceções na fronteira da integração quando a aplicação hospedeira precisar convertê-las na sua própria resposta ou formato de erro." + +#. type: Plain text +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "Yii services can still use `Psr\\Log\\LoggerInterface`. Configure the Yii logger to write to the same destination as the host application or bridge both applications to the same PSR-3 logger." +msgstr "Os serviços do Yii ainda podem usar `Psr\\Log\\LoggerInterface`. Configure o logger do Yii para gravar no mesmo destino da aplicação hospedeira ou conecte as duas aplicações ao mesmo logger PSR-3." + +#. type: Title ## +#: ../src/cookbook/using-yii-in-third-party-apps.md +#, no-wrap +msgid "Long-running host processes" +msgstr "Processos hospedeiros de longa duração" + +#. type: Plain text +#: ../src/cookbook/using-yii-in-third-party-apps.md +msgid "If the third-party application is a worker, daemon, or event-loop server, avoid mutable shared state in services. Yii services resolved from the container are shared by default, so design them as stateless services or create a fresh container for each isolated job when stateful dependencies are unavoidable." +msgstr "Se a aplicação de terceiros for um worker, um daemon ou um servidor com event loop, evite estado mutável compartilhado nos serviços. Os serviços do Yii obtidos do container são compartilhados por padrão, então projete-os como serviços sem estado ou crie um container novo para cada job isolado quando dependências com estado forem inevitáveis." diff --git a/_translations/po/pt-BR/cookbook_working-on-windows.md.po b/_translations/po/pt-BR/cookbook_working-on-windows.md.po new file mode 100644 index 00000000..fd630d34 --- /dev/null +++ b/_translations/po/pt-BR/cookbook_working-on-windows.md.po @@ -0,0 +1,170 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-05-05 22:18+0000\n" +"PO-Revision-Date: 2026-05-05 22:18+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/cookbook/working-on-windows.md +#, no-wrap +msgid "Working on Windows" +msgstr "Trabalhando no Windows" + +#. type: Plain text +#: ../src/cookbook/working-on-windows.md +msgid "Yii applications usually run on Linux in production. On Windows, choose a local workflow that stays close to that environment and keeps filesystem performance predictable." +msgstr "Aplicações Yii geralmente rodam no Linux em produção. No Windows, escolha um fluxo de trabalho local que fique próximo desse ambiente e mantenha o desempenho do sistema de arquivos previsível." + +#. type: Title ## +#: ../src/cookbook/working-on-windows.md +#, no-wrap +msgid "Recommended setup: WSL" +msgstr "Configuração recomendada: WSL" + +#. type: Plain text +#: ../src/cookbook/working-on-windows.md +msgid "Use [Windows Subsystem for Linux](https://learn.microsoft.com/windows/wsl/) with a Linux distribution such as Ubuntu. Install PHP, Composer, Git, and Make inside WSL, then clone the project into the Linux filesystem:" +msgstr "Use o [Windows Subsystem for Linux](https://learn.microsoft.com/windows/wsl/) com uma distribuição Linux como o Ubuntu. Instale PHP, Composer, Git e Make dentro do WSL e depois clone o projeto no sistema de arquivos do Linux:" + +#. type: Fenced code block (shell) +#: ../src/cookbook/working-on-windows.md +#, no-wrap +msgid "" +"cd ~\n" +"git clone https://github.com/yiisoft/app.git my-app\n" +"cd my-app\n" +"composer install\n" +msgstr "" +"cd ~\n" +"git clone https://github.com/yiisoft/app.git my-app\n" +"cd my-app\n" +"composer install\n" + +#. type: Plain text +#: ../src/cookbook/working-on-windows.md +msgid "Keep the project under the WSL filesystem, for example `/home/user/projects/my-app`. Avoid working from a mounted Windows path such as `/mnt/c/Users/user/projects/my-app`; it is much slower for Composer, tests, and tools that read many small files." +msgstr "Mantenha o projeto no sistema de arquivos do WSL, por exemplo `/home/user/projects/my-app`. Evite trabalhar a partir de um caminho montado do Windows, como `/mnt/c/Users/user/projects/my-app`; ele é muito mais lento para o Composer, os testes e as ferramentas que leem muitos arquivos pequenos." + +#. type: Plain text +#: ../src/cookbook/working-on-windows.md +msgid "You can open the project from Windows editors through the WSL integration. In PhpStorm, open the project from the WSL filesystem. In VS Code, use the WSL extension and open the folder from inside the WSL session." +msgstr "Você pode abrir o projeto em editores do Windows por meio da integração com o WSL. No PhpStorm, abra o projeto a partir do sistema de arquivos do WSL. No VS Code, use a extensão WSL e abra a pasta de dentro da sessão do WSL." + +#. type: Title ## +#: ../src/cookbook/working-on-windows.md +#, no-wrap +msgid "Docker with WSL" +msgstr "Docker com WSL" + +#. type: Plain text +#: ../src/cookbook/working-on-windows.md +msgid "Docker Desktop with the WSL backend is also a good Windows setup. Keep the project in the WSL filesystem and run Docker commands from WSL:" +msgstr "O Docker Desktop com o backend WSL também é uma boa configuração no Windows. Mantenha o projeto no sistema de arquivos do WSL e rode os comandos do Docker a partir do WSL:" + +#. type: Fenced code block (shell) +#: ../src/cookbook/working-on-windows.md +#, no-wrap +msgid "" +"make build\n" +"make up\n" +"make yii\n" +"make test\n" +msgstr "" +"make build\n" +"make up\n" +"make yii\n" +"make test\n" + +#. type: Plain text +#: ../src/cookbook/working-on-windows.md +msgid "This keeps bind mounts fast and gives containers Linux paths that match the tooling used by the Yii application templates." +msgstr "Isso mantém os bind mounts rápidos e dá aos containers caminhos Linux que batem com as ferramentas usadas pelos templates de aplicação do Yii." + +#. type: Plain text +#: ../src/cookbook/working-on-windows.md +msgid "If you need IDE links from debug stack traces, set `APP_HOST_PATH` to the project path that your IDE can open." +msgstr "Se você precisar de links para a IDE nos stack traces de debug, defina `APP_HOST_PATH` com o caminho do projeto que a sua IDE consegue abrir." + +#. type: Title ## +#: ../src/cookbook/working-on-windows.md +#, no-wrap +msgid "Git Bash" +msgstr "Git Bash" + +#. type: Plain text +#: ../src/cookbook/working-on-windows.md +msgid "[Git for Windows](https://git-scm.com/downloads/win) installs Git Bash and common Unix tools. It can be enough when you want to run the application directly on Windows without WSL or Docker." +msgstr "O [Git for Windows](https://git-scm.com/downloads/win) instala o Git Bash e ferramentas Unix comuns. Ele pode bastar quando você quer rodar a aplicação diretamente no Windows, sem WSL nem Docker." + +#. type: Plain text +#: ../src/cookbook/working-on-windows.md +msgid "Use this option when your project does not depend on Linux-only extensions or shell scripts. Check the same commands you expect contributors to use:" +msgstr "Use esta opção quando o seu projeto não depende de extensões ou scripts de shell exclusivos do Linux. Teste os mesmos comandos que você espera que os contribuidores usem:" + +#. type: Fenced code block (shell) +#: ../src/cookbook/working-on-windows.md +#, no-wrap +msgid "" +"composer install\n" +"composer test\n" +msgstr "" +"composer install\n" +"composer test\n" + +#. type: Plain text +#: ../src/cookbook/working-on-windows.md +msgid "If the project uses `make`, Git for Windows includes a Bash environment, but `make` availability depends on your local installation. Install it separately when needed." +msgstr "Se o projeto usa `make`, o Git for Windows inclui um ambiente Bash, mas a disponibilidade do `make` depende da sua instalação local. Instale-o separadamente quando necessário." + +#. type: Title ## +#: ../src/cookbook/working-on-windows.md +#, no-wrap +msgid "PowerShell and CMD" +msgstr "PowerShell e CMD" + +#. type: Plain text +#: ../src/cookbook/working-on-windows.md +msgid "PowerShell and CMD can run PHP and Composer, but they differ from the common Linux server environment in quoting, environment variables, paths, and shell utilities. Use them for simple commands only." +msgstr "O PowerShell e o CMD conseguem rodar PHP e Composer, mas diferem do ambiente comum de servidores Linux em aspas, variáveis de ambiente, caminhos e utilitários de shell. Use-os apenas para comandos simples." + +#. type: Plain text +#: ../src/cookbook/working-on-windows.md +msgid "For regular Yii development on Windows, prefer WSL or Docker with WSL." +msgstr "Para o desenvolvimento regular com Yii no Windows, prefira o WSL ou o Docker com WSL." + +#. type: Title ## +#: ../src/cookbook/working-on-windows.md +#, no-wrap +msgid "Choosing a workflow" +msgstr "Escolhendo um fluxo de trabalho" + +#. type: Plain text +#: ../src/cookbook/working-on-windows.md +msgid "Use WSL when you want the closest local match to a Linux server and do not need containers for every service." +msgstr "Use o WSL quando quiser o ambiente local mais parecido com um servidor Linux e não precisar de containers para cada serviço." + +#. type: Plain text +#: ../src/cookbook/working-on-windows.md +msgid "Use Docker with WSL when you want the application, database, and other services described by Compose files." +msgstr "Use o Docker com WSL quando quiser a aplicação, o banco de dados e outros serviços descritos em arquivos do Compose." + +#. type: Plain text +#: ../src/cookbook/working-on-windows.md +msgid "Use Git Bash for small projects or quick checks that run directly on Windows." +msgstr "Use o Git Bash para projetos pequenos ou verificações rápidas que rodam diretamente no Windows." + +#. type: Plain text +#: ../src/cookbook/working-on-windows.md +msgid "Use PowerShell or CMD when the command is known to be platform-neutral." +msgstr "Use o PowerShell ou o CMD quando se sabe que o comando é independente de plataforma." diff --git a/_translations/po/pt-BR/guide_caching_data.md.po b/_translations/po/pt-BR/guide_caching_data.md.po new file mode 100644 index 00000000..ebd7f56b --- /dev/null +++ b/_translations/po/pt-BR/guide_caching_data.md.po @@ -0,0 +1,383 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-09-11 10:15+0500\n" +"PO-Revision-Date: 2025-09-11 10:15+0500\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../../guide/en/caching/data.md +#, no-wrap +msgid "Data caching" +msgstr "Cache de dados" + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "Data caching is about storing some PHP variables in a cache and retrieving them later from the cache. It's also the foundation for more advanced caching features, such as page caching." +msgstr "O cache de dados consiste em guardar algumas variáveis PHP no cache e recuperá-las dele mais tarde. Ele também é a base para recursos de cache mais avançados, como o cache de páginas." + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "To use cache, install [yiisoft/cache](https://github.com/yiisoft/cache) package:" +msgstr "Para usar o cache, instale o pacote [yiisoft/cache](https://github.com/yiisoft/cache):" + +#. type: Fenced code block (shell) +#: ../../guide/en/caching/data.md +#, no-wrap +msgid "composer require yiisoft/cache\n" +msgstr "composer require yiisoft/cache\n" + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "The following code is a typical usage pattern of data caching, where `$cache` refers to a `Cache` instance from the package:" +msgstr "O código a seguir é um padrão típico de uso do cache de dados, em que `$cache` se refere a uma instância de `Cache` do pacote:" + +#. type: Fenced code block (php) +#: ../../guide/en/caching/data.md +#, no-wrap +msgid "" +"public function getTopProducts(\\Yiisoft\\Cache\\CacheInterface $cache): array\n" +"{\n" +" $key = ['top-products', $count = 10];\n" +" \n" +" // Try retrieving $data from cache.\n" +" $data = $cache->getOrSet($key, function (\\Psr\\SimpleCache\\CacheInterface $cache) use ($count) {\n" +" // Can't find $data in a cache, calculate it from scratch.\n" +" return getTopProductsFromDatabase($count);\n" +" }, 3600);\n" +" \n" +" return $data;\n" +"}\n" +msgstr "" +"public function getTopProducts(\\Yiisoft\\Cache\\CacheInterface $cache): array\n" +"{\n" +" $key = ['top-products', $count = 10];\n" +" \n" +" // Tenta recuperar $data do cache.\n" +" $data = $cache->getOrSet($key, function (\\Psr\\SimpleCache\\CacheInterface $cache) use ($count) {\n" +" // $data não está no cache, então calcula do zero.\n" +" return getTopProductsFromDatabase($count);\n" +" }, 3600);\n" +" \n" +" return $data;\n" +"}\n" + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "When cache has data associated with the `$key`, it returns the cached value. Otherwise, it executes the passed anonymous function to calculate the value to cache and return." +msgstr "Quando o cache tem dados associados à `$key`, ele retorna o valor em cache. Caso contrário, executa a função anônima passada para calcular o valor a ser guardado no cache e retornado." + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "If the anonymous function requires some data from the outer scope, you can pass it with the `use` statement." +msgstr "Se a função anônima precisar de dados do escopo externo, você pode passá-los com a instrução `use`." + +#. type: Title ## +#: ../../guide/en/caching/data.md +#, no-wrap +msgid "Cache handlers" +msgstr "Drivers de cache" + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "The cache service uses [PSR-16](https://www.php-fig.org/psr/psr-16/) compatible cache handlers which represent various cache storages, such as memory, files, and databases." +msgstr "O serviço de cache usa drivers de cache compatíveis com a [PSR-16](https://www.php-fig.org/psr/psr-16/), que representam vários tipos de armazenamento, como memória, arquivos e bancos de dados." + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "Yii provides the following handlers:" +msgstr "O Yii fornece os seguintes drivers:" + +#. type: Bullet: '- ' +#: ../../guide/en/caching/data.md +msgid "`NullCache` — a cache placeholder which does no real caching. The purpose of this handler is to simplify the code that needs to check the availability of cache. For example, during development or if the server doesn't have actual cache support, you may configure a cache service to use this handler. When you enable actual cache support, you can switch to using the corresponding cache handler. In both cases, you may use the same code without extra checks." +msgstr "`NullCache` — um substituto de cache que não faz cache de verdade. O objetivo desse driver é simplificar o código que precisa verificar se há cache disponível. Por exemplo, durante o desenvolvimento ou se o servidor não tiver suporte real a cache, você pode configurar o serviço de cache para usar esse driver. Quando você habilitar o suporte real a cache, pode trocar para o driver correspondente. Nos dois casos, você pode usar o mesmo código, sem verificações extras." + +#. type: Bullet: '- ' +#: ../../guide/en/caching/data.md +msgid "`ArrayCache` — provides caching for the current request only by storing the values in an array." +msgstr "`ArrayCache` — faz cache apenas durante a requisição atual, guardando os valores em um array." + +#. type: Bullet: '- ' +#: ../../guide/en/caching/data.md +msgid "[APCu](https://github.com/yiisoft/cache-apcu) - uses a PHP [APC](https://www.php.net/manual/en/book.apcu.php) extension. You can consider this option as the fastest one when dealing with cache for a centralized thick application (e.g., one server, no dedicated load balancers, etc.)." +msgstr "[APCu](https://github.com/yiisoft/cache-apcu) - usa a extensão [APC](https://www.php.net/manual/en/book.apcu.php) do PHP. Você pode considerar esta a opção mais rápida ao lidar com cache em uma aplicação centralizada e robusta (por exemplo, um servidor, sem load balancers dedicados etc.)." + +#. type: Bullet: '- ' +#: ../../guide/en/caching/data.md +msgid "[Database](https://github.com/yiisoft/cache-db) — uses a database table to store cached data." +msgstr "[Banco de dados](https://github.com/yiisoft/cache-db) — usa uma tabela do banco de dados para guardar os dados em cache." + +#. type: Bullet: '- ' +#: ../../guide/en/caching/data.md +msgid "[File](https://github.com/yiisoft/cache-file) — uses standard files to store cached data. This is particularly suitable to cache large chunks of data, such as page content." +msgstr "[Arquivo](https://github.com/yiisoft/cache-file) — usa arquivos comuns para guardar os dados em cache. É especialmente adequado para guardar grandes blocos de dados, como o conteúdo de páginas." + +#. type: Bullet: '- ' +#: ../../guide/en/caching/data.md +msgid "[Memcached](https://github.com/yiisoft/cache-memcached) — uses a PHP [memcached](https://secure.php.net/manual/en/book.memcached.php) extension. You can consider this option as the fastest one when dealing with cache in a distributed application" +msgstr "[Memcached](https://github.com/yiisoft/cache-memcached) — usa a extensão [memcached](https://secure.php.net/manual/en/book.memcached.php) do PHP. Você pode considerar esta a opção mais rápida ao lidar com cache em uma aplicação distribuída" + +#. type: Plain text +#: ../../guide/en/caching/data.md +#, no-wrap +msgid "" +" (e.g., with several servers, load balancers, etc.)\n" +"- [Wincache](https://github.com/yiisoft/cache-wincache) — uses PHP [WinCache](https://iis.net/downloads/microsoft/wincache-extension)\n" +" ([see also](https://secure.php.net/manual/en/book.wincache.php)) extension.\n" +msgstr "" +" (por exemplo, com vários servidores, load balancers etc.)\n" +"- [Wincache](https://github.com/yiisoft/cache-wincache) — usa a extensão [WinCache](https://iis.net/downloads/microsoft/wincache-extension)\n" +" ([veja também](https://secure.php.net/manual/en/book.wincache.php)) do PHP.\n" + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "[You could find more handlers at packagist.org](https://packagist.org/providers/psr/simple-cache-implementation)." +msgstr "[Você encontra mais drivers no packagist.org](https://packagist.org/providers/psr/simple-cache-implementation)." + +#. type: Plain text +#: ../../guide/en/caching/data.md +#, no-wrap +msgid "" +"> [!TIP]\n" +"> You may use different cache storage in the same application. A common strategy is:\n" +"> - To use memory-based cache storage to store small but constantly used data (e.g., statistics)\n" +"> - To use file-based or database-based cache storage to store big and less often used data (e.g., page content)\n" +msgstr "" +"> [!TIP]\n" +"> Você pode usar armazenamentos de cache diferentes na mesma aplicação. Uma estratégia comum é:\n" +"> - Usar armazenamento de cache em memória para dados pequenos, mas usados constantemente (por exemplo, estatísticas)\n" +"> - Usar armazenamento de cache em arquivo ou em banco de dados para dados grandes e usados com menos frequência (por exemplo, conteúdo de páginas)\n" + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "Cache handlers are usually set up in a [dependency injection container](../concept/di-container.md) so that they can be globally configurable and accessible." +msgstr "Os drivers de cache normalmente são configurados em um [container de injeção de dependência](../concept/di-container.md), para que possam ser configurados e acessados globalmente." + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "Because all cache handlers support the same set of APIs, you can swap the underlying cache handler with a different one. You can do it by reconfiguring the application without modifying the code that uses the cache." +msgstr "Como todos os drivers de cache suportam o mesmo conjunto de APIs, você pode trocar o driver de cache subjacente por outro. Basta reconfigurar a aplicação, sem modificar o código que usa o cache." + +#. type: Title ### +#: ../../guide/en/caching/data.md +#, no-wrap +msgid "Cache keys" +msgstr "Chaves de cache" + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "A key uniquely identifies each data item stored in the cache. When you store a data item, you have to specify a key for it. Later, when you retrieve the data item, you should give the corresponding key." +msgstr "Uma chave identifica de forma única cada item de dados guardado no cache. Ao guardar um item, você precisa especificar uma chave para ele. Depois, ao recuperar o item, você deve informar a chave correspondente." + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "You may use a string or an arbitrary value as a cache key. When a key isn't a string, it will be automatically serialized into a string." +msgstr "Você pode usar uma string ou um valor arbitrário como chave de cache. Quando a chave não é uma string, ela é serializada automaticamente em uma string." + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "A common strategy of defining a cache key is to include all determining factors in terms of an array." +msgstr "Uma estratégia comum para definir uma chave de cache é incluir todos os fatores determinantes em um array." + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "When different applications use the same cache storage, you should specify a unique cache key prefix for each application to avoid conflicts of cache keys. You can do this by using `\\Yiisoft\\Cache\\PrefixedCache` decorator:" +msgstr "Quando aplicações diferentes usam o mesmo armazenamento de cache, você deve especificar um prefixo de chave de cache único para cada aplicação, para evitar conflitos de chaves. Você pode fazer isso usando o decorator `\\Yiisoft\\Cache\\PrefixedCache`:" + +#. type: Fenced code block (php) +#: ../../guide/en/caching/data.md +#, no-wrap +msgid "" +"$arrayCacheWithPrefix = new \\Yiisoft\\Cache\\PrefixedCache(new \\Yiisoft\\Cache\\ArrayCache(), 'myapp_');\n" +"$cache = new \\Yiisoft\\Cache\\Cache($arrayCacheWithPrefix);\n" +msgstr "" +"$arrayCacheWithPrefix = new \\Yiisoft\\Cache\\PrefixedCache(new \\Yiisoft\\Cache\\ArrayCache(), 'myapp_');\n" +"$cache = new \\Yiisoft\\Cache\\Cache($arrayCacheWithPrefix);\n" + +#. type: Title ### +#: ../../guide/en/caching/data.md +#, no-wrap +msgid "Cache expiration" +msgstr "Expiração do cache" + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "A data item stored in a cache will remain there forever unless it's removed because of some caching policy enforcement. For example, caching space is full and cache storage removes the oldest data. To change this behavior, you can set a TTL parameter when calling a method to store a data item:" +msgstr "Um item de dados guardado no cache fica lá para sempre, a menos que seja removido por alguma política de cache. Por exemplo, o espaço do cache fica cheio e o armazenamento remove os dados mais antigos. Para mudar esse comportamento, você pode definir um parâmetro TTL ao chamar um método que guarda um item:" + +#. type: Fenced code block (php) +#: ../../guide/en/caching/data.md +#, no-wrap +msgid "" +"$ttl = 3600;\n" +"$data = $cache->getOrSet($key, function (\\Psr\\SimpleCache\\CacheInterface $cache) use ($count) {\n" +"return getTopProductsFromDatabase($count);\n" +"}, $ttl);\n" +msgstr "" +"$ttl = 3600;\n" +"$data = $cache->getOrSet($key, function (\\Psr\\SimpleCache\\CacheInterface $cache) use ($count) {\n" +"return getTopProductsFromDatabase($count);\n" +"}, $ttl);\n" + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "The `$ttl` parameter indicates for how many seconds the data item can remain valid in the cache. When you retrieve the data item, if it has passed the expiration time, the method will execute the function and set the resulting value into cache." +msgstr "O parâmetro `$ttl` indica por quantos segundos o item pode continuar válido no cache. Ao recuperar o item, se o tempo de expiração já tiver passado, o método executa a função e grava o valor resultante no cache." + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "You may set the default TTL for the cache:" +msgstr "Você pode definir o TTL padrão do cache:" + +#. type: Fenced code block (php) +#: ../../guide/en/caching/data.md +#, no-wrap +msgid "$cache = new \\Yiisoft\\Cache\\Cache($arrayCache, 60 * 60); // 1 hour\n" +msgstr "$cache = new \\Yiisoft\\Cache\\Cache($arrayCache, 60 * 60); // 1 hora\n" + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "Additionally, you can invalidate a cache key explicitly:" +msgstr "Além disso, você pode invalidar uma chave de cache explicitamente:" + +#. type: Fenced code block (php) +#: ../../guide/en/caching/data.md +#, no-wrap +msgid "$cache->remove($key);\n" +msgstr "$cache->remove($key);\n" + +#. type: Title ### +#: ../../guide/en/caching/data.md +#, no-wrap +msgid "Invalidation dependencies" +msgstr "Dependências de invalidação" + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "Besides the expiration setting, changes of the so-called **invalidation dependencies** may also invalidate cached data item. For example, `\\Yiisoft\\Cache\\Dependency\\FileDependency` represents the dependency of a file's modification time. When this dependency changes, it means something modifying the corresponding file. As a result, any outdated file content found in the cache should invalidate." +msgstr "Além da configuração de expiração, mudanças nas chamadas **dependências de invalidação** também podem invalidar um item em cache. Por exemplo, `\\Yiisoft\\Cache\\Dependency\\FileDependency` representa a dependência da data de modificação de um arquivo. Quando essa dependência muda, significa que algo modificou o arquivo correspondente. Como resultado, qualquer conteúdo desatualizado do arquivo encontrado no cache deve ser invalidado." + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "Cache dependencies are objects of `\\Yiisoft\\Cache\\Dependency\\Dependency` descendant classes. When you store a data item in the cache, you can pass along an associated cache dependency object. For example," +msgstr "As dependências de cache são objetos de classes descendentes de `\\Yiisoft\\Cache\\Dependency\\Dependency`. Ao guardar um item no cache, você pode passar junto um objeto de dependência de cache associado. Por exemplo," + +#. type: Fenced code block (php) +#: ../../guide/en/caching/data.md +#, no-wrap +msgid "" +"/**\n" +" * @var callable $callable\n" +" * @var \\Yiisoft\\Cache\\CacheInterface $cache\n" +" */\n" +"\n" +"use Yiisoft\\Cache\\Dependency\\TagDependency;\n" +"\n" +"// Set many cache values marking both with a tag.\n" +"$cache->getOrSet('item_42_price', $callable, null, new TagDependency('item_42'));\n" +"$cache->getOrSet('item_42_total', $callable, 3600, new TagDependency('item_42'));\n" +"\n" +"// Trigger invalidation by tag.\n" +"TagDependency::invalidate($cache, 'item_42');\n" +msgstr "" +"/**\n" +" * @var callable $callable\n" +" * @var \\Yiisoft\\Cache\\CacheInterface $cache\n" +" */\n" +"\n" +"use Yiisoft\\Cache\\Dependency\\TagDependency;\n" +"\n" +"// Grava vários valores no cache, marcando ambos com uma tag.\n" +"$cache->getOrSet('item_42_price', $callable, null, new TagDependency('item_42'));\n" +"$cache->getOrSet('item_42_total', $callable, 3600, new TagDependency('item_42'));\n" +"\n" +"// Dispara a invalidação pela tag.\n" +"TagDependency::invalidate($cache, 'item_42');\n" + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "Below is a summary of the available cache dependencies:" +msgstr "Veja um resumo das dependências de cache disponíveis:" + +#. type: Bullet: '- ' +#: ../../guide/en/caching/data.md +msgid "`\\Yiisoft\\Cache\\Dependency\\ValueDependency`: invalidates the cache when specified value changes." +msgstr "`\\Yiisoft\\Cache\\Dependency\\ValueDependency`: invalida o cache quando o valor especificado muda." + +#. type: Bullet: '- ' +#: ../../guide/en/caching/data.md +msgid "`\\Yiisoft\\Cache\\Dependency\\CallbackDependency`: invalidates the cache when the result of the specified PHP callback is different." +msgstr "`\\Yiisoft\\Cache\\Dependency\\CallbackDependency`: invalida o cache quando o resultado do callback PHP especificado é diferente." + +#. type: Bullet: '- ' +#: ../../guide/en/caching/data.md +msgid "`\\Yiisoft\\Cache\\Dependency\\FileDependency`: invalidates the cache when the file's last modification time is different." +msgstr "`\\Yiisoft\\Cache\\Dependency\\FileDependency`: invalida o cache quando a data da última modificação do arquivo é diferente." + +#. type: Bullet: '- ' +#: ../../guide/en/caching/data.md +msgid "`\\Yiisoft\\Cache\\Dependency\\TagDependency`: associates a cached data item with one or many tags. You may invalidate the cached data items with the specified tag(s) by calling `TagDependency::invalidate()`." +msgstr "`\\Yiisoft\\Cache\\Dependency\\TagDependency`: associa um item em cache a uma ou várias tags. Você pode invalidar os itens em cache com as tags especificadas chamando `TagDependency::invalidate()`." + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "You may combine many dependencies using `\\Yiisoft\\Cache\\Dependency\\AnyDependency` or `\\Yiisoft\\Cache\\Dependency\\AllDependencies`." +msgstr "Você pode combinar várias dependências usando `\\Yiisoft\\Cache\\Dependency\\AnyDependency` ou `\\Yiisoft\\Cache\\Dependency\\AllDependencies`." + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "To implement your own dependency, extend from `\\Yiisoft\\Cache\\Dependency\\Dependency`." +msgstr "Para implementar a sua própria dependência, estenda `\\Yiisoft\\Cache\\Dependency\\Dependency`." + +#. type: Title ### +#: ../../guide/en/caching/data.md +#, no-wrap +msgid "Cache stampede prevention" +msgstr "Prevenção do efeito manada" + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "[A cache stampede](https://en.wikipedia.org/wiki/Cache_stampede) is a type of cascading failure that can occur when massively parallel computing systems with caching mechanisms come under a high load. This behavior is sometimes also called dog-piling." +msgstr "O [efeito manada (cache stampede)](https://en.wikipedia.org/wiki/Cache_stampede) é um tipo de falha em cascata que pode ocorrer quando sistemas de computação massivamente paralelos com mecanismos de cache ficam sob carga alta. Esse comportamento às vezes também é chamado de dog-piling." + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "The `\\Yiisoft\\Cache\\Cache` uses a built-in \"Probably early expiration\" algorithm that prevents cache stampede. This algorithm randomly fakes a cache miss for one user while others are still served the cached value. You can control its behavior with the fifth optional parameter of `getOrSet()`, which is a float value called `$beta`. By default, beta is `1.0`, which is usually enough. The higher the value, the earlier cache will be re-created." +msgstr "O `\\Yiisoft\\Cache\\Cache` usa um algoritmo embutido de \"expiração antecipada probabilística\" (\"Probably early expiration\") que evita o efeito manada. Esse algoritmo simula aleatoriamente um cache miss para um usuário enquanto os outros continuam recebendo o valor em cache. Você pode controlar o comportamento dele com o quinto parâmetro opcional de `getOrSet()`, um valor float chamado `$beta`. Por padrão, beta é `1.0`, o que costuma ser suficiente. Quanto maior o valor, mais cedo o cache será recriado." + +#. type: Fenced code block (php) +#: ../../guide/en/caching/data.md +#, no-wrap +msgid "" +"/**\n" +" * @var mixed $key\n" +" * @var callable $callable\n" +" * @var \\DateInterval $ttl\n" +" * @var \\Yiisoft\\Cache\\CacheInterface $cache\n" +" * @var \\Yiisoft\\Cache\\Dependency\\Dependency $dependency\n" +" */\n" +"\n" +"$beta = 2.0;\n" +"$cache->getOrSet($key, $callable, $ttl, $dependency, $beta);\n" +msgstr "" +"/**\n" +" * @var mixed $key\n" +" * @var callable $callable\n" +" * @var \\DateInterval $ttl\n" +" * @var \\Yiisoft\\Cache\\CacheInterface $cache\n" +" * @var \\Yiisoft\\Cache\\Dependency\\Dependency $dependency\n" +" */\n" +"\n" +"$beta = 2.0;\n" +"$cache->getOrSet($key, $callable, $ttl, $dependency, $beta);\n" diff --git a/_translations/po/pt-BR/guide_caching_overview.md.po b/_translations/po/pt-BR/guide_caching_overview.md.po new file mode 100644 index 00000000..7b4d3ed9 --- /dev/null +++ b/_translations/po/pt-BR/guide_caching_overview.md.po @@ -0,0 +1,57 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 08:23+0000\n" +"PO-Revision-Date: 2025-12-24 08:23+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/guide/caching/overview.md ../src/guide/index.md +#, no-wrap +msgid "Caching" +msgstr "Cache" + +#. type: Plain text +#: ../src/guide/caching/overview.md +msgid "Caching is an inexpensive and effective way to improve the performance of an application. By storing relatively static data in cache and serving it from cache when requested, the application saves the time that it otherwise would require to generate the data from scratch every time." +msgstr "O cache é uma forma barata e eficaz de melhorar o desempenho de uma aplicação. Ao armazenar dados relativamente estáticos no cache e servi-los a partir dele quando solicitados, a aplicação economiza o tempo que, de outra forma, precisaria para gerar os dados do zero a cada vez." + +#. type: Plain text +#: ../src/guide/caching/overview.md +msgid "Caching can occur at different levels and places in an application. On the server-side, at the lower level, cache may be used to store basic data, such as a list of most recent article information fetched from the database; and at the higher level, cache may be used to store fragments or whole of Web pages, such as the rendering result of the most recent articles. On the client-side, you may use HTTP caching to keep most recently visited page content in the browser cache." +msgstr "O cache pode ocorrer em diferentes níveis e lugares de uma aplicação. No lado do servidor, no nível mais baixo, o cache pode ser usado para armazenar dados básicos, como uma lista com as informações dos artigos mais recentes obtida do banco de dados; e, no nível mais alto, o cache pode ser usado para armazenar fragmentos ou páginas web inteiras, como o resultado da renderização dos artigos mais recentes. No lado do cliente, você pode usar o cache HTTP para manter o conteúdo das páginas visitadas mais recentemente no cache do navegador." + +#. type: Plain text +#: ../src/guide/caching/overview.md +msgid "Yii supports all these caching mechanisms:" +msgstr "O Yii suporta todos estes mecanismos de cache:" + +#. type: Bullet: '* ' +#: ../src/guide/caching/overview.md +msgid "[Data caching](data.md)" +msgstr "[Cache de dados](data.md)" + +#. type: Bullet: '* ' +#: ../src/guide/caching/overview.md +msgid "Fragment caching" +msgstr "Cache de fragmentos" + +#. type: Bullet: '* ' +#: ../src/guide/caching/overview.md +msgid "Page caching" +msgstr "Cache de páginas" + +#. type: Bullet: '* ' +#: ../src/guide/caching/overview.md +msgid "HTTP caching" +msgstr "Cache HTTP" diff --git a/_translations/po/pt-BR/guide_concept_aliases.md.po b/_translations/po/pt-BR/guide_concept_aliases.md.po new file mode 100644 index 00000000..e01f360d --- /dev/null +++ b/_translations/po/pt-BR/guide_concept_aliases.md.po @@ -0,0 +1,334 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-06-05 20:33+0000\n" +"PO-Revision-Date: 2026-06-05 20:33+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/concept/aliases.md +#, no-wrap +msgid "Aliases" +msgstr "Aliases" + +#. type: Plain text +#: ../src/guide/concept/aliases.md +msgid "You can use aliases to represent file paths or URLs so that you don't have to hard-code absolute paths or URLs in your project. An alias must start with the `@` character to be differentiated from normal file paths and URLs. Alias defined without leading `@` will be prefixed with `@` character." +msgstr "Você pode usar aliases para representar caminhos de arquivos ou URLs, evitando escrever caminhos absolutos ou URLs fixos no seu projeto. Um alias deve começar com o caractere `@` para se diferenciar de caminhos de arquivos e URLs normais. Um alias definido sem o `@` inicial receberá o prefixo `@`." + +#. type: Plain text +#: ../src/guide/concept/aliases.md +msgid "Default Yii application has some aliases pre-defined in `config/params.php`. For example, the alias `@public` represents the web root path; `@baseUrl` represents the base URL for the currently running Web application." +msgstr "A aplicação Yii padrão tem alguns aliases predefinidos em `config/params.php`. Por exemplo, o alias `@public` representa o caminho da raiz web; `@baseUrl` representa a URL base da aplicação web em execução." + +#. type: Title ## +#: ../src/guide/concept/aliases.md +#, no-wrap +msgid "Defining aliases" +msgstr "Definindo aliases" + +#. type: Plain text +#: ../src/guide/concept/aliases.md +msgid "You can define an alias via application's `config/params.php`:" +msgstr "Você pode definir um alias no `config/params.php` da aplicação:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/aliases.md +#, no-wrap +msgid "" +"return [\n" +" // ...\n" +" \n" +" 'yiisoft/aliases' => [\n" +" 'aliases' => [\n" +" // ...\n" +" \n" +" // an alias of a file path\n" +" '@foo' => '/path/to/foo',\n" +" \n" +" // an alias of a URL\n" +" '@bar' => 'https://www.example.com',\n" +" \n" +" // an alias of a concrete file that contains a \\foo\\Bar class \n" +" '@foo/Bar.php' => '/definitely/not/foo/Bar.php',\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +"return [\n" +" // ...\n" +" \n" +" 'yiisoft/aliases' => [\n" +" 'aliases' => [\n" +" // ...\n" +" \n" +" // um alias de um caminho de arquivo\n" +" '@foo' => '/path/to/foo',\n" +" \n" +" // um alias de uma URL\n" +" '@bar' => 'https://www.example.com',\n" +" \n" +" // um alias de um arquivo concreto que contém a classe \\foo\\Bar \n" +" '@foo/Bar.php' => '/definitely/not/foo/Bar.php',\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/concept/aliases.md +#, no-wrap +msgid "" +"> [!NOTE]\n" +"> The file path or URL being aliased may *not* necessarily refer to an existing file or resource.\n" +msgstr "" +"> [!NOTE]\n" +"> O caminho de arquivo ou URL representado pelo alias *não* precisa necessariamente se referir a um arquivo ou recurso existente.\n" + +#. type: Plain text +#: ../src/guide/concept/aliases.md +msgid "Given a defined alias, you may derive a new alias by appending a slash `/` followed with one or more path segments. For example, `@foo` is a root alias, while `@foo/bar/file.php` is a derived alias." +msgstr "A partir de um alias definido, você pode derivar um novo alias acrescentando uma barra `/` seguida de um ou mais segmentos de caminho. Por exemplo, `@foo` é um alias raiz, enquanto `@foo/bar/file.php` é um alias derivado." + +#. type: Plain text +#: ../src/guide/concept/aliases.md +msgid "You can define an alias using another alias (either root or derived):" +msgstr "Você pode definir um alias usando outro alias (raiz ou derivado):" + +#. type: Fenced code block (php) +#: ../src/guide/concept/aliases.md +#, no-wrap +msgid "'@foobar' => '@foo/bar', \n" +msgstr "'@foobar' => '@foo/bar', \n" + +#. type: Plain text +#: ../src/guide/concept/aliases.md +msgid "The `yiisoft/aliases` parameter initializes `Aliases` service from [`yiisoft/aliases`](https://github.com/yiisoft/aliases) package. You can set extra aliases in runtime by using the service:" +msgstr "O parâmetro `yiisoft/aliases` inicializa o serviço `Aliases` do pacote [`yiisoft/aliases`](https://github.com/yiisoft/aliases). Você pode definir aliases extras em tempo de execução usando o serviço:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/aliases.md +#, no-wrap +msgid "" +"use \\Yiisoft\\Aliases\\Aliases;\n" +"\n" +"public function actionIndex(Aliases $aliases)\n" +"{\n" +" $aliases->set('@uploads', '@root/uploads');\n" +"}\n" +msgstr "" +"use \\Yiisoft\\Aliases\\Aliases;\n" +"\n" +"public function actionIndex(Aliases $aliases)\n" +"{\n" +" $aliases->set('@uploads', '@root/uploads');\n" +"}\n" + +#. type: Title ## +#: ../src/guide/concept/aliases.md +#, no-wrap +msgid "Using aliases in configuration" +msgstr "Usando aliases na configuração" + +#. type: Plain text +#: ../src/guide/concept/aliases.md +msgid "It's preferred to resolve aliases at the configuration level, so services get URLs and paths as ready to use strings:" +msgstr "É preferível resolver os aliases no nível da configuração, para que os serviços recebam URLs e caminhos como strings prontas para uso:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/aliases.md +#, no-wrap +msgid "" +" static fn (Aliases $aliases) => new FileCache(\n" +" $aliases->get($params['yiisoft/cache-file']['fileCache']['path'])\n" +" ),\n" +"];\n" +msgstr "" +" static fn (Aliases $aliases) => new FileCache(\n" +" $aliases->get($params['yiisoft/cache-file']['fileCache']['path'])\n" +" ),\n" +"];\n" + +#. type: Title ## +#: ../src/guide/concept/aliases.md +#, no-wrap +msgid "Resolving aliases" +msgstr "Resolvendo aliases" + +#. type: Plain text +#: ../src/guide/concept/aliases.md +msgid "You can use `Aliases` service to resolve an alias or derived alias into the file path or URL it represents:" +msgstr "Você pode usar o serviço `Aliases` para resolver um alias ou alias derivado no caminho de arquivo ou URL que ele representa:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/aliases.md +#, no-wrap +msgid "" +"use \\Yiisoft\\Aliases\\Aliases;\n" +"\n" +"public function actionIndex(Aliases $aliases)\n" +"{\n" +" $foo = $aliases->get('@foo'); // /path/to/foo\n" +" $bar = $aliases->get('@bar'); // https://www.example.com\n" +" $file = $aliases->get('@foo/bar/file.php'); // /path/to/foo/bar/file.php\n" +"}\n" +msgstr "" +"use \\Yiisoft\\Aliases\\Aliases;\n" +"\n" +"public function actionIndex(Aliases $aliases)\n" +"{\n" +" $foo = $aliases->get('@foo'); // /path/to/foo\n" +" $bar = $aliases->get('@bar'); // https://www.example.com\n" +" $file = $aliases->get('@foo/bar/file.php'); // /path/to/foo/bar/file.php\n" +"}\n" + +#. type: Plain text +#: ../src/guide/concept/aliases.md +msgid "The path/URL represented by a derived alias is determined by replacing the root alias part with its corresponding path/URL in the derived alias." +msgstr "O caminho/URL representado por um alias derivado é determinado substituindo a parte do alias raiz pelo caminho/URL correspondente." + +#. type: Plain text +#: ../src/guide/concept/aliases.md +#, no-wrap +msgid "" +"> [!NOTE]\n" +"> The `get()` method doesn't check whether the resulting path/URL refers to an existing file or resource.\n" +msgstr "" +"> [!NOTE]\n" +"> O método `get()` não verifica se o caminho/URL resultante se refere a um arquivo ou recurso existente.\n" + +#. type: Plain text +#: ../src/guide/concept/aliases.md +msgid "A root alias may also contain slash `/` characters. The `get()` method is intelligent enough to tell, which part of an alias is a root alias and thus correctly determines the corresponding file path or URL:" +msgstr "Um alias raiz também pode conter caracteres de barra `/`. O método `get()` é inteligente o suficiente para identificar qual parte de um alias é o alias raiz e, assim, determina corretamente o caminho de arquivo ou URL correspondente:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/aliases.md +#, no-wrap +msgid "" +"use \\Yiisoft\\Aliases\\Aliases;\n" +"\n" +"public function actionIndex(Aliases $aliases)\n" +"{\n" +" $aliases->set('@foo', '/path/to/foo');\n" +" $aliases->set('@foo/bar', '/path2/bar');\n" +"\n" +" $aliases->get('@foo/test/file.php'); // /path/to/foo/test/file.php\n" +" $aliases->get('@foo/bar/file.php'); // /path2/bar/file.php\n" +"} \n" +msgstr "" +"use \\Yiisoft\\Aliases\\Aliases;\n" +"\n" +"public function actionIndex(Aliases $aliases)\n" +"{\n" +" $aliases->set('@foo', '/path/to/foo');\n" +" $aliases->set('@foo/bar', '/path2/bar');\n" +"\n" +" $aliases->get('@foo/test/file.php'); // /path/to/foo/test/file.php\n" +" $aliases->get('@foo/bar/file.php'); // /path2/bar/file.php\n" +"} \n" + +#. type: Plain text +#: ../src/guide/concept/aliases.md +msgid "If `@foo/bar` isn't defined as a root alias, the last statement would display `/path/to/foo/bar/file.php`." +msgstr "Se `@foo/bar` não estiver definido como alias raiz, a última instrução exibiria `/path/to/foo/bar/file.php`." + +#. type: Title ## +#: ../src/guide/concept/aliases.md +#, no-wrap +msgid "Predefined aliases" +msgstr "Aliases predefinidos" + +#. type: Plain text +#: ../src/guide/concept/aliases.md +msgid "[Yii application](https://github.com/yiisoft/app) predefines a set of aliases to reference commonly used file paths and URLs:" +msgstr "A [aplicação Yii](https://github.com/yiisoft/app) predefine um conjunto de aliases para referenciar caminhos de arquivos e URLs de uso comum:" + +#. type: Bullet: '- ' +#: ../src/guide/concept/aliases.md +msgid "`@root` - the base directory of the currently running application." +msgstr "`@root` - a pasta base da aplicação em execução." + +#. type: Bullet: '- ' +#: ../src/guide/concept/aliases.md +msgid "`@assets` - application's public directory where it publishes assets." +msgstr "`@assets` - pasta pública da aplicação onde ela publica os assets." + +#. type: Bullet: '- ' +#: ../src/guide/concept/aliases.md +msgid "`@assetsUrl` - URL of base directory with published assets." +msgstr "`@assetsUrl` - URL da pasta base com os assets publicados." + +#. type: Bullet: '- ' +#: ../src/guide/concept/aliases.md +msgid "`@baseUrl` - the base URL of the currently running Web application. Defaults to `/`." +msgstr "`@baseUrl` - a URL base da aplicação web em execução. O padrão é `/`." + +#. type: Bullet: '- ' +#: ../src/guide/concept/aliases.md +msgid "`@npm` - node packages directory." +msgstr "`@npm` - pasta de pacotes node." + +#. type: Bullet: '- ' +#: ../src/guide/concept/aliases.md +msgid "`@bower` - bower packages directory." +msgstr "`@bower` - pasta de pacotes bower." + +#. type: Bullet: '- ' +#: ../src/guide/concept/aliases.md +msgid "`@vendor` - Composer's `vendor` directory." +msgstr "`@vendor` - a pasta `vendor` do Composer." + +#. type: Bullet: '- ' +#: ../src/guide/concept/aliases.md +msgid "`@public` - application's publicly accessible directory that with `index.php`." +msgstr "`@public` - pasta publicamente acessível da aplicação, que contém o `index.php`." + +#. type: Bullet: '- ' +#: ../src/guide/concept/aliases.md +msgid "`@runtime` - the runtime path of the currently running application. Defaults to `@root/runtime`." +msgstr "`@runtime` - o caminho de runtime da aplicação em execução. O padrão é `@root/runtime`." + +#. type: Bullet: '- ' +#: ../src/guide/concept/aliases.md +msgid "`@layout` - the directory with layouts." +msgstr "`@layout` - a pasta com os layouts." + +#. type: Bullet: '- ' +#: ../src/guide/concept/aliases.md +msgid "`@resources` - directory with views, asset sources and other resources." +msgstr "`@resources` - pasta com views, fontes de assets e outros recursos." + +#. type: Bullet: '- ' +#: ../src/guide/concept/aliases.md +msgid "`@views` - application view templates base directory." +msgstr "`@views` - pasta base dos templates de view da aplicação." diff --git a/_translations/po/pt-BR/guide_concept_autoloading.md.po b/_translations/po/pt-BR/guide_concept_autoloading.md.po new file mode 100644 index 00000000..08a34a37 --- /dev/null +++ b/_translations/po/pt-BR/guide_concept_autoloading.md.po @@ -0,0 +1,78 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-01-08 08:54+0000\n" +"PO-Revision-Date: 2026-01-08 08:54+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md ../src/guide/concept/autoloading.md ../src/guide/security/best-practices.md ../src/guide/structure/domain.md ../src/guide/tutorial/console-applications.md ../src/internals/004-namespaces.md ../src/internals/007-exceptions.md ../src/internals/008-interfaces.md +#, no-wrap +msgid "References" +msgstr "Referências" + +#. type: Title # +#: ../src/guide/concept/autoloading.md +#, no-wrap +msgid "Class autoloading" +msgstr "Autoload de classes" + +#. type: Plain text +#: ../src/guide/concept/autoloading.md +msgid "Since Yii uses [Composer](https://getcomposer.org) to manage packages, it automatically loads classes from these packages without the need to `require` their file explicitly. When it installs packages, it generates a [PSR-4 compatible autoloader](https://www.php-fig.org/psr/psr-4/). To use it, `require_once` autoloader `/vendor/autoload.php` in your `index.php` entry point file." +msgstr "Como o Yii usa o [Composer](https://getcomposer.org) para gerenciar pacotes, ele carrega automaticamente as classes desses pacotes sem a necessidade de fazer `require` dos arquivos explicitamente. Ao instalar pacotes, o Composer gera um [autoloader compatível com PSR-4](https://www.php-fig.org/psr/psr-4/). Para usá-lo, faça `require_once` do autoloader `/vendor/autoload.php` no seu arquivo de ponto de entrada `index.php`." + +#. type: Plain text +#: ../src/guide/concept/autoloading.md +msgid "You can use autoloader not only for the packages installed, but for your application as well since it's also a package. To load classes of a certain namespace, add the following to `composer.json`:" +msgstr "Você pode usar o autoloader não só para os pacotes instalados, mas também para a sua aplicação, já que ela também é um pacote. Para carregar classes de um determinado namespace, adicione o seguinte ao `composer.json`:" + +#. type: Fenced code block (json) +#: ../src/guide/concept/autoloading.md +#, no-wrap +msgid "" +"{\n" +" \"autoload\": {\n" +" \"psr-4\": {\n" +" \"App\\\\\": \"src/\"\n" +" }\n" +" }\n" +"}\n" +msgstr "" +"{\n" +" \"autoload\": {\n" +" \"psr-4\": {\n" +" \"App\\\\\": \"src/\"\n" +" }\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/concept/autoloading.md +msgid "Where `App\\\\` is a root namespace and `src/` is a directory where you have your classes. You can add more source roots if needed. When done, execute `composer dump-autoload` or simply `composer du` and classes from the corresponding namespaces will start loading automatically." +msgstr "Onde `App\\\\` é o namespace raiz e `src/` é a pasta onde ficam suas classes. Você pode adicionar mais raízes de código-fonte se precisar. Depois, execute `composer dump-autoload` ou simplesmente `composer du`, e as classes dos namespaces correspondentes passarão a ser carregadas automaticamente." + +#. type: Plain text +#: ../src/guide/concept/autoloading.md +msgid "If you need development-environment-specific autoloading that isn't used when executing Composer with `--no-dev` flag, add it to `autoload-dev` section instead of `autoload`." +msgstr "Se você precisar de autoload específico do ambiente de desenvolvimento, que não seja usado ao executar o Composer com a flag `--no-dev`, adicione-o à seção `autoload-dev` em vez de `autoload`." + +#. type: Bullet: '- ' +#: ../src/guide/concept/autoloading.md +msgid "[PSR-4: Autoloader](https://www.php-fig.org/psr/psr-4/)." +msgstr "[PSR-4: Autoloader](https://www.php-fig.org/psr/psr-4/)." + +#. type: Bullet: '- ' +#: ../src/guide/concept/autoloading.md +msgid "[Composer guide on autoloading](https://getcomposer.org/doc/01-basic-usage.md#autoloading)." +msgstr "[Guia do Composer sobre autoload](https://getcomposer.org/doc/01-basic-usage.md#autoloading)." diff --git a/_translations/po/pt-BR/guide_concept_configuration.md.po b/_translations/po/pt-BR/guide_concept_configuration.md.po new file mode 100644 index 00000000..acd4c330 --- /dev/null +++ b/_translations/po/pt-BR/guide_concept_configuration.md.po @@ -0,0 +1,904 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-05-29 19:04+0000\n" +"PO-Revision-Date: 2026-05-29 19:04+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/sentry-integration.md ../src/guide/concept/configuration.md ../src/guide/tutorial/using-yii-with-frankenphp.md ../src/guide/tutorial/using-yii-with-roadrunner.md ../src/guide/views/view-injections.md +#, no-wrap +msgid "Configuration" +msgstr "Configuração" + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "There are many ways to configure your application. We will focus on concepts used in the [default project template](https://github.com/yiisoft/app)." +msgstr "Há muitas formas de configurar a sua aplicação. Aqui o foco são os conceitos usados no [template de projeto padrão](https://github.com/yiisoft/app)." + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "Yii3 configs are part of the application. You can change many aspects of how the application works by editing configuration under `config/` directory." +msgstr "As configurações do Yii3 fazem parte da aplicação. Você pode mudar muitos aspectos do funcionamento da aplicação editando a configuração na pasta `config/`." + +#. type: Title ## +#: ../src/guide/concept/configuration.md +#, no-wrap +msgid "Config plugin" +msgstr "Plugin de configuração" + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "The application template uses [yiisoft/config](https://github.com/yiisoft/config) as a composer plugin to assemble configs." +msgstr "O template de aplicação usa o [yiisoft/config](https://github.com/yiisoft/config) como plugin do Composer para montar as configurações." + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "Packages provide default configurations through defined [config groups](https://github.com/yiisoft/config#config-groups) in the `config-plugin` key in the `extra` section of the `composer.json`:" +msgstr "Os pacotes fornecem configurações padrão por meio de [grupos de configuração](https://github.com/yiisoft/config#config-groups) definidos na chave `config-plugin` da seção `extra` do `composer.json`:" + +#. type: Fenced code block (json) +#: ../src/guide/concept/configuration.md +#, no-wrap +msgid "" +"\"extra\": {\n" +" \"config-plugin-options\": {\n" +" \"source-directory\": \"config\",\n" +" },\n" +" \"config-plugin\": {\n" +" \"params\": \"params.php\",\n" +" \"web\": \"web.php\"\n" +" }\n" +"}\n" +msgstr "" +"\"extra\": {\n" +" \"config-plugin-options\": {\n" +" \"source-directory\": \"config\",\n" +" },\n" +" \"config-plugin\": {\n" +" \"params\": \"params.php\",\n" +" \"web\": \"web.php\"\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "After Composer updates autoload files, such as during `dump-autoload`, `install`, `require`, `update`, or `remove`, the plugin scans installed packages for configurations and writes a merge plan to `config/.merge-plan.php`. The merge plan declares the order of merging found configurations into the final configuration to be passed to [DI container](di-container.md)." +msgstr "Depois que o Composer atualiza os arquivos de autoload, como durante `dump-autoload`, `install`, `require`, `update` ou `remove`, o plugin procura configurações nos pacotes instalados e grava um merge plan em `config/.merge-plan.php`. O merge plan declara a ordem em que as configurações encontradas são mescladas na configuração final, que é passada ao [container de DI](di-container.md)." + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "At runtime, `Yiisoft\\Config\\Config` loads the defined config groups according to that merge plan. Configs are read in three layers:" +msgstr "Em tempo de execução, `Yiisoft\\Config\\Config` carrega os grupos de configuração definidos de acordo com esse merge plan. As configurações são lidas em três camadas:" + +#. type: Bullet: '1. ' +#: ../src/guide/concept/configuration.md +msgid "Vendor package configs with default values." +msgstr "Configurações dos pacotes em vendor, com os valores padrão." + +#. type: Bullet: '2. ' +#: ../src/guide/concept/configuration.md +msgid "Root package configs from the application `config/` directory." +msgstr "Configurações do pacote raiz, da pasta `config/` da aplicação." + +#. type: Bullet: '3. ' +#: ../src/guide/concept/configuration.md +msgid "Environment-specific configs from the application." +msgstr "Configurações da aplicação específicas de cada ambiente." + +#. type: Plain text +#: ../src/guide/concept/configuration.md +#, no-wrap +msgid "" +"> [!WARNING]\n" +"> Config keys with the same name are not allowed within a single layer.\n" +msgstr "" +"> [!WARNING]\n" +"> Chaves de configuração com o mesmo nome não são permitidas dentro de uma mesma camada.\n" + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "The application template stores configurations in a PHP file instead of inline JSON:" +msgstr "O template de aplicação guarda as configurações em um arquivo PHP em vez de JSON inline:" + +#. type: Fenced code block (json) +#: ../src/guide/concept/configuration.md +#, no-wrap +msgid "" +"\"extra\": {\n" +" \"config-plugin-file\": \"config/configuration.php\"\n" +"}\n" +msgstr "" +"\"extra\": {\n" +" \"config-plugin-file\": \"config/configuration.php\"\n" +"}\n" + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "That file returns the same keys you could otherwise define in `composer.json`: `config-plugin`, `config-plugin-options`, and `config-plugin-environments`." +msgstr "Esse arquivo retorna as mesmas chaves que você poderia definir no `composer.json`: `config-plugin`, `config-plugin-options` e `config-plugin-environments`." + +#. type: Fenced code block (php) +#: ../src/guide/concept/configuration.md +#, no-wrap +msgid "" +"use App\\Environment;\n" +"\n" +"return [\n" +" 'config-plugin-options' => [\n" +" 'source-directory' => 'config',\n" +" ],\n" +" 'config-plugin' => [\n" +" 'params' => 'common/params.php',\n" +" 'params-web' => [\n" +" '$params',\n" +" 'web/params.php',\n" +" ],\n" +" 'params-console' => [\n" +" '$params',\n" +" 'console/params.php',\n" +" ],\n" +" 'bootstrap' => 'common/bootstrap.php',\n" +" 'bootstrap-web' => '$bootstrap',\n" +" 'bootstrap-console' => '$bootstrap',\n" +" 'di' => 'common/di/*.php',\n" +" 'di-web' => [\n" +" '$di',\n" +" 'web/di/*.php',\n" +" ],\n" +" 'di-console' => '$di',\n" +" 'di-delegates' => [],\n" +" 'di-delegates-console' => '$di-delegates',\n" +" 'di-delegates-web' => '$di-delegates',\n" +" 'di-providers' => [],\n" +" 'di-providers-web' => '$di-providers',\n" +" 'di-providers-console' => '$di-providers',\n" +" 'events' => [],\n" +" 'events-web' => '$events',\n" +" 'events-console' => '$events',\n" +" 'routes' => 'common/routes.php',\n" +" ],\n" +" 'config-plugin-environments' => [\n" +" Environment::DEV => [\n" +" 'params' => [\n" +" 'environments/dev/params.php',\n" +" ],\n" +" ],\n" +" Environment::TEST => [\n" +" 'params' => [\n" +" 'environments/test/params.php',\n" +" ],\n" +" ],\n" +" Environment::PROD => [\n" +" 'params' => [\n" +" 'environments/prod/params.php',\n" +" ],\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +"use App\\Environment;\n" +"\n" +"return [\n" +" 'config-plugin-options' => [\n" +" 'source-directory' => 'config',\n" +" ],\n" +" 'config-plugin' => [\n" +" 'params' => 'common/params.php',\n" +" 'params-web' => [\n" +" '$params',\n" +" 'web/params.php',\n" +" ],\n" +" 'params-console' => [\n" +" '$params',\n" +" 'console/params.php',\n" +" ],\n" +" 'bootstrap' => 'common/bootstrap.php',\n" +" 'bootstrap-web' => '$bootstrap',\n" +" 'bootstrap-console' => '$bootstrap',\n" +" 'di' => 'common/di/*.php',\n" +" 'di-web' => [\n" +" '$di',\n" +" 'web/di/*.php',\n" +" ],\n" +" 'di-console' => '$di',\n" +" 'di-delegates' => [],\n" +" 'di-delegates-console' => '$di-delegates',\n" +" 'di-delegates-web' => '$di-delegates',\n" +" 'di-providers' => [],\n" +" 'di-providers-web' => '$di-providers',\n" +" 'di-providers-console' => '$di-providers',\n" +" 'events' => [],\n" +" 'events-web' => '$events',\n" +" 'events-console' => '$events',\n" +" 'routes' => 'common/routes.php',\n" +" ],\n" +" 'config-plugin-environments' => [\n" +" Environment::DEV => [\n" +" 'params' => [\n" +" 'environments/dev/params.php',\n" +" ],\n" +" ],\n" +" Environment::TEST => [\n" +" 'params' => [\n" +" 'environments/test/params.php',\n" +" ],\n" +" ],\n" +" Environment::PROD => [\n" +" 'params' => [\n" +" 'environments/prod/params.php',\n" +" ],\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "Config group names are mapping keys. Their values are file paths relative to the `source-directory` option, which defaults to the directory containing `composer.json`." +msgstr "Os nomes dos grupos de configuração são as chaves do mapeamento. Os valores são caminhos de arquivos relativos à opção `source-directory`, cujo padrão é a pasta que contém o `composer.json`." + +#. type: Bullet: '- ' +#: ../src/guide/concept/configuration.md +msgid "A string value loads one file." +msgstr "Um valor string carrega um arquivo." + +#. type: Bullet: '- ' +#: ../src/guide/concept/configuration.md +msgid "An array loads and merges multiple files in the given order." +msgstr "Um array carrega e mescla vários arquivos na ordem indicada." + +#. type: Bullet: '- ' +#: ../src/guide/concept/configuration.md +msgid "`?` marks an optional file." +msgstr "`?` marca um arquivo opcional." + +#. type: Bullet: '- ' +#: ../src/guide/concept/configuration.md +msgid "`*` marks a wildcard path." +msgstr "`*` marca um caminho com curinga." + +#. type: Bullet: '- ' +#: ../src/guide/concept/configuration.md +msgid "`$group` references another config group to be merged." +msgstr "`$group` referencia outro grupo de configuração a ser mesclado." + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "The `params` group is special: its values are available as `$params` in other config files by default." +msgstr "O grupo `params` é especial: por padrão, os valores dele ficam disponíveis como `$params` nos outros arquivos de configuração." + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "You can read more in the [yiisoft/config documentation](https://github.com/yiisoft/config/blob/master/README.md)." +msgstr "Leia mais na [documentação do yiisoft/config](https://github.com/yiisoft/config/blob/master/README.md)." + +#. type: Title ## +#: ../src/guide/concept/configuration.md +#, no-wrap +msgid "Config files" +msgstr "Arquivos de configuração" + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "Now, as you know how the plugin assembles configs, look at the `config/` directory structure used by the default application template:" +msgstr "Agora que você sabe como o plugin monta as configurações, veja a estrutura da pasta `config/` usada pelo template de aplicação padrão:" + +#. type: Fenced code block +#: ../src/guide/concept/configuration.md +#, no-wrap +msgid "" +"common/\n" +" bootstrap.php\n" +" params.php\n" +" routes.php\n" +" di/\n" +" *.php\n" +"console/\n" +" params.php\n" +"environments/\n" +" dev/\n" +" params.php\n" +" prod/\n" +" params.php\n" +" test/\n" +" params.php\n" +"web/\n" +" params.php\n" +" di/\n" +" *.php\n" +".merge-plan.php\n" +"configuration.php\n" +msgstr "" +"common/\n" +" bootstrap.php\n" +" params.php\n" +" routes.php\n" +" di/\n" +" *.php\n" +"console/\n" +" params.php\n" +"environments/\n" +" dev/\n" +" params.php\n" +" prod/\n" +" params.php\n" +" test/\n" +" params.php\n" +"web/\n" +" params.php\n" +" di/\n" +" *.php\n" +".merge-plan.php\n" +"configuration.php\n" + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "This structure follows the groups defined in `config/configuration.php`:" +msgstr "Essa estrutura segue os grupos definidos em `config/configuration.php`:" + +#. type: Bullet: '- ' +#: ../src/guide/concept/configuration.md +msgid "`params`, `params-web`, and `params-console` load parameter files from `common/`, `web/`, and `console/`." +msgstr "`params`, `params-web` e `params-console` carregam arquivos de parâmetros de `common/`, `web/` e `console/`." + +#. type: Bullet: '- ' +#: ../src/guide/concept/configuration.md +msgid "`di` and `di-web` load container definitions from `common/di/` and `web/di/`." +msgstr "`di` e `di-web` carregam definições do container de `common/di/` e `web/di/`." + +#. type: Bullet: '- ' +#: ../src/guide/concept/configuration.md +msgid "`routes` and `bootstrap` load `common/routes.php` and `common/bootstrap.php`." +msgstr "`routes` e `bootstrap` carregam `common/routes.php` e `common/bootstrap.php`." + +#. type: Bullet: '- ' +#: ../src/guide/concept/configuration.md +msgid "`config-plugin-environments` adds environment-specific parameter files from `environments/dev/`, `environments/test/`, and `environments/prod/`." +msgstr "`config-plugin-environments` acrescenta arquivos de parâmetros específicos de cada ambiente de `environments/dev/`, `environments/test/` e `environments/prod/`." + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "At runtime, `.merge-plan.php` stores the assembled merge plan generated from `configuration.php`." +msgstr "Em tempo de execução, `.merge-plan.php` guarda o merge plan montado a partir de `configuration.php`." + +#. type: Title ### +#: ../src/guide/concept/configuration.md +#, no-wrap +msgid "Container configuration" +msgstr "Configuração do container" + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "The application consists of services registered in a [dependency container](di-container.md). In the default template, direct container definitions live in `config/common/di/*.php` and `config/web/di/*.php`." +msgstr "A aplicação é formada por serviços registrados em um [container de dependências](di-container.md). No template padrão, as definições diretas do container ficam em `config/common/di/*.php` e `config/web/di/*.php`." + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "Definitions from `common/di/` are shared by web and console entry points. The `di-web` group adds web-specific definitions from `web/di/`. The `di-console` group currently reuses the shared `di` definitions without extra files." +msgstr "As definições de `common/di/` são compartilhadas pelos pontos de entrada web e de console. O grupo `di-web` acrescenta definições específicas da web, de `web/di/`. Atualmente, o grupo `di-console` reaproveita as definições compartilhadas de `di`, sem arquivos extras." + +#. type: Fenced code block (php) +#: ../src/guide/concept/configuration.md +#, no-wrap +msgid "" +" [\n" +" '__construct()' => [\n" +" 'name' => $params['application']['name'],\n" +" 'charset' => $params['application']['charset'],\n" +" 'locale' => $params['application']['locale'],\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +" [\n" +" '__construct()' => [\n" +" 'name' => $params['application']['name'],\n" +" 'charset' => $params['application']['charset'],\n" +" 'locale' => $params['application']['locale'],\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "Config plugin passes the special `$params` variable to all config files. The definition uses it to configure services." +msgstr "O plugin de configuração passa a variável especial `$params` para todos os arquivos de configuração. A definição a usa para configurar os serviços." + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "The guide on [\"Dependency injection and container\"](di-container.md) describes the configuration format and the idea of dependency injection in detail." +msgstr "O guia [\"Injeção de dependência e container\"](di-container.md) descreve em detalhes o formato da configuração e a ideia de injeção de dependência." + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "For convenience, there is a naming convention for custom string keys:" +msgstr "Por conveniência, existe uma convenção de nomes para chaves string personalizadas:" + +#. type: Bullet: '1. ' +#: ../src/guide/concept/configuration.md +msgid "Prefix package name such as `yiisoft/cache-file/custom-definition`." +msgstr "Prefixe com o nome do pacote, como em `yiisoft/cache-file/custom-definition`." + +#. type: Bullet: '2. ' +#: ../src/guide/concept/configuration.md +msgid "In case configuration are for the application itself, skip package prefix, such as `custom-definition`." +msgstr "Se a configuração for da própria aplicação, omita o prefixo do pacote, como em `custom-definition`." + +#. type: Title ### +#: ../src/guide/concept/configuration.md +#, no-wrap +msgid "Service providers" +msgstr "Service providers" + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "As an alternative to registering dependencies directly, you can use service providers. A service provider is a class that returns a reusable set of container definitions and extensions." +msgstr "Como alternativa a registrar dependências diretamente, você pode usar service providers. Um service provider é uma classe que retorna um conjunto reutilizável de definições e extensões do container." + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "The default template exposes three config groups for service providers: `di-providers`, `di-providers-web`, and `di-providers-console`. In the template they are initialized as empty arrays in `config/configuration.php`, and you can later populate them inline or switch them to load values from files." +msgstr "O template padrão expõe três grupos de configuração para service providers: `di-providers`, `di-providers-web` e `di-providers-console`. No template, eles são inicializados como arrays vazios em `config/configuration.php`, e depois você pode preenchê-los inline ou fazê-los carregar valores de arquivos." + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "Prefer direct container configuration for application services with a simple definition: a class name, an interface implementation, constructor arguments from `$params`, or a closure that creates a single service." +msgstr "Prefira a configuração direta do container para serviços da aplicação com definição simples: um nome de classe, a implementação de uma interface, argumentos do construtor vindos de `$params` ou uma closure que cria um único serviço." + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "Use a service provider when the registration itself is a reusable unit:" +msgstr "Use um service provider quando o próprio registro for uma unidade reutilizável:" + +#. type: Bullet: '- ' +#: ../src/guide/concept/configuration.md +msgid "A package registers several related services, aliases, or extensions." +msgstr "Um pacote registra vários serviços, aliases ou extensões relacionados." + +#. type: Bullet: '- ' +#: ../src/guide/concept/configuration.md +msgid "A service registration also needs supporting definitions." +msgstr "O registro de um serviço também precisa de definições de apoio." + +#. type: Bullet: '- ' +#: ../src/guide/concept/configuration.md +msgid "The same registration should be reused in several applications." +msgstr "O mesmo registro deve ser reutilizado em várias aplicações." + +#. type: Bullet: '- ' +#: ../src/guide/concept/configuration.md +msgid "Registration depends on optional classes or environment-specific decisions." +msgstr "O registro depende de classes opcionais ou de decisões específicas do ambiente." + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "Use a factory class when construction logic belongs to one service. A factory returns an object. A service provider returns definitions for several related services." +msgstr "Use uma classe factory quando a lógica de construção pertence a um único serviço. Uma factory retorna um objeto. Um service provider retorna definições para vários serviços relacionados." + +#. type: Fenced code block (php) +#: ../src/guide/concept/configuration.md +#, no-wrap +msgid "" +"/* @var array $params */\n" +"\n" +"// ...\n" +"use App\\Provider\\CacheProvider;\n" +"use App\\Provider\\MiddlewareProvider;\n" +"// ...\n" +"\n" +"return [\n" +" // ...\n" +" 'yiisoft/yii-web/middleware' => MiddlewareProvider::class,\n" +" 'yiisoft/cache/cache' => new CacheProvider($params['yiisoft/cache-file']['file-cache']['path']),\n" +" // ...\n" +"];\n" +msgstr "" +"/* @var array $params */\n" +"\n" +"// ...\n" +"use App\\Provider\\CacheProvider;\n" +"use App\\Provider\\MiddlewareProvider;\n" +"// ...\n" +"\n" +"return [\n" +" // ...\n" +" 'yiisoft/yii-web/middleware' => MiddlewareProvider::class,\n" +" 'yiisoft/cache/cache' => new CacheProvider($params['yiisoft/cache-file']['file-cache']['path']),\n" +" // ...\n" +"];\n" + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "In this config keys are provider names. By convention these are `vendor/package-name/provider-name`. Values are provider class names or provider instances. These classes could be either created in the project itself or provided by a package." +msgstr "Nesta configuração, as chaves são os nomes dos providers. Por convenção, eles seguem o formato `vendor/package-name/provider-name`. Os valores são nomes de classes de provider ou instâncias de provider. Essas classes podem ser criadas no próprio projeto ou fornecidas por um pacote." + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "If you need to configure some options for a service, similar to direct container configuration, take values from `$params` and pass them to providers." +msgstr "Se você precisar configurar algumas opções de um serviço, da mesma forma que na configuração direta do container, pegue os valores de `$params` e passe-os aos providers." + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "Provider should implement `Yiisoft\\Di\\ServiceProviderInterface`. Below is a provider for a cache service:" +msgstr "O provider deve implementar `Yiisoft\\Di\\ServiceProviderInterface`. Abaixo está um provider para um serviço de cache:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/configuration.md +#, no-wrap +msgid "" +"use Psr\\Container\\ContainerInterface;\n" +"use Psr\\SimpleCache\\CacheInterface;\n" +"use Yiisoft\\Aliases\\Aliases;\n" +"use Yiisoft\\Cache\\Cache;\n" +"use Yiisoft\\Cache\\CacheInterface as YiiCacheInterface;\n" +"use Yiisoft\\Cache\\File\\FileCache;\n" +"use Yiisoft\\Di\\ServiceProviderInterface;\n" +"\n" +"final readonly class CacheProvider implements ServiceProviderInterface\n" +"{\n" +" public function __construct(\n" +" private string $cachePath = '@runtime/cache'\n" +" )\n" +" {\n" +" }\n" +"\n" +" public function getDefinitions(): array\n" +" {\n" +" return [\n" +" CacheInterface::class => function (ContainerInterface $container) {\n" +" $aliases = $container->get(Aliases::class);\n" +"\n" +" return new FileCache($aliases->get($this->cachePath));\n" +" },\n" +" YiiCacheInterface::class => Cache::class,\n" +" ];\n" +" }\n" +"\n" +" public function getExtensions(): array\n" +" {\n" +" return [];\n" +" }\n" +"}\n" +msgstr "" +"use Psr\\Container\\ContainerInterface;\n" +"use Psr\\SimpleCache\\CacheInterface;\n" +"use Yiisoft\\Aliases\\Aliases;\n" +"use Yiisoft\\Cache\\Cache;\n" +"use Yiisoft\\Cache\\CacheInterface as YiiCacheInterface;\n" +"use Yiisoft\\Cache\\File\\FileCache;\n" +"use Yiisoft\\Di\\ServiceProviderInterface;\n" +"\n" +"final readonly class CacheProvider implements ServiceProviderInterface\n" +"{\n" +" public function __construct(\n" +" private string $cachePath = '@runtime/cache'\n" +" )\n" +" {\n" +" }\n" +"\n" +" public function getDefinitions(): array\n" +" {\n" +" return [\n" +" CacheInterface::class => function (ContainerInterface $container) {\n" +" $aliases = $container->get(Aliases::class);\n" +"\n" +" return new FileCache($aliases->get($this->cachePath));\n" +" },\n" +" YiiCacheInterface::class => Cache::class,\n" +" ];\n" +" }\n" +"\n" +" public function getExtensions(): array\n" +" {\n" +" return [];\n" +" }\n" +"}\n" + +#. type: Title ## +#: ../src/guide/concept/configuration.md ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "Routes" +msgstr "Rotas" + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "You can configure how the web application responds to certain URLs in `config/common/routes.php`:" +msgstr "Você pode configurar como a aplicação web responde a determinadas URLs em `config/common/routes.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/configuration.md ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"use App\\Web;\n" +"use Yiisoft\\Router\\Group;\n" +"use Yiisoft\\Router\\Route;\n" +"\n" +"return [\n" +" Group::create()\n" +" ->routes(\n" +" Route::get('/')\n" +" ->action(Web\\HomePage\\Action::class)\n" +" ->name('home'),\n" +" ),\n" +"];\n" +msgstr "" +"use App\\Web;\n" +"use Yiisoft\\Router\\Group;\n" +"use Yiisoft\\Router\\Route;\n" +"\n" +"return [\n" +" Group::create()\n" +" ->routes(\n" +" Route::get('/')\n" +" ->action(Web\\HomePage\\Action::class)\n" +" ->name('home'),\n" +" ),\n" +"];\n" + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "Read more about it in [\"Routes\"](../runtime/routing.md)." +msgstr "Leia mais sobre isso em [\"Rotas\"](../runtime/routing.md)." + +#. type: Title ## +#: ../src/guide/concept/configuration.md ../src/guide/concept/events.md ../src/guide/structure/designing-packages.md ../src/internals/022-config-groups.md +#, no-wrap +msgid "Events" +msgstr "Eventos" + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "Many services emit certain events that you can attach to. The default template defines three event config groups in `config/configuration.php`: `events`, `events-web`, and `events-console`. They are empty by default, but you can populate them inline or point them to event config files." +msgstr "Muitos serviços emitem eventos aos quais você pode se associar. O template padrão define três grupos de configuração de eventos em `config/configuration.php`: `events`, `events-web` e `events-console`. Eles vêm vazios por padrão, mas você pode preenchê-los inline ou apontá-los para arquivos de configuração de eventos." + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "The configuration is an array where keys are event names and values are arrays of handlers:" +msgstr "A configuração é um array em que as chaves são os nomes dos eventos e os valores são arrays de handlers:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/configuration.md +#, no-wrap +msgid "" +"return [\n" +" EventName::class => [\n" +" // Just a regular closure, it will be called from the Dispatcher \"as is\".\n" +" static fn (EventName $event) => someStuff($event),\n" +" \n" +" // A regular closure with an extra dependency. All the parameters after the first one (the event itself)\n" +" // will be resolved from your DI container within `yiisoft/injector`.\n" +" static fn (EventName $event, DependencyClass $dependency) => someStuff($event),\n" +" \n" +" // An example with a regular callable. If the `staticMethodName` method has some dependencies,\n" +" // they will be resolved the same way as in the earlier example.\n" +" [SomeClass::class, 'staticMethodName'],\n" +" \n" +" // Non-static methods are allowed too. In this case, `SomeClass` will be instantiated by your DI container.\n" +" [SomeClass::class, 'methodName'],\n" +" \n" +" // An object of a class with the `__invoke` method implemented\n" +" new InvokableClass(),\n" +" \n" +" // In this case, the `InvokableClass` with the `__invoke` method will be instantiated by your DI container\n" +" InvokableClass::class,\n" +" \n" +" // Any invokable class definition may be here as long as `$container->has('the definition')` is true.\n" +" 'di-alias'\n" +" ],\n" +"];\n" +msgstr "" +"return [\n" +" EventName::class => [\n" +" // Uma closure comum, que será chamada pelo Dispatcher \"como está\".\n" +" static fn (EventName $event) => someStuff($event),\n" +" \n" +" // Uma closure comum com uma dependência extra. Todos os parâmetros depois do primeiro (o próprio evento)\n" +" // serão resolvidos pelo seu container de DI por meio do `yiisoft/injector`.\n" +" static fn (EventName $event, DependencyClass $dependency) => someStuff($event),\n" +" \n" +" // Um exemplo com um callable comum. Se o método `staticMethodName` tiver dependências,\n" +" // elas serão resolvidas da mesma forma que no exemplo anterior.\n" +" [SomeClass::class, 'staticMethodName'],\n" +" \n" +" // Métodos não estáticos também são permitidos. Nesse caso, `SomeClass` será instanciada pelo seu container de DI.\n" +" [SomeClass::class, 'methodName'],\n" +" \n" +" // Um objeto de uma classe que implementa o método `__invoke`\n" +" new InvokableClass(),\n" +" \n" +" // Nesse caso, a `InvokableClass` com o método `__invoke` será instanciada pelo seu container de DI\n" +" InvokableClass::class,\n" +" \n" +" // Qualquer definição de classe invocável pode estar aqui, desde que `$container->has('the definition')` seja true.\n" +" 'di-alias'\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "Read more about it in [\"Events\"](events.md)." +msgstr "Leia mais sobre isso em [\"Eventos\"](events.md)." + +#. type: Title ## +#: ../src/guide/concept/configuration.md ../src/guide/structure/designing-packages.md ../src/internals/022-config-groups.md +#, no-wrap +msgid "Parameters" +msgstr "Parâmetros" + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "Base parameters are stored in `config/common/params.php`. They are then extended by `config/web/params.php`, `config/console/params.php`, and environment-specific files under `config/environments/`." +msgstr "Os parâmetros base ficam em `config/common/params.php`. Depois, eles são estendidos por `config/web/params.php`, `config/console/params.php` e pelos arquivos específicos de cada ambiente em `config/environments/`." + +#. type: Plain text +#: ../src/guide/concept/configuration.md +#, no-wrap +msgid "" +"> [!TIP]\n" +"> Don't use parameters, constants, or environment variables directly in your application, configure\n" +"> services instead.\n" +msgstr "" +"> [!TIP]\n" +"> Não use parâmetros, constantes ou variáveis de ambiente diretamente na sua aplicação; em vez disso, configure\n" +"> os serviços.\n" + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "The default application `common/params.php` looks like the following:" +msgstr "O `common/params.php` da aplicação padrão é assim:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/configuration.md +#, no-wrap +msgid "" +" require __DIR__ . '/application.php',\n" +"\n" +" 'yiisoft/aliases' => [\n" +" 'aliases' => require __DIR__ . '/aliases.php',\n" +" ],\n" +"\n" +" 'yiisoft/view' => [\n" +" 'basePath' => null,\n" +" 'parameters' => [\n" +" 'assetManager' => Reference::to(AssetManager::class),\n" +" 'applicationParams' => Reference::to(ApplicationParams::class),\n" +" 'aliases' => Reference::to(Aliases::class),\n" +" 'urlGenerator' => Reference::to(UrlGeneratorInterface::class),\n" +" 'currentRoute' => Reference::to(CurrentRoute::class),\n" +" ],\n" +" ],\n" +"\n" +" 'yiisoft/yii-view-renderer' => [\n" +" 'viewPath' => null,\n" +" 'layout' => '@src/Web/Shared/Layout/Main/layout.php',\n" +" 'injections' => [\n" +" Reference::to(CsrfViewInjection::class),\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +" require __DIR__ . '/application.php',\n" +"\n" +" 'yiisoft/aliases' => [\n" +" 'aliases' => require __DIR__ . '/aliases.php',\n" +" ],\n" +"\n" +" 'yiisoft/view' => [\n" +" 'basePath' => null,\n" +" 'parameters' => [\n" +" 'assetManager' => Reference::to(AssetManager::class),\n" +" 'applicationParams' => Reference::to(ApplicationParams::class),\n" +" 'aliases' => Reference::to(Aliases::class),\n" +" 'urlGenerator' => Reference::to(UrlGeneratorInterface::class),\n" +" 'currentRoute' => Reference::to(CurrentRoute::class),\n" +" ],\n" +" ],\n" +"\n" +" 'yiisoft/yii-view-renderer' => [\n" +" 'viewPath' => null,\n" +" 'layout' => '@src/Web/Shared/Layout/Main/layout.php',\n" +" 'injections' => [\n" +" Reference::to(CsrfViewInjection::class),\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "For convenience, there is a naming convention about parameters:" +msgstr "Por conveniência, existe uma convenção de nomes para os parâmetros:" + +#. type: Bullet: '1. ' +#: ../src/guide/concept/configuration.md +msgid "Group parameters package name such as `yiisoft/cache-file`." +msgstr "Agrupe os parâmetros pelo nome do pacote, como em `yiisoft/cache-file`." + +#. type: Bullet: '2. ' +#: ../src/guide/concept/configuration.md +msgid "In case parameters are for the application itself, as in `application`, skip package prefix." +msgstr "Se os parâmetros forem da própria aplicação, como em `application`, omita o prefixo do pacote." + +#. type: Bullet: '3. ' +#: ../src/guide/concept/configuration.md +msgid "In case there are many services in the package, such as `file-target` and `file-rotator` in `yiisoft/log-target-file` package, group parameters by service name." +msgstr "Se houver muitos serviços no pacote, como `file-target` e `file-rotator` no pacote `yiisoft/log-target-file`, agrupe os parâmetros pelo nome do serviço." + +#. type: Bullet: '4. ' +#: ../src/guide/concept/configuration.md +msgid "Use `enabled` as parameter name to be able to disable or enable a service, such as `yiisoft/yii-debug`." +msgstr "Use `enabled` como nome de parâmetro para poder desabilitar ou habilitar um serviço, como em `yiisoft/yii-debug`." + +#. type: Title ### +#: ../src/guide/concept/configuration.md +#, no-wrap +msgid "Package configs" +msgstr "Configurações de pacotes" + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "Config plugin does not copy vendor package configs automatically. It loads them directly from `vendor/` as the vendor layer and combines them with the root package and environment-specific layers." +msgstr "O plugin de configuração não copia automaticamente as configurações dos pacotes em vendor. Ele as carrega diretamente de `vendor/` como camada vendor e as combina com as camadas do pacote raiz e específicas de cada ambiente." + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "If you want to customize a package config file in your application, use the `yii-config-copy` Composer command to copy it into your `config/` directory, usually under `config/packages/`. Once copied, the file becomes part of the root package layer, so it can override vendor defaults." +msgstr "Se você quiser personalizar um arquivo de configuração de um pacote na sua aplicação, use o comando do Composer `yii-config-copy` para copiá-lo para a sua pasta `config/`, normalmente em `config/packages/`. Depois de copiado, o arquivo passa a fazer parte da camada do pacote raiz e pode sobrescrever os padrões de vendor." + +#. type: Plain text +#: ../src/guide/concept/configuration.md +msgid "The merge plan stored in `.merge-plan.php` defines how config groups are assembled. If you add new config files or directories and update the root package configuration, rebuild the merge plan with `composer yii-config-rebuild`." +msgstr "O merge plan guardado em `.merge-plan.php` define como os grupos de configuração são montados. Se você adicionar novos arquivos ou pastas de configuração e atualizar a configuração do pacote raiz, reconstrua o merge plan com `composer yii-config-rebuild`." diff --git a/_translations/po/pt-BR/guide_concept_di-container.md.po b/_translations/po/pt-BR/guide_concept_di-container.md.po new file mode 100644 index 00000000..1b1b9559 --- /dev/null +++ b/_translations/po/pt-BR/guide_concept_di-container.md.po @@ -0,0 +1,674 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-06-05 20:33+0000\n" +"PO-Revision-Date: 2026-06-05 20:33+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md ../src/guide/concept/autoloading.md ../src/guide/concept/di-container.md ../src/guide/security/best-practices.md ../src/guide/structure/domain.md ../src/guide/tutorial/console-applications.md ../src/internals/004-namespaces.md ../src/internals/007-exceptions.md ../src/internals/008-interfaces.md +#, no-wrap +msgid "References" +msgstr "Referências" + +#. type: Title # +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "Dependency injection and container" +msgstr "Injeção de dependência e container" + +#. type: Title ## +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "Dependency injection" +msgstr "Injeção de dependência" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "There are two ways of re-using things in OOP: inheritance and composition." +msgstr "Há duas formas de reaproveitar código em OOP: herança e composição." + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "Inheritance is simple:" +msgstr "A herança é simples:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "" +"class Cache\n" +"{\n" +" public function getCachedValue($key)\n" +" {\n" +" // ..\n" +" }\n" +"}\n" +"\n" +"final readonly class CachedWidget extends Cache\n" +"{\n" +" public function render(): string\n" +" {\n" +" $output = $this->getCachedValue('cachedWidget');\n" +" if ($output !== null) {\n" +" return $output;\n" +" }\n" +" // ... \n" +" }\n" +"}\n" +msgstr "" +"class Cache\n" +"{\n" +" public function getCachedValue($key)\n" +" {\n" +" // ..\n" +" }\n" +"}\n" +"\n" +"final readonly class CachedWidget extends Cache\n" +"{\n" +" public function render(): string\n" +" {\n" +" $output = $this->getCachedValue('cachedWidget');\n" +" if ($output !== null) {\n" +" return $output;\n" +" }\n" +" // ... \n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "The issue here is that these two are becoming unnecessarily coupled or inter-dependent, making them more fragile." +msgstr "O problema aqui é que essas duas classes ficam acopladas ou interdependentes sem necessidade, o que as torna mais frágeis." + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "Another way to handle this is composition:" +msgstr "Outra forma de resolver isso é a composição:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "" +"interface CacheInterface\n" +"{\n" +" public function getCachedValue($key);\n" +"}\n" +"\n" +"final readonly class Cache implements CacheInterface\n" +"{\n" +" public function getCachedValue($key)\n" +" {\n" +" // ..\n" +" }\n" +"}\n" +"\n" +"final readonly class CachedWidget\n" +"{\n" +" public function __construct(\n" +" private CacheInterface $cache\n" +" )\n" +" {\n" +" }\n" +" \n" +" public function render(): string\n" +" {\n" +" $output = $this->cache->getCachedValue('cachedWidget');\n" +" if ($output !== null) {\n" +" return $output;\n" +" }\n" +" // ... \n" +" }\n" +"}\n" +msgstr "" +"interface CacheInterface\n" +"{\n" +" public function getCachedValue($key);\n" +"}\n" +"\n" +"final readonly class Cache implements CacheInterface\n" +"{\n" +" public function getCachedValue($key)\n" +" {\n" +" // ..\n" +" }\n" +"}\n" +"\n" +"final readonly class CachedWidget\n" +"{\n" +" public function __construct(\n" +" private CacheInterface $cache\n" +" )\n" +" {\n" +" }\n" +" \n" +" public function render(): string\n" +" {\n" +" $output = $this->cache->getCachedValue('cachedWidget');\n" +" if ($output !== null) {\n" +" return $output;\n" +" }\n" +" // ... \n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "We've avoided unnecessary inheritance and used `CacheInterface` in the `CacheWidget` to reduce coupling. You can replace cache implementation without changing `CachedWidget` so it's becoming more stable. The less edits are made to the code, the less chance of breaking it." +msgstr "Evitamos a herança desnecessária e usamos `CacheInterface` no `CacheWidget` para reduzir o acoplamento. Você pode trocar a implementação do cache sem alterar o `CachedWidget`, então ele fica mais estável. Quanto menos edições forem feitas no código, menor a chance de quebrá-lo." + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "The `CacheInterface` here is a dependency: a contract our object needs to function. In other words, our object depends on the contract." +msgstr "Aqui, `CacheInterface` é uma dependência: um contrato de que o nosso objeto precisa para funcionar. Em outras palavras, o nosso objeto depende do contrato." + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "The process of putting an instance of a contract into an object (`CachedWidget`) is called dependency injection. There are many ways to perform it:" +msgstr "O processo de colocar uma instância de um contrato dentro de um objeto (`CachedWidget`) se chama injeção de dependência. Há várias formas de fazer isso:" + +#. type: Bullet: '- ' +#: ../src/guide/concept/di-container.md +msgid "Constructor injection. Best for mandatory dependencies." +msgstr "Injeção pelo construtor. A melhor para dependências obrigatórias." + +#. type: Bullet: '- ' +#: ../src/guide/concept/di-container.md +msgid "Method injection. Best for optional dependencies." +msgstr "Injeção por método. A melhor para dependências opcionais." + +#. type: Bullet: '- ' +#: ../src/guide/concept/di-container.md +msgid "Property injection. Better to be avoided in PHP except maybe data transfer objects." +msgstr "Injeção por propriedade. É melhor evitar em PHP, exceto talvez em data transfer objects." + +#. type: Title ### +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "Why use private properties" +msgstr "Por que usar propriedades privadas" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "In the composition example above, note that the `$cache` property is declared as `private`." +msgstr "No exemplo de composição acima, repare que a propriedade `$cache` é declarada como `private`." + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "This approach embraces composition by ensuring objects have well-defined interfaces for interaction rather than direct property access, making the code more maintainable and less prone to certain types of mistakes." +msgstr "Essa abordagem favorece a composição ao garantir que os objetos tenham interfaces bem definidas para interação, em vez de acesso direto às propriedades, o que deixa o código mais fácil de manter e menos sujeito a certos tipos de erro." + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "This design choice provides several benefits:" +msgstr "Essa escolha de design traz vários benefícios:" + +#. type: Bullet: '- ' +#: ../src/guide/concept/di-container.md +msgid "**Encapsulation**: Private properties with getters/setters allow you to control access and make future changes without breaking existing code." +msgstr "**Encapsulamento**: propriedades privadas com getters/setters permitem controlar o acesso e fazer mudanças futuras sem quebrar o código existente." + +#. type: Bullet: '- ' +#: ../src/guide/concept/di-container.md +msgid "**Data integrity**: Setters can validate, normalize, or format values before storing them, ensuring properties contain valid data." +msgstr "**Integridade dos dados**: setters podem validar, normalizar ou formatar valores antes de armazená-los, garantindo que as propriedades contenham dados válidos." + +#. type: Bullet: '- ' +#: ../src/guide/concept/di-container.md +msgid "**Immutability**: Private properties enable immutable object patterns where setter `with*()` methods return new instances rather than modifying the current one." +msgstr "**Imutabilidade**: propriedades privadas permitem padrões de objetos imutáveis, em que os métodos `with*()` retornam novas instâncias em vez de modificar a atual." + +#. type: Bullet: '- ' +#: ../src/guide/concept/di-container.md +msgid "**Flexibility**: You can create read-only or write-only properties or add additional logic to property access later." +msgstr "**Flexibilidade**: você pode criar propriedades somente leitura ou somente escrita, ou acrescentar lógica ao acesso às propriedades mais tarde." + +#. type: Title ## +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "DI container" +msgstr "Container de DI" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "Injecting basic dependencies is straightforward. You're choosing a place where you don't care about dependencies, which is usually an action handler, which you aren't going to unit-test ever, create instances of dependencies needed and pass these to dependent classes." +msgstr "Injetar dependências básicas é simples. Você escolhe um lugar onde não se importa com as dependências, que normalmente é um handler de action, que você nunca vai testar com testes unitários, cria as instâncias das dependências necessárias e as passa para as classes dependentes." + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "It works well when there are few dependencies overall and when there are no nested dependencies. When there are many and each dependency has dependencies itself, instantiating the whole hierarchy becomes a tedious process, which requires lots of code and may lead to hardly debuggable mistakes." +msgstr "Isso funciona bem quando há poucas dependências no total e quando não há dependências aninhadas. Quando há muitas e cada dependência tem as suas próprias dependências, instanciar a hierarquia inteira se torna um processo tedioso, que exige muito código e pode levar a erros difíceis de depurar." + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "Additionally, lots of dependencies, such as certain third-party API wrappers, are the same for any class using it. So it makes sense to:" +msgstr "Além disso, muitas dependências, como certos wrappers de APIs de terceiros, são as mesmas para qualquer classe que as use. Então faz sentido:" + +#. type: Bullet: '- ' +#: ../src/guide/concept/di-container.md +msgid "Define how to instantiate such common dependencies." +msgstr "Definir como instanciar essas dependências comuns." + +#. type: Bullet: '- ' +#: ../src/guide/concept/di-container.md +msgid "Instantiate them when required and only once per request." +msgstr "Instanciá-las quando necessário e apenas uma vez por requisição." + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "That's what dependency containers are for." +msgstr "É para isso que servem os containers de dependências." + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "A dependency injection (DI) container is an object that knows how to instantiate and configure objects and all objects they depend on." +msgstr "Um container de injeção de dependência (DI) é um objeto que sabe como instanciar e configurar objetos e todos os objetos dos quais eles dependem." + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "Yii provides the DI container feature through the [yiisoft/di](https://github.com/yiisoft/di) package and [yiisoft/injector](https://github.com/yiisoft/injector) package." +msgstr "O Yii fornece o container de DI por meio dos pacotes [yiisoft/di](https://github.com/yiisoft/di) e [yiisoft/injector](https://github.com/yiisoft/injector)." + +#. type: Plain text +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "" +"> [!NOTE]\n" +"> The container contains only shared instances. If you need a factory, use the dedicated\n" +"> [yiisoft/factory](https://github.com/yiisoft/factory) package.\n" +msgstr "" +"> [!NOTE]\n" +"> O container contém apenas instâncias compartilhadas. Se você precisar de uma factory, use o pacote dedicado\n" +"> [yiisoft/factory](https://github.com/yiisoft/factory).\n" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "" +"> [!TIP]\n" +"> [Martin Fowler's article](https://martinfowler.com/articles/injection.html) has well\n" +"> explained why DI container is useful. Here we will mainly explain the usage of the DI container provided by Yii.\n" +msgstr "" +"> [!TIP]\n" +"> O [artigo de Martin Fowler](https://martinfowler.com/articles/injection.html) explica bem\n" +"> por que um container de DI é útil. Aqui vamos explicar principalmente o uso do container de DI fornecido pelo Yii.\n" + +#. type: Title ### +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "Configuring container" +msgstr "Configurando o container" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "Because to create a new object you need its dependencies, you should register them as early as possible. You can do it in the application configuration, `config/web.php`. For the following service:" +msgstr "Como para criar um novo objeto você precisa das dependências dele, registre-as o quanto antes. Você pode fazer isso na configuração da aplicação, `config/web.php`. Para o seguinte serviço:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "" +"final class MyService implements MyServiceInterface\n" +"{\n" +" public function __construct(int $amount)\n" +" {\n" +" }\n" +"\n" +" public function setDiscount(int $discount): void\n" +" {\n" +" \n" +" }\n" +"}\n" +msgstr "" +"final class MyService implements MyServiceInterface\n" +"{\n" +" public function __construct(int $amount)\n" +" {\n" +" }\n" +"\n" +" public function setDiscount(int $discount): void\n" +" {\n" +" \n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "configuration could be:" +msgstr "a configuração poderia ser:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "" +"return [\n" +" MyServiceInterface::class => [\n" +" 'class' => MyService::class,\n" +" '__construct()' => [42],\n" +" 'setDiscount()' => [10],\n" +" ],\n" +"];\n" +msgstr "" +"return [\n" +" MyServiceInterface::class => [\n" +" 'class' => MyService::class,\n" +" '__construct()' => [42],\n" +" 'setDiscount()' => [10],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "That's equal to the following:" +msgstr "Isso equivale ao seguinte:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "" +"$myService = new MyService(42);\n" +"$myService->setDiscount(10);\n" +msgstr "" +"$myService = new MyService(42);\n" +"$myService->setDiscount(10);\n" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "You can provide arguments with names as well:" +msgstr "Você também pode passar argumentos com nomes:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "" +"return [\n" +" MyServiceInterface::class => [\n" +" 'class' => MyService::class,\n" +" '__construct()' => ['amount' => 42],\n" +" 'setDiscount()' => ['discount' => 10],\n" +" ],\n" +"];\n" +msgstr "" +"return [\n" +" MyServiceInterface::class => [\n" +" 'class' => MyService::class,\n" +" '__construct()' => ['amount' => 42],\n" +" 'setDiscount()' => ['discount' => 10],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "That's basically it. You define a map of interfaces to classes and define how to configure them. When an interface is requested in constructor or elsewhere, container creates an instance of a class and configures it as per the configuration:" +msgstr "Basicamente é isso. Você define um mapa de interfaces para classes e define como configurá-las. Quando uma interface é solicitada no construtor ou em outro lugar, o container cria uma instância da classe e a configura conforme a configuração:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "" +"final class MyAction\n" +"{\n" +" public function __construct(\n" +" private readonly MyServiceInterface $myService\n" +" ) {\n" +" }\n" +" \n" +" public function __invoke() \n" +" {\n" +" $this->myService->doSomething();\n" +" }\n" +"}\n" +msgstr "" +"final class MyAction\n" +"{\n" +" public function __construct(\n" +" private readonly MyServiceInterface $myService\n" +" ) {\n" +" }\n" +" \n" +" public function __invoke() \n" +" {\n" +" $this->myService->doSomething();\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "There are extra methods of declaring dependency configuration." +msgstr "Há outras formas de declarar a configuração de dependências." + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "For simplest cases where there are no custom values needed and all the constructor dependencies could be obtained from a container, you can use a class name as a value." +msgstr "Nos casos mais simples, em que não são necessários valores personalizados e todas as dependências do construtor podem ser obtidas do container, você pode usar um nome de classe como valor." + +#. type: Fenced code block (php) +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "" +"interface EngineInterface\n" +"{\n" +" \n" +"}\n" +"\n" +"final class EngineMarkOne implements EngineInterface\n" +"{\n" +" public function __construct(CacheInterface $cache) {\n" +" } \n" +"}\n" +msgstr "" +"interface EngineInterface\n" +"{\n" +" \n" +"}\n" +"\n" +"final class EngineMarkOne implements EngineInterface\n" +"{\n" +" public function __construct(CacheInterface $cache) {\n" +" } \n" +"}\n" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "In the above example, if we already have cache defined in the container, nothing besides the class name is needed:" +msgstr "No exemplo acima, se já houver um cache definido no container, não é preciso nada além do nome da classe:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "" +"return [\n" +" // declare a class for an interface, resolve dependencies automatically\n" +" EngineInterface::class => EngineMarkOne::class,\n" +"];\n" +msgstr "" +"return [\n" +" // declara uma classe para uma interface, resolvendo as dependências automaticamente\n" +" EngineInterface::class => EngineMarkOne::class,\n" +"];\n" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "If you have a dependency that has public properties, you can configure it as well." +msgstr "Se você tiver uma dependência com propriedades públicas, também pode configurá-la." + +#. type: Fenced code block (php) +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "" +"final class NameProvider\n" +"{\n" +" public string $name;\n" +"}\n" +msgstr "" +"final class NameProvider\n" +"{\n" +" public string $name;\n" +"}\n" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "Here's how to do it for the example above:" +msgstr "Veja como fazer isso no exemplo acima:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "" +"NameProvider::class => [\n" +" 'class' => NameProvider::class, \n" +" '$name' => 'Alex',\n" +"],\n" +msgstr "" +"NameProvider::class => [\n" +" 'class' => NameProvider::class, \n" +" '$name' => 'Alex',\n" +"],\n" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "In this example, you may notice `NameProvider` specified twice. The key is what you may request as dependency and the value is how to create it." +msgstr "Neste exemplo, você pode notar que `NameProvider` aparece duas vezes. A chave é o que você pode solicitar como dependência, e o valor é como criá-la." + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "If the configuration is tricky and requires some logic, a closure can be used:" +msgstr "Se a configuração for complicada e exigir alguma lógica, você pode usar uma closure:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "" +"MyServiceInterface::class => static function(ContainerInterface $container) {\n" +" return new MyService($container->get('db'));\n" +"},\n" +msgstr "" +"MyServiceInterface::class => static function(ContainerInterface $container) {\n" +" return new MyService($container->get('db'));\n" +"},\n" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "Additionally, to `ContainerInterface`, you can request any registered service directly as a closure parameter. The injector will automatically resolve and inject these:" +msgstr "Além do `ContainerInterface`, você pode solicitar qualquer serviço registrado diretamente como parâmetro da closure. O injector vai resolvê-los e injetá-los automaticamente:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "" +"MyServiceInterface::class => static function(ConnectionInterface $db) {\n" +" return new MyService($db);\n" +"},\n" +msgstr "" +"MyServiceInterface::class => static function(ConnectionInterface $db) {\n" +" return new MyService($db);\n" +"},\n" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "It's possible to use a static method call:" +msgstr "É possível usar a chamada de um método estático:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "MyServiceInterface::class => [MyFactory::class, 'create'],\n" +msgstr "MyServiceInterface::class => [MyFactory::class, 'create'],\n" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "Or an instance of an object:" +msgstr "Ou uma instância de um objeto:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "MyServiceInterface::class => new MyService(),\n" +msgstr "MyServiceInterface::class => new MyService(),\n" + +#. type: Title ### +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "Injecting dependencies properly" +msgstr "Injetando dependências corretamente" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "Directly referencing a container in a class is a bad idea since the code becomes non-generic, coupled to the container interface and, what's worse, dependencies are becoming hidden. Because of that, Yii inverts the control by automatically injecting objects from a container in some constructors and methods based on method argument types." +msgstr "Referenciar o container diretamente em uma classe é uma má ideia, porque o código deixa de ser genérico, fica acoplado à interface do container e, pior ainda, as dependências ficam escondidas. Por isso, o Yii inverte o controle, injetando automaticamente objetos do container em alguns construtores e métodos com base nos tipos dos argumentos." + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "This is primarily done in constructor and handing method of action handlers:" +msgstr "Isso é feito principalmente no construtor e no método de tratamento dos handlers de action:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "" +"use \\Yiisoft\\Cache\\CacheInterface;\n" +"\n" +"final readonly class MyController\n" +"{\n" +" public function __construct(\n" +" private CacheInterface $cache\n" +" )\n" +" {\n" +" $this->cache = $cache; \n" +" }\n" +"\n" +" public function actionDashboard(RevenueReport $report)\n" +" {\n" +" $reportData = $this->cache->getOrSet('revenue_report', function() use ($report) {\n" +" return $report->getData(); \n" +" });\n" +"\n" +" return $this->render('dashboard', [\n" +" 'reportData' => $reportData,\n" +" ]);\n" +" }\n" +"}\n" +msgstr "" +"use \\Yiisoft\\Cache\\CacheInterface;\n" +"\n" +"final readonly class MyController\n" +"{\n" +" public function __construct(\n" +" private CacheInterface $cache\n" +" )\n" +" {\n" +" $this->cache = $cache; \n" +" }\n" +"\n" +" public function actionDashboard(RevenueReport $report)\n" +" {\n" +" $reportData = $this->cache->getOrSet('revenue_report', function() use ($report) {\n" +" return $report->getData(); \n" +" });\n" +"\n" +" return $this->render('dashboard', [\n" +" 'reportData' => $reportData,\n" +" ]);\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "Since it's [yiisoft/injector](https://github.com/yiisoft/injector) that instantiates and calls action handler, it checks the constructor and method argument types, gets dependencies of these types from a container and passes them as arguments. That's usually called auto-wiring. It happens for sub-dependencies as well, that's if you don't give dependency explicitly, the container would check if it has such a dependency first. It's enough to declare a dependency you need, and it would be got from a container automatically." +msgstr "Como é o [yiisoft/injector](https://github.com/yiisoft/injector) que instancia e chama o handler de action, ele verifica os tipos dos argumentos do construtor e do método, obtém do container as dependências desses tipos e as passa como argumentos. Isso normalmente se chama autowiring. Acontece também com as subdependências: se você não fornecer uma dependência explicitamente, o container vai verificar primeiro se tem essa dependência. Basta declarar a dependência de que você precisa, e ela será obtida do container automaticamente." + +#. type: Bullet: '- ' +#: ../src/guide/concept/di-container.md +msgid "[Inversion of Control Containers and the Dependency Injection pattern by Martin Fowler](https://martinfowler.com/articles/injection.html)" +msgstr "[Inversion of Control Containers and the Dependency Injection pattern, de Martin Fowler](https://martinfowler.com/articles/injection.html)" diff --git a/_translations/po/pt-BR/guide_concept_events.md.po b/_translations/po/pt-BR/guide_concept_events.md.po new file mode 100644 index 00000000..57dd1600 --- /dev/null +++ b/_translations/po/pt-BR/guide_concept_events.md.po @@ -0,0 +1,399 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-06-05 20:33+0000\n" +"PO-Revision-Date: 2026-06-05 20:33+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/guide/concept/configuration.md ../src/guide/concept/events.md ../src/guide/structure/designing-packages.md ../src/internals/022-config-groups.md +#, no-wrap +msgid "Events" +msgstr "Eventos" + +#. type: Plain text +#: ../src/guide/concept/events.md +msgid "Events allow you to run custom code at certain execution points without changing the code that emits the event. You attach a custom code called a listener to an event. When the event is dispatched, the listener is executed." +msgstr "Eventos permitem executar código personalizado em determinados pontos da execução, sem alterar o código que emite o evento. Você associa a um evento um código personalizado chamado listener. Quando o evento é disparado, o listener é executado." + +#. type: Plain text +#: ../src/guide/concept/events.md +msgid "For example, when a user signs up, you need to send a welcome email. You can do it in `SignupService`. Later, when you also need to resize the user's avatar image, the service has to know about that too." +msgstr "Por exemplo, quando um usuário se cadastra, você precisa enviar um e-mail de boas-vindas. Dá para fazer isso no `SignupService`. Mais tarde, quando você também precisar redimensionar a imagem de avatar do usuário, o serviço vai ter que saber disso também." + +#. type: Plain text +#: ../src/guide/concept/events.md +msgid "A cleaner flow is to dispatch a `UserSignedUp` event from `SignupService`. The welcome email sender and the avatar processor listen to this event. Additional signup-related work can be added by registering another listener." +msgstr "Um fluxo mais limpo é disparar um evento `UserSignedUp` a partir do `SignupService`. O remetente do e-mail de boas-vindas e o processador de avatar escutam esse evento. Trabalho adicional relacionado ao cadastro pode ser incluído registrando outro listener." + +#. type: Plain text +#: ../src/guide/concept/events.md +msgid "Yii uses [yiisoft/yii-event](https://github.com/yiisoft/yii-event) for application event configuration. It builds on the [yiisoft/event-dispatcher](https://github.com/yiisoft/event-dispatcher) package, which provides a [PSR-14](https://www.php-fig.org/psr/psr-14/) compatible event dispatcher." +msgstr "O Yii usa o [yiisoft/yii-event](https://github.com/yiisoft/yii-event) para a configuração de eventos da aplicação. Ele é construído sobre o pacote [yiisoft/event-dispatcher](https://github.com/yiisoft/event-dispatcher), que fornece um event dispatcher compatível com [PSR-14](https://www.php-fig.org/psr/psr-14/)." + +#. type: Title ## +#: ../src/guide/concept/events.md +#, no-wrap +msgid "Event classes" +msgstr "Classes de evento" + +#. type: Plain text +#: ../src/guide/concept/events.md +msgid "An event is an object. It usually contains data that listeners need:" +msgstr "Um evento é um objeto. Normalmente ele contém os dados de que os listeners precisam:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/events.md +#, no-wrap +msgid "" +"final readonly class UserSignedUp\n" +"{\n" +" public function __construct(\n" +" public SignupForm $form,\n" +" ) {}\n" +"}\n" +msgstr "" +"final readonly class UserSignedUp\n" +"{\n" +" public function __construct(\n" +" public SignupForm $form,\n" +" ) {}\n" +"}\n" + +#. type: Title ## +#: ../src/guide/concept/events.md +#, no-wrap +msgid "Event listeners" +msgstr "Listeners de eventos" + +#. type: Plain text +#: ../src/guide/concept/events.md +msgid "An event listener is a [PHP callable](https://www.php.net/manual/en/language.types.callable.php) that receives an event:" +msgstr "Um listener de evento é um [callable do PHP](https://www.php.net/manual/en/language.types.callable.php) que recebe um evento:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/events.md +#, no-wrap +msgid "" +"static function (UserSignedUp $event): void {\n" +" // Send a welcome email.\n" +"}\n" +msgstr "" +"static function (UserSignedUp $event): void {\n" +" // Envia um e-mail de boas-vindas.\n" +"}\n" + +#. type: Plain text +#: ../src/guide/concept/events.md +msgid "You can also use an invokable class:" +msgstr "Você também pode usar uma classe invocável:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/events.md +#, no-wrap +msgid "" +"final readonly class WelcomeEmailSender\n" +"{\n" +" public function __invoke(UserSignedUp $event): void\n" +" {\n" +" // Send a welcome email.\n" +" }\n" +"}\n" +msgstr "" +"final readonly class WelcomeEmailSender\n" +"{\n" +" public function __invoke(UserSignedUp $event): void\n" +" {\n" +" // Envia um e-mail de boas-vindas.\n" +" }\n" +"}\n" + +#. type: Title ## +#: ../src/guide/concept/events.md +#, no-wrap +msgid "Configuring event listeners" +msgstr "Configurando listeners de eventos" + +#. type: Plain text +#: ../src/guide/concept/events.md +msgid "In an application, configure listeners in:" +msgstr "Em uma aplicação, configure os listeners em:" + +#. type: Bullet: '- ' +#: ../src/guide/concept/events.md +msgid "`config/events.php` for all application types." +msgstr "`config/events.php` para todos os tipos de aplicação." + +#. type: Bullet: '- ' +#: ../src/guide/concept/events.md +msgid "`config/events-web.php` for web application events." +msgstr "`config/events-web.php` para eventos da aplicação web." + +#. type: Bullet: '- ' +#: ../src/guide/concept/events.md +msgid "`config/events-console.php` for console application events." +msgstr "`config/events-console.php` para eventos da aplicação de console." + +#. type: Plain text +#: ../src/guide/concept/events.md +msgid "The configuration is an array where keys are event class names and values are lists of listeners:" +msgstr "A configuração é um array em que as chaves são os nomes das classes de evento e os valores são listas de listeners:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/events.md +#, no-wrap +msgid "" +" [\n" +" WelcomeEmailSender::class,\n" +" static fn (UserSignedUp $event, AvatarProcessor $avatarProcessor) => $avatarProcessor->resize($event->form),\n" +" ],\n" +"];\n" +msgstr "" +" [\n" +" WelcomeEmailSender::class,\n" +" static fn (UserSignedUp $event, AvatarProcessor $avatarProcessor) => $avatarProcessor->resize($event->form),\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/concept/events.md +msgid "The listener may be a closure, a callable array, an invokable object, an invokable class name, or a DI alias. For closure and callable array listeners, parameters after the first event parameter are resolved from the DI container. Invokable class names are instantiated by the container." +msgstr "O listener pode ser uma closure, um array callable, um objeto invocável, o nome de uma classe invocável ou um alias de DI. Para listeners do tipo closure e array callable, os parâmetros depois do primeiro (o evento) são resolvidos pelo container de DI. Nomes de classes invocáveis são instanciados pelo container." + +#. type: Plain text +#: ../src/guide/concept/events.md +msgid "Dependencies are resolved when the event is dispatched." +msgstr "As dependências são resolvidas quando o evento é disparado." + +#. type: Title ## +#: ../src/guide/concept/events.md +#, no-wrap +msgid "Dispatching events" +msgstr "Disparando eventos" + +#. type: Plain text +#: ../src/guide/concept/events.md +msgid "To dispatch an event, use `Psr\\EventDispatcher\\EventDispatcherInterface`:" +msgstr "Para disparar um evento, use `Psr\\EventDispatcher\\EventDispatcherInterface`:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/events.md +#, no-wrap +msgid "" +"use Psr\\EventDispatcher\\EventDispatcherInterface;\n" +"\n" +"final readonly class SignupService\n" +"{\n" +" public function __construct(\n" +" private EventDispatcherInterface $eventDispatcher,\n" +" ) {}\n" +"\n" +" public function signup(SignupForm $form): void\n" +" {\n" +" // Sign up the user.\n" +"\n" +" $this->eventDispatcher->dispatch(new UserSignedUp($form));\n" +" }\n" +"}\n" +msgstr "" +"use Psr\\EventDispatcher\\EventDispatcherInterface;\n" +"\n" +"final readonly class SignupService\n" +"{\n" +" public function __construct(\n" +" private EventDispatcherInterface $eventDispatcher,\n" +" ) {}\n" +"\n" +" public function signup(SignupForm $form): void\n" +" {\n" +" // Cadastra o usuário.\n" +"\n" +" $this->eventDispatcher->dispatch(new UserSignedUp($form));\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/concept/events.md +msgid "The dispatcher asks a listener provider for listeners that match the event and calls them one by one." +msgstr "O dispatcher pede a um listener provider os listeners que correspondem ao evento e os chama um por um." + +#. type: Title ## +#: ../src/guide/concept/events.md +#, no-wrap +msgid "Event listener order" +msgstr "Ordem dos listeners" + +#. type: Plain text +#: ../src/guide/concept/events.md +msgid "When several listeners are configured for the same event, they are called in the order they are listed in the config. If an event implements `Psr\\EventDispatcher\\StoppableEventInterface`, the dispatcher checks `isPropagationStopped()` before calling the next listener. When it returns `true`, the dispatcher stops processing the event." +msgstr "Quando vários listeners são configurados para o mesmo evento, eles são chamados na ordem em que aparecem na configuração. Se um evento implementa `Psr\\EventDispatcher\\StoppableEventInterface`, o dispatcher verifica `isPropagationStopped()` antes de chamar o próximo listener. Quando ele retorna `true`, o dispatcher para de processar o evento." + +#. type: Plain text +#: ../src/guide/concept/events.md +msgid "Keep listeners independent where possible. Ordering is useful for technical needs, but business logic is usually easier to maintain when each listener can run on its own." +msgstr "Mantenha os listeners independentes sempre que possível. A ordem é útil para necessidades técnicas, mas a lógica de negócio costuma ser mais fácil de manter quando cada listener consegue rodar sozinho." + +#. type: Title ## +#: ../src/guide/concept/events.md +#, no-wrap +msgid "Event hierarchy" +msgstr "Hierarquia de eventos" + +#. type: Plain text +#: ../src/guide/concept/events.md +msgid "Events don't have names or wildcard matching. Event class names, interfaces, and inheritance can be used when one listener should handle several related events:" +msgstr "Eventos não têm nomes nem correspondência por curinga. Nomes de classes de evento, interfaces e herança podem ser usados quando um listener precisa tratar vários eventos relacionados:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/events.md +#, no-wrap +msgid "" +"interface DocumentEvent\n" +"{\n" +"}\n" +"\n" +"final readonly class BeforeDocumentProcessed implements DocumentEvent\n" +"{\n" +"}\n" +"\n" +"final readonly class AfterDocumentProcessed implements DocumentEvent\n" +"{\n" +"}\n" +msgstr "" +"interface DocumentEvent\n" +"{\n" +"}\n" +"\n" +"final readonly class BeforeDocumentProcessed implements DocumentEvent\n" +"{\n" +"}\n" +"\n" +"final readonly class AfterDocumentProcessed implements DocumentEvent\n" +"{\n" +"}\n" + +#. type: Plain text +#: ../src/guide/concept/events.md +msgid "With the interface, you can listen to all document-related events:" +msgstr "Com a interface, você pode escutar todos os eventos relacionados a documentos:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/events.md +#, no-wrap +msgid "" +"use Yiisoft\\EventDispatcher\\Provider\\ListenerCollection;\n" +"use Yiisoft\\EventDispatcher\\Provider\\Provider;\n" +"\n" +"$listeners = (new ListenerCollection())\n" +" ->add(static function (DocumentEvent $event): void {\n" +" // Log document events.\n" +" });\n" +"\n" +"$provider = new Provider($listeners);\n" +msgstr "" +"use Yiisoft\\EventDispatcher\\Provider\\ListenerCollection;\n" +"use Yiisoft\\EventDispatcher\\Provider\\Provider;\n" +"\n" +"$listeners = (new ListenerCollection())\n" +" ->add(static function (DocumentEvent $event): void {\n" +" // Registra em log os eventos de documentos.\n" +" });\n" +"\n" +"$provider = new Provider($listeners);\n" + +#. type: Title ## +#: ../src/guide/concept/events.md +#, no-wrap +msgid "Manual listener provider setup" +msgstr "Configuração manual do listener provider" + +#. type: Plain text +#: ../src/guide/concept/events.md +msgid "In an application, use event configuration. For package-level code or tests, you can create a listener provider manually:" +msgstr "Em uma aplicação, use a configuração de eventos. Para código de pacotes ou testes, você pode criar um listener provider manualmente:" + +#. type: Fenced code block (php) +#: ../src/guide/concept/events.md +#, no-wrap +msgid "" +"use Yiisoft\\EventDispatcher\\Dispatcher\\Dispatcher;\n" +"use Yiisoft\\EventDispatcher\\Provider\\ListenerCollection;\n" +"use Yiisoft\\EventDispatcher\\Provider\\Provider;\n" +"\n" +"$listeners = (new ListenerCollection())\n" +" ->add(static function (UserSignedUp $event): void {\n" +" // Send a welcome email.\n" +" });\n" +"\n" +"$provider = new Provider($listeners);\n" +"$dispatcher = new Dispatcher($provider);\n" +"\n" +"$dispatcher->dispatch(new UserSignedUp($form));\n" +msgstr "" +"use Yiisoft\\EventDispatcher\\Dispatcher\\Dispatcher;\n" +"use Yiisoft\\EventDispatcher\\Provider\\ListenerCollection;\n" +"use Yiisoft\\EventDispatcher\\Provider\\Provider;\n" +"\n" +"$listeners = (new ListenerCollection())\n" +" ->add(static function (UserSignedUp $event): void {\n" +" // Envia um e-mail de boas-vindas.\n" +" });\n" +"\n" +"$provider = new Provider($listeners);\n" +"$dispatcher = new Dispatcher($provider);\n" +"\n" +"$dispatcher->dispatch(new UserSignedUp($form));\n" + +#. type: Plain text +#: ../src/guide/concept/events.md +#, no-wrap +msgid "`ListenerCollection::add()` returns a new collection instance. Assign the result when building a collection step by step:\n" +msgstr "`ListenerCollection::add()` retorna uma nova instância da coleção. Atribua o resultado ao montar uma coleção passo a passo:\n" + +#. type: Fenced code block (php) +#: ../src/guide/concept/events.md +#, no-wrap +msgid "" +"$listeners = new ListenerCollection();\n" +"$listeners = $listeners->add(\n" +" static function (UserSignedUp $event): void {\n" +" // Send a welcome email.\n" +" },\n" +" UserSignedUp::class,\n" +");\n" +msgstr "" +"$listeners = new ListenerCollection();\n" +"$listeners = $listeners->add(\n" +" static function (UserSignedUp $event): void {\n" +" // Envia um e-mail de boas-vindas.\n" +" },\n" +" UserSignedUp::class,\n" +");\n" diff --git a/_translations/po/pt-BR/guide_concept_immutability.md.po b/_translations/po/pt-BR/guide_concept_immutability.md.po new file mode 100644 index 00000000..f65ddfee --- /dev/null +++ b/_translations/po/pt-BR/guide_concept_immutability.md.po @@ -0,0 +1,331 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 08:02+0000\n" +"PO-Revision-Date: 2025-12-24 08:02+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/en/guide/concept/immutability.md ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +#, no-wrap +msgid "Immutability" +msgstr "Imutabilidade" + +#. type: Plain text +#: ../src/en/guide/concept/immutability.md +msgid "Immutability means an object's state cannot change after it has been created. Instead of modifying an instance, you create a new instance with the desired changes. This approach is common for value objects such as Money, IDs, and DTOs. It helps to avoid accidental side effects: methods cannot silently change shared state, which makes code easier to reason about." +msgstr "Imutabilidade significa que o estado de um objeto não pode mudar depois que ele é criado. Em vez de modificar uma instância, você cria uma nova instância com as mudanças desejadas. Essa abordagem é comum em value objects como Money, IDs e DTOs. Ela ajuda a evitar efeitos colaterais acidentais: os métodos não conseguem alterar silenciosamente um estado compartilhado, o que torna o código mais fácil de entender." + +#. type: Title ## +#: ../src/en/guide/concept/immutability.md +#, no-wrap +msgid "Mutable pitfalls (what we avoid)" +msgstr "Armadilhas da mutabilidade (o que evitamos)" + +#. type: Fenced code block (php) +#: ../src/en/guide/concept/immutability.md +#, no-wrap +msgid "" +"// A shared base query built once and reused:\n" +"$base = Post::find()->where(['status' => Post::STATUS_PUBLISHED]);\n" +"\n" +"// Somewhere deep in the code we only need one post:\n" +"$one = $base->limit(1)->one(); // mutates the underlying builder (sticky limit!)\n" +"\n" +"// Later we reuse the same $base expecting a full list:\n" +"$list = $base->orderBy(['created_at' => SORT_DESC])->all();\n" +"// Oops: still limited to 1 because the previous limit(1) modified $base.\n" +msgstr "" +"// Uma query base compartilhada, montada uma vez e reutilizada:\n" +"$base = Post::find()->where(['status' => Post::STATUS_PUBLISHED]);\n" +"\n" +"// Em algum lugar profundo do código, precisamos de um só post:\n" +"$one = $base->limit(1)->one(); // altera o builder subjacente (o limit fica grudado!)\n" +"\n" +"// Depois reutilizamos o mesmo $base esperando a lista completa:\n" +"$list = $base->orderBy(['created_at' => SORT_DESC])->all();\n" +"// Ops: continua limitado a 1, porque o limit(1) anterior modificou $base.\n" + +#. type: Title ## +#: ../src/en/guide/concept/immutability.md +#, no-wrap +msgid "Creating an immutable object in PHP" +msgstr "Criando um objeto imutável em PHP" + +#. type: Plain text +#: ../src/en/guide/concept/immutability.md +msgid "There is no direct way to modify an instance, but you can use clone to create a new instance with the desired changes. That is what `with*` methods do." +msgstr "Não há como modificar uma instância diretamente, mas você pode usar clone para criar uma nova instância com as mudanças desejadas. É isso que os métodos `with*` fazem." + +#. type: Fenced code block (php) +#: ../src/en/guide/concept/immutability.md +#, no-wrap +msgid "" +"final class Money\n" +"{\n" +" public function __construct(\n" +" private int $amount,\n" +" private string $currency,\n" +" ) {\n" +" $this->validateAmount($amount);\n" +" $this->validateCurrency($currency);\n" +" }\n" +" \n" +" private function validateAmount(string $amount) \n" +" {\n" +" if ($amount < 0) {\n" +" throw new InvalidArgumentException('Amount must be positive.');\n" +" }\n" +" }\n" +" \n" +" private function validateCurrency(string $currency)\n" +" {\n" +" if (!in_array($currency, ['USD', 'EUR'])) {\n" +" throw new InvalidArgumentException('Invalid currency. Only USD and EUR are supported.');\n" +" }\n" +" } \n" +"\n" +" public function withAmount(int $amount): self\n" +" {\n" +" $this->validateAmount($amount);\n" +" \n" +" if ($amount === $this->amount) {\n" +" return $this;\n" +" }\n" +" \n" +" $clone = clone $this;\n" +" $clone->amount = $amount;\n" +" return $clone;\n" +" }\n" +" \n" +" public function withCurrency(string $currency): self\n" +" {\n" +" $this->validateCurrency($currency);\n" +" \n" +" if ($currency === $this->currency) {\n" +" return $this;\n" +" }\n" +" \n" +" $clone = clone $this;\n" +" $clone->currency = $currency;\n" +" return $clone;\n" +" }\n" +" \n" +" public function amount(): int \n" +" {\n" +" return $this->amount;\n" +" }\n" +" \n" +" public function currency(): string \n" +" {\n" +" return $this->currency;\n" +" }\n" +"\n" +" public function add(self $money): self\n" +" {\n" +" if ($money->currency !== $this->currency) {\n" +" throw new InvalidArgumentException('Currency mismatch. Cannot add money of different currency.');\n" +" }\n" +" return $this->withAmount($this->amount + $money->amount);\n" +" }\n" +"}\n" +"\n" +"$price = new Money(1000, 'USD');\n" +"$discounted = $price->withAmount(800);\n" +"// $price is still 1000 USD, $discounted is 800 USD\n" +msgstr "" +"final class Money\n" +"{\n" +" public function __construct(\n" +" private int $amount,\n" +" private string $currency,\n" +" ) {\n" +" $this->validateAmount($amount);\n" +" $this->validateCurrency($currency);\n" +" }\n" +" \n" +" private function validateAmount(string $amount) \n" +" {\n" +" if ($amount < 0) {\n" +" throw new InvalidArgumentException('Amount must be positive.');\n" +" }\n" +" }\n" +" \n" +" private function validateCurrency(string $currency)\n" +" {\n" +" if (!in_array($currency, ['USD', 'EUR'])) {\n" +" throw new InvalidArgumentException('Invalid currency. Only USD and EUR are supported.');\n" +" }\n" +" } \n" +"\n" +" public function withAmount(int $amount): self\n" +" {\n" +" $this->validateAmount($amount);\n" +" \n" +" if ($amount === $this->amount) {\n" +" return $this;\n" +" }\n" +" \n" +" $clone = clone $this;\n" +" $clone->amount = $amount;\n" +" return $clone;\n" +" }\n" +" \n" +" public function withCurrency(string $currency): self\n" +" {\n" +" $this->validateCurrency($currency);\n" +" \n" +" if ($currency === $this->currency) {\n" +" return $this;\n" +" }\n" +" \n" +" $clone = clone $this;\n" +" $clone->currency = $currency;\n" +" return $clone;\n" +" }\n" +" \n" +" public function amount(): int \n" +" {\n" +" return $this->amount;\n" +" }\n" +" \n" +" public function currency(): string \n" +" {\n" +" return $this->currency;\n" +" }\n" +"\n" +" public function add(self $money): self\n" +" {\n" +" if ($money->currency !== $this->currency) {\n" +" throw new InvalidArgumentException('Currency mismatch. Cannot add money of different currency.');\n" +" }\n" +" return $this->withAmount($this->amount + $money->amount);\n" +" }\n" +"}\n" +"\n" +"$price = new Money(1000, 'USD');\n" +"$discounted = $price->withAmount(800);\n" +"// $price continua 1000 USD, $discounted é 800 USD\n" + +#. type: Bullet: '- ' +#: ../src/en/guide/concept/immutability.md +msgid "We mark the class `final` to prevent subclass mutations; alternatively, design for extension carefully." +msgstr "Marcamos a classe como `final` para impedir mutações por subclasses; como alternativa, projete a extensão com cuidado." + +#. type: Bullet: '- ' +#: ../src/en/guide/concept/immutability.md +msgid "Validate in the constructor and `with*` methods so every instance is always valid." +msgstr "Valide no construtor e nos métodos `with*`, para que toda instância seja sempre válida." + +#. type: Plain text +#: ../src/en/guide/concept/immutability.md +#, no-wrap +msgid "" +"> [!TIP]\n" +"> If you define a simple DTO, you can use modern PHP `readonly` and leave properties `public`. The `readonly` keyword\n" +"> would ensure that the properties cannot be modified after the object is created.\n" +msgstr "" +"> [!TIP]\n" +"> Se você define um DTO simples, pode usar o `readonly` do PHP moderno e deixar as propriedades `public`. A palavra-chave `readonly`\n" +"> garante que as propriedades não possam ser modificadas depois que o objeto é criado.\n" + +#. type: Title ## +#: ../src/en/guide/concept/immutability.md +#, no-wrap +msgid "Using clone (and why it is inexpensive)" +msgstr "Usando clone (e por que é barato)" + +#. type: Plain text +#: ../src/en/guide/concept/immutability.md +msgid "PHP's clone performs a shallow copy of the object. For immutable value objects that contain only scalars or other immutable objects, shallow cloning is enough and fast. In modern PHP, cloning small value objects is inexpensive in both time and memory." +msgstr "O clone do PHP faz uma cópia rasa do objeto. Para value objects imutáveis que contêm apenas escalares ou outros objetos imutáveis, a clonagem rasa é suficiente e rápida. No PHP moderno, clonar value objects pequenos é barato em tempo e em memória." + +#. type: Plain text +#: ../src/en/guide/concept/immutability.md +msgid "If your object holds mutable sub-objects that must also be copied, implement `__clone` to deep-clone them:" +msgstr "Se o seu objeto guarda subobjetos mutáveis que também precisam ser copiados, implemente `__clone` para fazer a clonagem profunda deles:" + +#. type: Fenced code block (php) +#: ../src/en/guide/concept/immutability.md +#, no-wrap +msgid "" +"final class Order\n" +"{\n" +" public function __construct(\n" +" private Money $total\n" +" ) {}\n" +" \n" +" public function total(): Money \n" +" {\n" +" return $this->total;\n" +" }\n" +"\n" +" public function __clone(): void\n" +" {\n" +" // Money is immutable in our example, so a deep clone is not required.\n" +" // If it were mutable, you could do: $this->total = clone $this->total;\n" +" }\n" +"\n" +" public function withTotal(Money $total): self\n" +" {\n" +" $clone = clone $this;\n" +" $clone->total = $total;\n" +" return $clone;\n" +" }\n" +"}\n" +msgstr "" +"final class Order\n" +"{\n" +" public function __construct(\n" +" private Money $total\n" +" ) {}\n" +" \n" +" public function total(): Money \n" +" {\n" +" return $this->total;\n" +" }\n" +"\n" +" public function __clone(): void\n" +" {\n" +" // Money é imutável no nosso exemplo, então a clonagem profunda não é necessária.\n" +" // Se fosse mutável, você poderia fazer: $this->total = clone $this->total;\n" +" }\n" +"\n" +" public function withTotal(Money $total): self\n" +" {\n" +" $clone = clone $this;\n" +" $clone->total = $total;\n" +" return $clone;\n" +" }\n" +"}\n" + +#. type: Title ## +#: ../src/en/guide/concept/immutability.md +#, no-wrap +msgid "Usage style" +msgstr "Estilo de uso" + +#. type: Bullet: '- ' +#: ../src/en/guide/concept/immutability.md +msgid "Build a value object once and pass it around. If you need a change, use a `with*` method that returns a new instance." +msgstr "Crie um value object uma vez e passe-o adiante. Se precisar de uma mudança, use um método `with*` que retorna uma nova instância." + +#. type: Bullet: '- ' +#: ../src/en/guide/concept/immutability.md +msgid "Prefer scalar/immutable fields inside immutable objects; if a field can mutate, isolate it and deep-clone in `__clone` when needed." +msgstr "Prefira campos escalares/imutáveis dentro de objetos imutáveis; se um campo puder mudar, isole-o e faça a clonagem profunda em `__clone` quando necessário." + +#. type: Plain text +#: ../src/en/guide/concept/immutability.md +msgid "Immutability aligns well with Yii's preference for predictable, side-effect-free code and makes services, caching, and configuration more robust." +msgstr "A imutabilidade combina bem com a preferência do Yii por código previsível e sem efeitos colaterais, e torna serviços, cache e configuração mais robustos." diff --git a/_translations/po/pt-BR/guide_databases_db-migrations.md.po b/_translations/po/pt-BR/guide_databases_db-migrations.md.po new file mode 100644 index 00000000..cef03b0d --- /dev/null +++ b/_translations/po/pt-BR/guide_databases_db-migrations.md.po @@ -0,0 +1,1054 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-06-05 20:33+0000\n" +"PO-Revision-Date: 2026-06-05 20:33+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/guide/databases/db-migrations.md ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "Migrations" +msgstr "Migrations" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "During the course of developing and maintaining a database-driven application, the structure of the database being used evolves just like the source code does. For example, during the development of an application, a new table may be found necessary; after the application is deployed to production, it may be discovered that an index should be created to improve the query performance; and so on. Because a database structure change often requires some source code changes, Yii supports the so-called *database migration* feature that allows you to keep track of database changes in terms of *database migrations* which are version-controlled together with the source code." +msgstr "Ao longo do desenvolvimento e da manutenção de uma aplicação que usa banco de dados, a estrutura do banco evolui assim como o código-fonte. Por exemplo, durante o desenvolvimento de uma aplicação, pode surgir a necessidade de uma nova tabela; depois que a aplicação vai para produção, pode-se descobrir que é preciso criar um índice para melhorar o desempenho de uma consulta; e assim por diante. Como uma mudança na estrutura do banco de dados muitas vezes exige mudanças no código-fonte, o Yii oferece o recurso chamado *migration de banco de dados*, que permite acompanhar as mudanças no banco em forma de *migrations*, versionadas junto com o código-fonte." + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "The following steps show how database migration can be used by a team during development:" +msgstr "Os passos a seguir mostram como uma equipe pode usar migrations durante o desenvolvimento:" + +#. type: Bullet: '1. ' +#: ../src/guide/databases/db-migrations.md +msgid "Tim creates a new migration (e.g. creates a new table, changes a column definition, etc.)." +msgstr "Tim cria uma nova migration (por exemplo, cria uma nova tabela, altera a definição de uma coluna etc.)." + +#. type: Bullet: '2. ' +#: ../src/guide/databases/db-migrations.md +msgid "Tim commits the new migration into the source control system (e.g. Git, Mercurial)." +msgstr "Tim faz o commit da nova migration no sistema de controle de versão (por exemplo, Git, Mercurial)." + +#. type: Bullet: '3. ' +#: ../src/guide/databases/db-migrations.md +msgid "Doug updates his repository from the source control system and receives the new migration." +msgstr "Doug atualiza o repositório dele a partir do sistema de controle de versão e recebe a nova migration." + +#. type: Bullet: '4. ' +#: ../src/guide/databases/db-migrations.md +msgid "Doug applies the migration to his local development database, thereby synchronizing his database to reflect the changes that Tim has made." +msgstr "Doug aplica a migration ao banco de dados local de desenvolvimento, sincronizando o banco dele com as mudanças que Tim fez." + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "And the following steps show how to deploy a new release with database migrations to production:" +msgstr "E os passos a seguir mostram como fazer o deploy de uma nova release com migrations para produção:" + +#. type: Bullet: '1. ' +#: ../src/guide/databases/db-migrations.md +msgid "Scott creates a release tag for the project repository that contains some new database migrations." +msgstr "Scott cria uma tag de release no repositório do projeto que contém algumas migrations novas." + +#. type: Bullet: '2. ' +#: ../src/guide/databases/db-migrations.md +msgid "Scott updates the source code on the production server to the release tag." +msgstr "Scott atualiza o código-fonte no servidor de produção para a tag da release." + +#. type: Bullet: '3. ' +#: ../src/guide/databases/db-migrations.md +msgid "Scott applies any accumulated database migrations to the production database." +msgstr "Scott aplica todas as migrations acumuladas ao banco de dados de produção." + +#. type: Fenced code block (mermaid) +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "" +"sequenceDiagram\n" +" participant Tim\n" +" participant VCS as Source control\n" +" participant Doug\n" +" participant LocalDB as Local development database\n" +" participant Scott\n" +" participant ProdServer as Production server\n" +" participant ProdDB as Production database\n" +"\n" +" Tim->>Tim: Creates a new migration\n" +" Tim->>VCS: Commits the new migration\n" +" Doug->>VCS: Updates his repository and receives the new migration\n" +" Doug->>LocalDB: Applies the migration locally\n" +"\n" +" Scott->>VCS: Creates a release tag with new migrations\n" +" Scott->>ProdServer: Updates source code to the release tag\n" +" Scott->>ProdDB: Applies accumulated migrations\n" +msgstr "" +"sequenceDiagram\n" +" participant Tim\n" +" participant VCS as Controle de versão\n" +" participant Doug\n" +" participant LocalDB as Banco de dados local de desenvolvimento\n" +" participant Scott\n" +" participant ProdServer as Servidor de produção\n" +" participant ProdDB as Banco de dados de produção\n" +"\n" +" Tim->>Tim: Cria uma nova migration\n" +" Tim->>VCS: Faz o commit da nova migration\n" +" Doug->>VCS: Atualiza o repositório e recebe a nova migration\n" +" Doug->>LocalDB: Aplica a migration localmente\n" +"\n" +" Scott->>VCS: Cria uma tag de release com as novas migrations\n" +" Scott->>ProdServer: Atualiza o código-fonte para a tag da release\n" +" Scott->>ProdDB: Aplica as migrations acumuladas\n" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "Yii provides a set of migration command line tools that allow you to:" +msgstr "O Yii fornece um conjunto de ferramentas de linha de comando para migrations que permitem:" + +#. type: Bullet: '* ' +#: ../src/guide/databases/db-migrations.md +msgid "create new migrations;" +msgstr "criar novas migrations;" + +#. type: Bullet: '* ' +#: ../src/guide/databases/db-migrations.md +msgid "apply migrations;" +msgstr "aplicar migrations;" + +#. type: Bullet: '* ' +#: ../src/guide/databases/db-migrations.md +msgid "revert migrations;" +msgstr "reverter migrations;" + +#. type: Bullet: '* ' +#: ../src/guide/databases/db-migrations.md +msgid "re-apply migrations;" +msgstr "reaplicar migrations;" + +#. type: Bullet: '* ' +#: ../src/guide/databases/db-migrations.md +msgid "show migration history and status." +msgstr "mostrar o histórico e o status das migrations." + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "All these tools are accessible through the command `yii migrate`. In this section we will describe in detail how to accomplish various tasks using these tools." +msgstr "Todas essas ferramentas são acessíveis pelo comando `yii migrate`. Nesta seção, vamos descrever em detalhes como realizar várias tarefas usando essas ferramentas." + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "" +"> [!TIP]\n" +"> Migrations could affect not only database schema but adjust existing data to fit new schema, create RBAC\n" +"hierarchy or clean up cache.\n" +msgstr "" +"> [!TIP]\n" +"> Migrations podem afetar não só o schema do banco de dados, mas também ajustar dados existentes ao novo schema, criar a hierarquia\n" +"de RBAC ou limpar o cache.\n" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "" +"> [!NOTE]\n" +"> When manipulating data using a migration you may find that using your Active Record or entity classes\n" +"> for this might be useful because some of the logic is already implemented there. Keep in mind however, that in contrast\n" +"> to code written in the migrations, whose nature is to stay constant forever, application logic is subject to change.\n" +"> So when using Active Record or entity classes in migration code, changes to the logic in the source code\n" +"> may accidentally break the existing migrations. For this reason migration code should be kept independent of other\n" +"> application logic such.\n" +msgstr "" +"> [!NOTE]\n" +"> Ao manipular dados em uma migration, pode parecer útil usar suas classes Active Record ou de entidade,\n" +"> já que parte da lógica já está implementada nelas. Lembre-se, porém, de que, ao contrário\n" +"> do código escrito nas migrations, que por natureza deve permanecer constante para sempre, a lógica da aplicação está sujeita a mudanças.\n" +"> Então, ao usar classes Active Record ou de entidade no código de migrations, mudanças na lógica do código-fonte\n" +"> podem quebrar acidentalmente as migrations existentes. Por isso, o código das migrations deve ser mantido independente do restante\n" +"> da lógica da aplicação.\n" + +#. type: Title ## +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "Initial configuration" +msgstr "Configuração inicial" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "To use migrations, install [yiisoft/db-migration](https://github.com/yiisoft/db-migration/) package:" +msgstr "Para usar migrations, instale o pacote [yiisoft/db-migration](https://github.com/yiisoft/db-migration/):" + +#. type: Fenced code block (sh) +#: ../src/guide/databases/db-migrations.md ../src/guide/start/databases.md +#, no-wrap +msgid "make composer require yiisoft/db-migration\n" +msgstr "make composer require yiisoft/db-migration\n" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "Create a directory to store migrations `src/Migration` right in the project root." +msgstr "Crie um diretório `src/Migration` para armazenar as migrations, diretamente na raiz do projeto." + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "Add the following configuration to `config/common/params.php`:" +msgstr "Adicione a seguinte configuração em `config/common/params.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/databases/db-migrations.md ../src/guide/start/databases.md +#, no-wrap +msgid "" +"'yiisoft/db-migration' => [\n" +" 'newMigrationNamespace' => 'App\\\\Migration',\n" +" 'sourceNamespaces' => ['App\\\\Migration'],\n" +"],\n" +msgstr "" +"'yiisoft/db-migration' => [\n" +" 'newMigrationNamespace' => 'App\\\\Migration',\n" +" 'sourceNamespaces' => ['App\\\\Migration'],\n" +"],\n" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "If you want to place migrations elsewhere, you can define the path in `newMigrationPath`. If your migrations to be applied are from multiple sources, such as external modules, `sourcePaths` could be used to define these." +msgstr "Se você quiser colocar as migrations em outro lugar, pode definir o caminho em `newMigrationPath`. Se as migrations a aplicar vêm de várias fontes, como módulos externos, você pode usar `sourcePaths` para defini-las." + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "You need a database connection configured as well. See [Working with databases](../start/databases.md) for an example of configuring it for PostgreSQL." +msgstr "Você também precisa de uma conexão com o banco de dados configurada. Veja [Trabalhando com banco de dados](../start/databases.md) para um exemplo de configuração com PostgreSQL." + +#. type: Title ## +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "Creating a migration" +msgstr "Criando uma migration" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "To create a new empty migration, run the following command:" +msgstr "Para criar uma nova migration vazia, execute o seguinte comando:" + +#. type: Fenced code block (sh) +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "" +"make shell\n" +"./yii migrate:create \n" +msgstr "" +"make shell\n" +"./yii migrate:create \n" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "The required `name` argument gives a brief description about the new migration. For example, if the migration is about creating a new table named *news*, you may use the name `create_news_table` and run the following command:" +msgstr "O argumento obrigatório `name` dá uma breve descrição da nova migration. Por exemplo, se a migration cria uma nova tabela chamada *news*, você pode usar o nome `create_news_table` e executar o seguinte comando:" + +#. type: Fenced code block +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "" +"make shell\n" +"./yii migrate:create create_news_table\n" +msgstr "" +"make shell\n" +"./yii migrate:create create_news_table\n" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "" +"> [!NOTE]\n" +"> Because the `name` argument will be used as part of the generated migration class name,\n" +"> it should only contain letters, digits, and/or underscore characters.\n" +msgstr "" +"> [!NOTE]\n" +"> Como o argumento `name` é usado como parte do nome da classe de migration gerada,\n" +"> ele deve conter apenas letras, dígitos e/ou underscores.\n" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "The above command will create a new PHP class file named `src/Migration/M251225221906CreateNewsTable.php`. The file contains the following code which mainly declares a migration class with the skeleton code:" +msgstr "O comando acima cria um novo arquivo de classe PHP chamado `src/Migration/M251225221906CreateNewsTable.php`. O arquivo contém o código a seguir, que basicamente declara uma classe de migration com o esqueleto do código:" + +#. type: Fenced code block (php) +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "" +"columnBuilder();\n" +"\n" +" $b->createTable('news', [\n" +" 'id' => $cb::uuidPrimaryKey(),\n" +" 'title' => $cb::string()->notNull(),\n" +" 'content' => $cb::text(),\n" +" ]);\n" +" }\n" +"\n" +" public function down(MigrationBuilder $b): void\n" +" {\n" +" $b->dropTable('news');\n" +" }\n" +"}\n" +msgstr "" +"columnBuilder();\n" +"\n" +" $b->createTable('news', [\n" +" 'id' => $cb::uuidPrimaryKey(),\n" +" 'title' => $cb::string()->notNull(),\n" +" 'content' => $cb::text(),\n" +" ]);\n" +" }\n" +"\n" +" public function down(MigrationBuilder $b): void\n" +" {\n" +" $b->dropTable('news');\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "Migration builder `$b` in the above manages database schema while the column builder `$cb` manages column types. Both allow using *abstract types*. When a migration is applied to a particular database, the abstract types will be translated into the corresponding database physical types and corresponding SQL to define them." +msgstr "No exemplo acima, o migration builder `$b` gerencia o schema do banco de dados, enquanto o column builder `$cb` gerencia os tipos de coluna. Ambos permitem usar *tipos abstratos*. Quando uma migration é aplicada a um banco de dados específico, os tipos abstratos são traduzidos para os tipos físicos correspondentes do banco e para o SQL correspondente que os define." + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "Methods available in migration builder belong to the following types:" +msgstr "Os métodos disponíveis no migration builder se dividem nos seguintes tipos:" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "Raw queries" +msgstr "Consultas SQL puras" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "getDb — to get database connection instance." +msgstr "getDb — para obter a instância da conexão com o banco de dados." + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "execute — to execute raw SQL query." +msgstr "execute — para executar uma consulta SQL pura." + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "Data" +msgstr "Dados" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "insert / update / delete" +msgstr "insert / update / delete" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "batchInsert" +msgstr "batchInsert" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "upsert" +msgstr "upsert" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "Tables and views" +msgstr "Tabelas e views" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "createTable / renameTable / dropTable" +msgstr "createTable / renameTable / dropTable" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "truncateTable" +msgstr "truncateTable" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "addCommentOnTable / dropCommentFromTable" +msgstr "addCommentOnTable / dropCommentFromTable" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "createView / dropView" +msgstr "createView / dropView" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "Columns" +msgstr "Colunas" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "addColumn / renameColumn / alterColumn / dropColumn" +msgstr "addColumn / renameColumn / alterColumn / dropColumn" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "addCommentOnColumn / dropCommentFromColumn" +msgstr "addCommentOnColumn / dropCommentFromColumn" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "Keys and indexes" +msgstr "Chaves e índices" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "addPrimaryKey / dropPrimaryKey" +msgstr "addPrimaryKey / dropPrimaryKey" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "addForeignKey / dropForeignKey" +msgstr "addForeignKey / dropForeignKey" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "createIndex / dropIndex" +msgstr "createIndex / dropIndex" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "Additionally, there's a `columnBuilder()` which is used to obtain a column builder as in example above. The builder has static methods that define various column types:" +msgstr "Além disso, há um `columnBuilder()`, usado para obter um column builder como no exemplo acima. O builder tem métodos estáticos que definem vários tipos de coluna:" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "Keys" +msgstr "Chaves" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "primaryKey" +msgstr "primaryKey" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "smallPrimaryKey" +msgstr "smallPrimaryKey" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "bigPrimaryKey" +msgstr "bigPrimaryKey" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "uuidPrimaryKey" +msgstr "uuidPrimaryKey" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "Boolean" +msgstr "Booleano" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "boolean" +msgstr "boolean" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "Numbers" +msgstr "Números" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "bit" +msgstr "bit" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "tinyint" +msgstr "tinyint" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "smallint" +msgstr "smallint" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "integer" +msgstr "integer" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "bigint" +msgstr "bigint" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "flat" +msgstr "flat" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "double" +msgstr "double" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "decimal" +msgstr "decimal" + +#. type: Title ## +#: ../src/guide/databases/db-migrations.md ../src/internals/010-code-style.md +#, no-wrap +msgid "Strings" +msgstr "Strings" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "char" +msgstr "char" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "string" +msgstr "string" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "text" +msgstr "text" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "Date and time" +msgstr "Data e hora" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "timestamp" +msgstr "timestamp" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "datetime" +msgstr "datetime" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "datetimeWithTimezone" +msgstr "datetimeWithTimezone" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "time" +msgstr "time" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "timeWithTimezone" +msgstr "timeWithTimezone" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "date" +msgstr "date" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "Special types" +msgstr "Tipos especiais" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "money" +msgstr "money" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "binary" +msgstr "binary" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "uuid" +msgstr "uuid" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "array" +msgstr "array" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "structured" +msgstr "structured" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "json" +msgstr "json" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "enum" +msgstr "enum" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "All the above methods create a base type which could be adjusted with additional methods:" +msgstr "Todos os métodos acima criam um tipo base que pode ser ajustado com métodos adicionais:" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "null / notNull" +msgstr "null / notNull" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "defaultValue" +msgstr "defaultValue" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "unique" +msgstr "unique" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "scale / size / unsigned" +msgstr "scale / size / unsigned" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "primaryKey / autoIncrement" +msgstr "primaryKey / autoIncrement" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "check" +msgstr "check" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "comment" +msgstr "comment" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "computed" +msgstr "computed" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "extra" +msgstr "extra" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "reference" +msgstr "reference" + +#. type: Title ### +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "Irreversible migrations" +msgstr "Migrations irreversíveis" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "Not all migrations are reversible. For example, if the `up()` method deletes a row of a table, you may not be able to recover this row in the `down()` method. Sometimes, you may be just too lazy to implement the `down()`, because it is not very common to revert database migrations. In this case, you should implement `Yiisoft\\Db\\Migration\\MigrationInterface` that has `up()` only." +msgstr "Nem todas as migrations são reversíveis. Por exemplo, se o método `up()` apaga uma linha de uma tabela, talvez você não consiga recuperar essa linha no método `down()`. Às vezes, você pode simplesmente não querer implementar o `down()`, porque não é muito comum reverter migrations. Nesse caso, implemente `Yiisoft\\Db\\Migration\\MigrationInterface`, que tem apenas `up()`." + +#. type: Title ### +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "Transactional migrations" +msgstr "Migrations transacionais" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "While performing complex DB migrations, it is important to ensure each migration to either succeed or fail as a whole so that the database can maintain integrity and consistency. To achieve this goal, it is recommended that you may enclose the DB operations of each migration in a transaction automatically by adding `TransactionalMigrationInterface` to `implements` of your migration." +msgstr "Ao executar migrations complexas, é importante garantir que cada migration tenha sucesso ou falhe por completo, para que o banco de dados mantenha a integridade e a consistência. Para isso, é recomendado envolver automaticamente as operações de banco de cada migration em uma transação, adicionando `TransactionalMigrationInterface` ao `implements` da sua migration." + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "As a result, if any operation in the `up()` or `down()` method fails, all prior operations will be rolled back automatically." +msgstr "Assim, se qualquer operação no método `up()` ou `down()` falhar, todas as operações anteriores serão desfeitas (rollback) automaticamente." + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "" +"> Note: Not all DBMS support transactions. And some DB queries cannot be put into a transaction. For some examples,\n" +"please refer to [implicit commit](https://dev.mysql.com/doc/refman/5.7/en/implicit-commit.html).\n" +msgstr "" +"> Nota: nem todo SGBD dá suporte a transações. E algumas consultas não podem ser colocadas em uma transação. Para alguns exemplos,\n" +"consulte [implicit commit](https://dev.mysql.com/doc/refman/5.7/en/implicit-commit.html).\n" + +#. type: Title ## +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "Generating a migration" +msgstr "Gerando uma migration" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "Instead of writing migrations by hand, the command provides a convenient way generate some of the code." +msgstr "Em vez de escrever migrations à mão, o comando oferece uma forma prática de gerar parte do código." + +#. type: Fenced code block (shell) +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "" +"make shell\n" +"./yii migrate:create -- my_first_table --command=table --fields=name,example --table-comment=my_first_table\n" +msgstr "" +"make shell\n" +"./yii migrate:create -- my_first_table --command=table --fields=name,example --table-comment=my_first_table\n" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "That would generate the following:" +msgstr "Isso geraria o seguinte:" + +#. type: Fenced code block (php) +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "" +"columnBuilder();\n" +"\n" +" $b->createTable('my_first_table', [\n" +" 'id' => $columnBuilder::primaryKey(),\n" +" 'name',\n" +" 'example',\n" +" ]);\n" +"\n" +" $b->addCommentOnTable('my_first_table', 'my_first_table');\n" +" }\n" +"\n" +" public function down(MigrationBuilder $b): void\n" +" {\n" +" $b->dropTable('my_first_table');\n" +" }\n" +"}\n" +msgstr "" +"columnBuilder();\n" +"\n" +" $b->createTable('my_first_table', [\n" +" 'id' => $columnBuilder::primaryKey(),\n" +" 'name',\n" +" 'example',\n" +" ]);\n" +"\n" +" $b->addCommentOnTable('my_first_table', 'my_first_table');\n" +" }\n" +"\n" +" public function down(MigrationBuilder $b): void\n" +" {\n" +" $b->dropTable('my_first_table');\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "Commands available are:" +msgstr "Os comandos disponíveis são:" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "create - empty migration." +msgstr "create - migration vazia." + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "table - creating a table. Use `--fields` specify a list of fields to use. Types could be specified as well such as `id:primaryKey,name:string:defaultValue(\"Alex\"),user_id:integer:foreignKey,category_id2:integer:foreignKey(category id2)`." +msgstr "table - cria uma tabela. Use `--fields` para especificar a lista de campos. Também é possível especificar os tipos, como em `id:primaryKey,name:string:defaultValue(\"Alex\"),user_id:integer:foreignKey,category_id2:integer:foreignKey(category id2)`." + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "dropTable - dropping a table." +msgstr "dropTable - remove uma tabela." + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "addColumn - adding a column." +msgstr "addColumn - adiciona uma coluna." + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "dropColumn - dropping a column." +msgstr "dropColumn - remove uma coluna." + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "junction - creating a junction table. Use `--and` specify a second table." +msgstr "junction - cria uma tabela de junção. Use `--and` para especificar a segunda tabela." + +#. type: Title ## +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "Applying Migrations" +msgstr "Aplicando migrations" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "To upgrade a database to its latest structure, you should apply all available new migrations using the following command:" +msgstr "Para atualizar um banco de dados para a estrutura mais recente, aplique todas as migrations novas disponíveis com o seguinte comando:" + +#. type: Fenced code block +#: ../src/guide/databases/db-migrations.md ../src/guide/security/authorization.md +#, no-wrap +msgid "./yii migrate:up\n" +msgstr "./yii migrate:up\n" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "This command will list all migrations that have not been applied so far. If you confirm that you want to apply these migrations, it will run the `up()` method in every new migration class, one after another, in the order of their timestamp values. If any of the migrations fails, the command will quit without applying the rest of the migrations." +msgstr "Esse comando lista todas as migrations que ainda não foram aplicadas. Se você confirmar que quer aplicá-las, ele executa o método `up()` de cada nova classe de migration, uma após a outra, na ordem de seus timestamps. Se alguma das migrations falhar, o comando é encerrado sem aplicar as demais." + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "For each migration that has been successfully applied, the command will insert a row into a database table named `migration` to record the successful application of the migration. This will allow the migration tool to identify which migrations have been applied and which have not." +msgstr "Para cada migration aplicada com sucesso, o comando insere uma linha em uma tabela do banco chamada `migration` para registrar a aplicação bem-sucedida. Isso permite que a ferramenta de migrations identifique quais migrations foram aplicadas e quais não foram." + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "Sometimes, you may only want to apply one or a few new migrations, instead of all available migrations. You can do so by specifying the number of migrations that you want to apply when running the command. For example, the following command will try to apply the next three available migrations:" +msgstr "Às vezes, você pode querer aplicar apenas uma ou algumas migrations novas, em vez de todas as disponíveis. Você pode fazer isso especificando o número de migrations que quer aplicar ao executar o comando. Por exemplo, o comando a seguir tenta aplicar as próximas três migrations disponíveis:" + +#. type: Fenced code block +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "./yii migrate:up --limit=3\n" +msgstr "./yii migrate:up --limit=3\n" + +#. type: Title ## +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "Reverting Migrations" +msgstr "Revertendo migrations" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "To revert (undo) one or multiple migrations that have been applied before, you can run the following command:" +msgstr "Para reverter (desfazer) uma ou várias migrations aplicadas anteriormente, execute o seguinte comando:" + +#. type: Fenced code block +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "" +"./yii migrate:down # revert the most recently applied migration\n" +"./yii migrate:down --limit=3 # revert the most 3 recently applied migrations\n" +"./yii migrate:down --all # revert all migrations\n" +msgstr "" +"./yii migrate:down # reverte a migration aplicada mais recentemente\n" +"./yii migrate:down --limit=3 # reverte as 3 migrations aplicadas mais recentemente\n" +"./yii migrate:down --all # reverte todas as migrations\n" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "" +"> Note: Not all migrations are reversible. Trying to revert such migrations will cause an error and stop the\n" +"entire reverting process.\n" +msgstr "" +"> Nota: nem todas as migrations são reversíveis. Tentar reverter uma migration assim causa um erro e interrompe\n" +"todo o processo de reversão.\n" + +#. type: Title ## +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "Redoing Migrations" +msgstr "Refazendo migrations" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "Redoing migrations means first reverting the specified migrations and then applying again. This can be done as follows:" +msgstr "Refazer migrations significa primeiro reverter as migrations especificadas e depois aplicá-las novamente. Isso pode ser feito assim:" + +#. type: Fenced code block +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "" +"./yii migrate:redo # redo the last applied migration\n" +"./yii migrate:redo --limit=3 # redo the last 3 applied migrations\n" +"./yii migrate:redo --all # redo all migrations\n" +msgstr "" +"./yii migrate:redo # refaz a última migration aplicada\n" +"./yii migrate:redo --limit=3 # refaz as 3 últimas migrations aplicadas\n" +"./yii migrate:redo --all # refaz todas as migrations\n" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "> Note: If a migration is not reversible, you will not be able to redo it.\n" +msgstr "> Nota: se uma migration não for reversível, você não conseguirá refazê-la.\n" + +#. type: Title ## +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "Listing Migrations" +msgstr "Listando migrations" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "To list which migrations have been applied and which are not, you may use the following commands:" +msgstr "Para listar quais migrations foram aplicadas e quais não foram, use os seguintes comandos:" + +#. type: Fenced code block +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "" +"./yii migrate/history # showing the last 10 applied migrations\n" +"./yii migrate:history --limit=5 # showing the last 5 applied migrations\n" +"./yii migrate:history --all # showing all applied migrations\n" +"\n" +"./yii migrate:new # showing the first 10 new migrations\n" +"./yii migrate:new --limit=5 # showing the first 5 new migrations\n" +"./yii migrate:new --all # showing all new migrations\n" +msgstr "" +"./yii migrate/history # mostra as 10 últimas migrations aplicadas\n" +"./yii migrate:history --limit=5 # mostra as 5 últimas migrations aplicadas\n" +"./yii migrate:history --all # mostra todas as migrations aplicadas\n" +"\n" +"./yii migrate:new # mostra as 10 primeiras migrations novas\n" +"./yii migrate:new --limit=5 # mostra as 5 primeiras migrations novas\n" +"./yii migrate:new --all # mostra todas as migrations novas\n" + +#. type: Title ### +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "Upgrading from Yii 2.0" +msgstr "Migrando do Yii 2.0" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "Migrations in Yii 2.0 and the [yiisoft/db-migration](https://github.com/yiisoft/db-migration/) package are not compatible, and the `migration` table is also not compatible." +msgstr "As migrations do Yii 2.0 e o pacote [yiisoft/db-migration](https://github.com/yiisoft/db-migration/) não são compatíveis, e a tabela `migration` também não é compatível." + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "A probable solution is to use structure dumps and rename the old `migration` table. Upon the initial execution of migrations, a new `migration` table with new fields will be created. All further changes in the database schema are applied using the new `migration` component and recorded in the new migration table." +msgstr "Uma solução possível é usar dumps da estrutura e renomear a tabela `migration` antiga. Na primeira execução das migrations, uma nova tabela `migration` com os novos campos será criada. Todas as mudanças seguintes no schema do banco de dados são aplicadas usando o novo componente `migration` e registradas na nova tabela de migrations." diff --git a/_translations/po/pt-BR/guide_glossary.md.po b/_translations/po/pt-BR/guide_glossary.md.po new file mode 100644 index 00000000..476c22fe --- /dev/null +++ b/_translations/po/pt-BR/guide_glossary.md.po @@ -0,0 +1,547 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-05-30 06:43+0000\n" +"PO-Revision-Date: 2026-05-30 06:43+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/glossary.md +#, no-wrap +msgid "A" +msgstr "A" + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "action" +msgstr "action" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Action is a callable, class, or class method that handles a matched route and returns a response. Read more in [\"Actions\"](structure/action.md)." +msgstr "Action é um callable, uma classe ou um método de classe que trata uma rota correspondida e retorna uma resposta. Leia mais em [\"Actions\"](structure/action.md)." + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "alias" +msgstr "alias" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Alias is a string used by Yii to refer to the class or directory such as `@app/vendor`. Read more in [\"Aliases\"](concept/aliases.md)." +msgstr "Alias é uma string usada pelo Yii para se referir a uma classe ou a um diretório, como `@app/vendor`. Leia mais em [\"Aliases\"](concept/aliases.md)." + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "application" +msgstr "aplicação" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Application is an object that starts up, handles a request through configured middleware, and shuts down. Read more in [\"Application\"](structure/application.md)." +msgstr "A aplicação é um objeto que inicializa, trata uma requisição passando pelos middlewares configurados e encerra. Leia mais em [\"Aplicação\"](structure/application.md)." + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "asset" +msgstr "asset" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Asset refers to a resource file. Typically, it contains JavaScript or CSS code but can be any static content accessed via HTTP. Read more in [\"Assets\"](views/asset.md)." +msgstr "Asset é um arquivo de recurso. Normalmente contém código JavaScript ou CSS, mas pode ser qualquer conteúdo estático acessado via HTTP. Leia mais em [\"Assets\"](views/asset.md)." + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "asset bundle" +msgstr "asset bundle" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Asset bundle is a PHP class that declares a group of CSS, JavaScript, image, or font files that should be published and registered together. Read more in [\"Asset Bundles\"](views/asset.md#asset-bundles)." +msgstr "Asset bundle é uma classe PHP que declara um grupo de arquivos CSS, JavaScript, imagens ou fontes que devem ser publicados e registrados juntos. Leia mais em [\"Asset bundles\"](views/asset.md#asset-bundles)." + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "authentication" +msgstr "autenticação" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Authentication is the process of determining the identity of the current user. Read more in [\"Authentication\"](security/authentication.md)." +msgstr "Autenticação é o processo de determinar a identidade do usuário atual. Leia mais em [\"Autenticação\"](security/authentication.md)." + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "authorization" +msgstr "autorização" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Authorization is the process of checking whether an authenticated or anonymous user is allowed to perform an action. Read more in [\"Authorization\"](security/authorization.md)." +msgstr "Autorização é o processo de verificar se um usuário autenticado ou anônimo tem permissão para realizar uma ação. Leia mais em [\"Autorização\"](security/authorization.md)." + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "autoloading" +msgstr "autoloading" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Autoloading is the process of loading PHP classes automatically when they are first used. Read more in [\"Class autoloading\"](concept/autoloading.md)." +msgstr "Autoloading é o processo de carregar classes PHP automaticamente quando elas são usadas pela primeira vez. Leia mais em [\"Autoloading de classes\"](concept/autoloading.md)." + +#. type: Title # +#: ../src/guide/glossary.md +#, no-wrap +msgid "B" +msgstr "B" + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "bootstrap" +msgstr "bootstrap" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Bootstrap is application startup code that prepares services, configuration, and runtime state before request handling. Read more in [\"Configuration\"](concept/configuration.md)." +msgstr "Bootstrap é o código de inicialização da aplicação que prepara serviços, configuração e estado de execução antes do tratamento da requisição. Leia mais em [\"Configuração\"](concept/configuration.md)." + +#. type: Title # +#: ../src/guide/glossary.md +#, no-wrap +msgid "C" +msgstr "C" + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "configuration" +msgstr "configuração" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Configuration may refer either to the process of setting properties of an object or to a configuration file that stores settings for an object, or a class of objects. Read more in [\"Configuration\"](concept/configuration.md)." +msgstr "Configuração pode se referir tanto ao processo de definir propriedades de um objeto quanto a um arquivo de configuração que guarda definições para um objeto ou uma classe de objetos. Leia mais em [\"Configuração\"](concept/configuration.md)." + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "container" +msgstr "container" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Container is an object that creates services, resolves their dependencies, and returns configured instances. Read more in [\"DI container\"](concept/di-container.md#di-container)." +msgstr "Container é um objeto que cria serviços, resolve suas dependências e retorna instâncias configuradas. Leia mais em [\"Container de DI\"](concept/di-container.md#container-de-di)." + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "controller" +msgstr "controller" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Controller is a class that groups action methods for related routes. Read more in [\"Actions\"](structure/action.md)." +msgstr "Controller é uma classe que agrupa métodos de action de rotas relacionadas. Leia mais em [\"Actions\"](structure/action.md)." + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "cookie" +msgstr "cookie" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Cookie is a small piece of data stored by a browser and sent with later requests to the same site. Read more in [\"Cookies\"](runtime/cookies.md)." +msgstr "Cookie é um pequeno pedaço de dados guardado pelo navegador e enviado nas requisições seguintes ao mesmo site. Leia mais em [\"Cookies\"](runtime/cookies.md)." + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "CSRF" +msgstr "CSRF" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "CSRF means cross-site request forgery, an attack where another site tries to make a user's browser submit an unwanted request to your application. Read more in [\"Avoiding CSRF\"](security/best-practices.md#avoiding-csrf)." +msgstr "CSRF significa cross-site request forgery (falsificação de requisição entre sites), um ataque em que outro site tenta fazer o navegador de um usuário enviar uma requisição indesejada para sua aplicação. Leia mais em [\"Evitando CSRF\"](security/best-practices.md#evitando-csrf)." + +#. type: Title # +#: ../src/guide/glossary.md +#, no-wrap +msgid "D" +msgstr "D" + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "DI" +msgstr "DI" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Dependency injection is a programming technique where an object receives its dependencies from the outside. Read more in [\"Dependency injection and container\"](concept/di-container.md)." +msgstr "Injeção de dependência é uma técnica de programação em que um objeto recebe suas dependências de fora. Leia mais em [\"Injeção de dependência e container\"](concept/di-container.md)." + +#. type: Title # +#: ../src/guide/glossary.md +#, no-wrap +msgid "E" +msgstr "E" + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "entry script" +msgstr "entry script (script de entrada)" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Entry script is the first PHP script executed for a web or console application. Read more in [\"Entry scripts\"](structure/entry-script.md)." +msgstr "O script de entrada é o primeiro script PHP executado em uma aplicação web ou de console. Leia mais em [\"Scripts de entrada\"](structure/entry-script.md)." + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "event" +msgstr "evento" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Event is an object that represents something that happened and can be passed to listeners. Read more in [\"Events\"](concept/events.md)." +msgstr "Evento é um objeto que representa algo que aconteceu e que pode ser passado para listeners. Leia mais em [\"Eventos\"](concept/events.md)." + +#. type: Title # +#: ../src/guide/glossary.md +#, no-wrap +msgid "H" +msgstr "H" + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "handler" +msgstr "handler" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Handler is callable code selected by routing or middleware to process a request and produce a response. Read more in [\"Routing and URL generation\"](runtime/routing.md)." +msgstr "Handler é o código callable escolhido pelo roteamento ou por um middleware para processar uma requisição e produzir uma resposta. Leia mais em [\"Roteamento e geração de URLs\"](runtime/routing.md)." + +#. type: Title # +#: ../src/guide/glossary.md +#, no-wrap +msgid "I" +msgstr "I" + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "installation" +msgstr "instalação" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Installation is a process of preparing something to work either by following a readme file or by executing a specially prepared script. In the case of Yii, it's setting permissions and fulfilling software requirements." +msgstr "Instalação é o processo de preparar algo para funcionar, seja seguindo um arquivo readme, seja executando um script preparado especialmente para isso. No caso do Yii, é definir permissões e atender aos requisitos de software." + +#. type: Title # +#: ../src/guide/glossary.md +#, no-wrap +msgid "L" +msgstr "L" + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "layout" +msgstr "layout" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Layout is a view template that wraps page-specific content with shared page structure. Read more in [\"Working with layouts\"](views/view.md#working-with-layouts)." +msgstr "Layout é um template de view que envolve o conteúdo específico de uma página com a estrutura compartilhada da página. Leia mais em [\"Trabalhando com layouts\"](views/view.md#trabalhando-com-layouts)." + +#. type: Title # +#: ../src/guide/glossary.md +#, no-wrap +msgid "M" +msgstr "M" + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "migration" +msgstr "migration" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Migration is a versioned PHP class that applies or reverts a database schema or data change. Read more in [\"Migrations\"](databases/db-migrations.md)." +msgstr "Migration é uma classe PHP versionada que aplica ou reverte uma mudança no schema ou nos dados do banco de dados. Leia mais em [\"Migrations\"](databases/db-migrations.md)." + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "middleware" +msgstr "middleware" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Middleware is a processor in the request processing stack. Given a request, it may either produce a response or do some action and pass processing to the next middleware. Read more in [\"Middleware\"](structure/middleware.md)." +msgstr "Middleware é um processador na pilha de processamento da requisição. Dada uma requisição, ele pode produzir uma resposta ou fazer alguma ação e passar o processamento para o próximo middleware. Leia mais em [\"Middleware\"](structure/middleware.md)." + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "model" +msgstr "model" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Model is an object that represents application data and usually contains validation or business rules for that data. Read more in [\"Working with forms\"](start/forms.md)." +msgstr "Model é um objeto que representa dados da aplicação e normalmente contém regras de validação ou de negócio para esses dados. Leia mais em [\"Trabalhando com formulários\"](start/forms.md)." + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "module" +msgstr "módulo" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "The module is a namespace that groups some code based on a use-case. It's typically used within the main application and may contain any source code, define additional URL handlers or console commands." +msgstr "O módulo é um namespace que agrupa código com base em um caso de uso. Normalmente é usado dentro da aplicação principal e pode conter qualquer código-fonte, definir handlers de URL adicionais ou comandos de console." + +#. type: Title # +#: ../src/guide/glossary.md +#, no-wrap +msgid "N" +msgstr "N" + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "namespace" +msgstr "namespace" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Namespace refers to a [PHP language feature](https://www.php.net/manual/en/language.namespaces.php) to group multiple classes under a certain name." +msgstr "Namespace é um [recurso da linguagem PHP](https://www.php.net/manual/en/language.namespaces.php) para agrupar várias classes sob um determinado nome." + +#. type: Title # +#: ../src/guide/glossary.md +#, no-wrap +msgid "P" +msgstr "P" + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "package" +msgstr "pacote" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "A package usually refers to [Composer package](https://getcomposer.org/doc/). It's code ready for reuse and redistribution installable automatically via a package manager." +msgstr "Um pacote normalmente é um [pacote do Composer](https://getcomposer.org/doc/). É código pronto para reutilização e redistribuição, que pode ser instalado automaticamente por um gerenciador de pacotes." + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "parameter" +msgstr "parâmetro" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Parameter is a configuration value that can be used by application or package config files. Read more in [\"Parameters\"](concept/configuration.md#parameters)." +msgstr "Parâmetro é um valor de configuração que pode ser usado pelos arquivos de configuração da aplicação ou de pacotes. Leia mais em [\"Parâmetros\"](concept/configuration.md#parametros)." + +#. type: Title # +#: ../src/guide/glossary.md +#, no-wrap +msgid "Q" +msgstr "Q" + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "queue" +msgstr "queue (fila)" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "A queue is a data structure that processes items in first-in, first-out order. Yii has a [yiisoft/queue](https://github.com/yiisoft/queue) package." +msgstr "Uma fila é uma estrutura de dados que processa itens na ordem em que chegaram (primeiro a entrar, primeiro a sair). O Yii tem o pacote [yiisoft/queue](https://github.com/yiisoft/queue)." + +#. type: Title # +#: ../src/guide/glossary.md +#, no-wrap +msgid "R" +msgstr "R" + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "request" +msgstr "requisição" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Request is a PSR-7 object that represents an incoming HTTP message, including method, URI, headers, body, uploaded files, and attributes. Read more in [\"Request\"](runtime/request.md)." +msgstr "Requisição é um objeto PSR-7 que representa uma mensagem HTTP recebida, incluindo método, URI, headers, corpo, arquivos enviados e atributos. Leia mais em [\"Requisição\"](runtime/request.md)." + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "response" +msgstr "resposta" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Response is a PSR-7 object that represents an outgoing HTTP message, including status code, headers, and body. Read more in [\"Response\"](runtime/response.md)." +msgstr "Resposta é um objeto PSR-7 que representa uma mensagem HTTP enviada, incluindo código de status, headers e corpo. Leia mais em [\"Resposta\"](runtime/response.md)." + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "route" +msgstr "rota" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Route describes which request method and URL pattern should be handled by which action or middleware. Read more in [\"Routing and URL generation\"](runtime/routing.md)." +msgstr "A rota descreve qual método de requisição e qual padrão de URL devem ser tratados por qual action ou middleware. Leia mais em [\"Roteamento e geração de URLs\"](runtime/routing.md)." + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "rule" +msgstr "regra" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "The rule usually refers to a validation rule of the [yiisoft/validator](https://github.com/yiisoft/validator) package. It holds a set of parameters for checking if a data set is valid. \"Rule handler\" does the actual processing." +msgstr "A regra normalmente se refere a uma regra de validação do pacote [yiisoft/validator](https://github.com/yiisoft/validator). Ela guarda um conjunto de parâmetros para verificar se um conjunto de dados é válido. O \"rule handler\" faz o processamento de fato." + +#. type: Title # +#: ../src/guide/glossary.md +#, no-wrap +msgid "S" +msgstr "S" + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "service" +msgstr "serviço" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Service is a focused object that performs application work or provides infrastructure behavior and is usually stored in the DI container. Read more in [\"Service components\"](../cookbook/organizing-code/service.md)." +msgstr "Serviço é um objeto focado que realiza trabalho da aplicação ou fornece comportamento de infraestrutura e normalmente fica registrado no container de DI. Leia mais em [\"Componentes de serviço\"](../cookbook/organizing-code/service.md)." + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "service provider" +msgstr "service provider (provedor de serviços)" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Service provider is a class that registers related service definitions for the DI container. Read more in [\"Service providers\"](concept/configuration.md#service-providers)." +msgstr "Service provider é uma classe que registra definições de serviços relacionados para o container de DI. Leia mais em [\"Service providers\"](concept/configuration.md#service-providers)." + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "session" +msgstr "sessão" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Session is server-side storage associated with a browser across multiple requests. Read more in [\"Sessions\"](runtime/sessions.md)." +msgstr "Sessão é um armazenamento no servidor associado a um navegador ao longo de várias requisições. Leia mais em [\"Sessões\"](runtime/sessions.md)." + +#. type: Title # +#: ../src/guide/glossary.md +#, no-wrap +msgid "T" +msgstr "T" + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "template" +msgstr "template" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Template is a file used by a view or template engine to produce presentation output such as HTML. Read more in [\"Views\"](views/view.md)." +msgstr "Template é um arquivo usado por uma view ou por um template engine para produzir a saída de apresentação, como HTML. Leia mais em [\"Views\"](views/view.md)." + +#. type: Title # +#: ../src/guide/glossary.md +#, no-wrap +msgid "V" +msgstr "V" + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "vendor" +msgstr "vendor" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "A vendor is an organization or individual developer providing code in the form of packages. It also may refer to [Composer's `vendor` directory](https://getcomposer.org/doc/)." +msgstr "Vendor é uma organização ou um desenvolvedor individual que fornece código na forma de pacotes. Também pode se referir ao [diretório `vendor` do Composer](https://getcomposer.org/doc/)." + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "view" +msgstr "view" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "View is responsible for presenting data to end users, usually by executing a template with provided data. Read more in [\"Views\"](views/view.md)." +msgstr "A view é responsável por apresentar dados aos usuários finais, normalmente executando um template com os dados fornecidos. Leia mais em [\"Views\"](views/view.md)." + +#. type: Title # +#: ../src/guide/glossary.md +#, no-wrap +msgid "W" +msgstr "W" + +#. type: Title ## +#: ../src/guide/glossary.md +#, no-wrap +msgid "widget" +msgstr "widget" + +#. type: Plain text +#: ../src/guide/glossary.md +msgid "Widget is a reusable view component that renders a piece of user interface. Read more in [\"Widgets\"](views/widget.md)." +msgstr "Widget é um componente de view reutilizável que renderiza uma parte da interface do usuário. Leia mais em [\"Widgets\"](views/widget.md)." diff --git a/_translations/po/pt-BR/guide_index.md.po b/_translations/po/pt-BR/guide_index.md.po new file mode 100644 index 00000000..a331ab4c --- /dev/null +++ b/_translations/po/pt-BR/guide_index.md.po @@ -0,0 +1,630 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-10-11 10:37+0000\n" +"PO-Revision-Date: 2026-10-11 10:37+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ### +#: ../src/cookbook/making-http-requests.md ../src/guide/index.md ../src/guide/intro/upgrade-from-v2.md ../src/guide/testing/overview.md ../src/guide/tutorial/docker.md +#, no-wrap +msgid "Testing" +msgstr "Testes" + +#. type: Title ## +#: ../src/guide/caching/overview.md ../src/guide/index.md +#, no-wrap +msgid "Caching" +msgstr "Cache" + +#. type: Title # +#: ../src/guide/index.md +#, no-wrap +msgid "The definitive guide to Yii3" +msgstr "O guia definitivo do Yii3" + +#. type: Plain text +#: ../src/guide/index.md +msgid "We release this guide under the [Terms of Yii Documentation](https://www.yiiframework.com/license#docs)." +msgstr "Este guia é publicado sob os [Termos da documentação do Yii](https://www.yiiframework.com/license#docs)." + +#. type: Title ## +#: ../src/guide/index.md +#, no-wrap +msgid "Introduction" +msgstr "Introdução" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[About Yii](intro/what-is-yii.md)" +msgstr "[Sobre o Yii](intro/what-is-yii.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Upgrading from version 1.1](intro/upgrade-from-v1.md)" +msgstr "[Migrando da versão 1.1](intro/upgrade-from-v1.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Upgrading from version 2.0](intro/upgrade-from-v2.md)" +msgstr "[Migrando da versão 2.0](intro/upgrade-from-v2.md)" + +#. type: Title ## +#: ../src/guide/index.md ../src/guide/tutorial/console-applications.md +#, no-wrap +msgid "Getting started" +msgstr "Primeiros passos" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[What do you need to know?](start/prerequisites.md)" +msgstr "[O que você precisa saber?](start/prerequisites.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Creating a project](start/creating-project.md)" +msgstr "[Criando um projeto](start/creating-project.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Application Workflow](start/workflow.md)" +msgstr "[Fluxo da aplicação](start/workflow.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Saying hello](start/hello.md)" +msgstr "[Dizendo olá](start/hello.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Working with forms](start/forms.md)" +msgstr "[Trabalhando com formulários](start/forms.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Working with databases](start/databases.md)" +msgstr "[Trabalhando com bancos de dados](start/databases.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Generating code with Gii](start/gii.md) TODO" +msgstr "[Gerando código com o Gii](start/gii.md) TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Looking ahead](start/looking-ahead.md)" +msgstr "[Seguindo em frente](start/looking-ahead.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Demo applications](start/demo-apps.md)" +msgstr "[Aplicações de demonstração](start/demo-apps.md)" + +#. type: Title ## +#: ../src/guide/index.md +#, no-wrap +msgid "Key concepts" +msgstr "Conceitos principais" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Aliases](concept/aliases.md)" +msgstr "[Aliases](concept/aliases.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Autoloading](concept/autoloading.md)" +msgstr "[Autoload](concept/autoloading.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Configuration](concept/configuration.md)" +msgstr "[Configuração](concept/configuration.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Dependency injection container](concept/di-container.md)" +msgstr "[Container de injeção de dependência](concept/di-container.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Events](concept/events.md)" +msgstr "[Eventos](concept/events.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Immutability](concept/immutability.md)" +msgstr "[Imutabilidade](concept/immutability.md)" + +#. type: Title ## +#: ../src/guide/index.md ../src/guide/start/workflow.md +#, no-wrap +msgid "Application structure" +msgstr "Estrutura da aplicação" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Application structure overview](structure/overview.md)" +msgstr "[Visão geral da estrutura da aplicação](structure/overview.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Entry scripts](structure/entry-script.md)" +msgstr "[Scripts de entrada](structure/entry-script.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Application](structure/application.md)" +msgstr "[Aplicação](structure/application.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Modules](structure/module.md)" +msgstr "[Módulos](structure/module.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Actions](structure/action.md)" +msgstr "[Actions](structure/action.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Middleware](structure/middleware.md)" +msgstr "[Middleware](structure/middleware.md)" + +#. type: Title ## +#: ../src/guide/index.md +#, no-wrap +msgid "Packages" +msgstr "Pacotes" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Using packages](structure/package.md)" +msgstr "[Usando pacotes](structure/package.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Designing packages](structure/designing-packages.md)" +msgstr "[Projetando pacotes](structure/designing-packages.md)" + +#. type: Title ## +#: ../src/guide/index.md +#, no-wrap +msgid "Handling requests" +msgstr "Tratando requisições" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Routing and URL generation](runtime/routing.md)" +msgstr "[Roteamento e geração de URLs](runtime/routing.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Request](runtime/request.md)" +msgstr "[Requisição](runtime/request.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Response](runtime/response.md)" +msgstr "[Resposta](runtime/response.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Sessions](runtime/sessions.md)" +msgstr "[Sessões](runtime/sessions.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Cookies](runtime/cookies.md)" +msgstr "[Cookies](runtime/cookies.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Handling errors](runtime/handling-errors.md)" +msgstr "[Tratamento de erros](runtime/handling-errors.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Logging](runtime/logging.md)" +msgstr "[Logs](runtime/logging.md)" + +#. type: Title # +#: ../src/guide/index.md ../src/guide/security/overview.md +#, no-wrap +msgid "Security" +msgstr "Segurança" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Security overview](security/overview.md)" +msgstr "[Visão geral de segurança](security/overview.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Authentication](security/authentication.md)" +msgstr "[Autenticação](security/authentication.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Authorization](security/authorization.md) TODO: verify and complete!" +msgstr "[Autorização](security/authorization.md) TODO: verify and complete!" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Working with passwords](security/passwords.md)" +msgstr "[Trabalhando com senhas](security/passwords.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Cryptography](security/cryptography.md)" +msgstr "[Criptografia](security/cryptography.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Trusted request](security/trusted-request.md)" +msgstr "[Requisição confiável](security/trusted-request.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Best practices](security/best-practices.md)" +msgstr "[Boas práticas](security/best-practices.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Caching overview](caching/overview.md)" +msgstr "[Visão geral do cache](caching/overview.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Data caching](caching/data.md)" +msgstr "[Cache de dados](caching/data.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "Fragment caching TODO" +msgstr "Cache de fragmentos TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "Page caching TODO" +msgstr "Cache de páginas TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "HTTP caching TODO" +msgstr "Cache HTTP TODO" + +#. type: Title # +#: ../src/guide/index.md ../src/guide/start/databases.md +#, no-wrap +msgid "Working with databases" +msgstr "Trabalhando com bancos de dados" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Yii DB](https://github.com/yiisoft/db/blob/master/docs/guide/en/README.md)" +msgstr "[Yii DB](https://github.com/yiisoft/db/blob/master/docs/guide/en/README.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Active Record](https://github.com/yiisoft/active-record/blob/master/README.md)" +msgstr "[Active Record](https://github.com/yiisoft/active-record/blob/master/README.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Migrations](databases/db-migrations.md) TODO: verify/update!" +msgstr "[Migrations](databases/db-migrations.md) TODO: verify/update!" + +#. type: Title # +#: ../src/guide/index.md ../src/guide/views/view.md +#, no-wrap +msgid "Views" +msgstr "Views" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[View](views/view.md)" +msgstr "[View](views/view.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Assets](views/asset.md) TODO: verify!" +msgstr "[Assets](views/asset.md) TODO: verify!" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Scripts, styles and metatags](views/script-style-meta.md) TODO: verify!" +msgstr "[Scripts, estilos e meta tags](views/script-style-meta.md) TODO: verify!" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Template engines](views/template-engines.md) TODO: verify!" +msgstr "[Template engines](views/template-engines.md) TODO: verify!" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[View injections](views/view-injections.md)" +msgstr "[Injeções de view](views/view-injections.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Widgets](views/widget.md) TODO: verify!" +msgstr "[Widgets](views/widget.md) TODO: verify!" + +#. type: Title ## +#: ../src/guide/index.md +#, no-wrap +msgid "Getting data from users" +msgstr "Recebendo dados dos usuários" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "Creating forms TODO" +msgstr "Criando formulários TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Validating input](https://github.com/yiisoft/validator/blob/master/docs/guide/en/README.md)" +msgstr "[Validando entradas](https://github.com/yiisoft/validator/blob/master/docs/guide/en/README.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "Uploading files TODO" +msgstr "Upload de arquivos TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "Collecting tabular input TODO" +msgstr "Coletando dados tabulares TODO" + +#. type: Title ## +#: ../src/guide/index.md +#, no-wrap +msgid "Displaying data" +msgstr "Exibindo dados" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "Data formatting TODO" +msgstr "Formatação de dados TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "Pagination TODO" +msgstr "Paginação TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "Sorting TODO" +msgstr "Ordenação TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "Data providers TODO" +msgstr "Data providers TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "Data widgets TODO" +msgstr "Widgets de dados TODO" + +#. type: Title ## +#: ../src/guide/index.md ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "REST APIs" +msgstr "APIs REST" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Quick start](rest/quick-start.md)" +msgstr "[Início rápido](rest/quick-start.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "Resources TODO" +msgstr "Recursos TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "Controllers TODO" +msgstr "Controllers TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "Routing TODO" +msgstr "Roteamento TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "Authentication TODO" +msgstr "Autenticação TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "Rate limiting TODO" +msgstr "Limitação de requisições TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "Versioning TODO" +msgstr "Versionamento TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "Error handling TODO" +msgstr "Tratamento de erros TODO" + +#. type: Title ## +#: ../src/guide/index.md +#, no-wrap +msgid "Development tools" +msgstr "Ferramentas de desenvolvimento" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "Debug toolbar and debugger" +msgstr "Barra e painel de debug" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "Generating code using Gii" +msgstr "Gerando código com o Gii" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "Generating API documentation" +msgstr "Gerando documentação da API" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Testing overview](testing/overview.md)" +msgstr "[Visão geral de testes](testing/overview.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Testing environment setup](testing/environment-setup.md)" +msgstr "[Configurando o ambiente de testes](testing/environment-setup.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Unit tests](testing/unit.md)" +msgstr "[Testes unitários](testing/unit.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Functional tests](testing/functional.md)" +msgstr "[Testes funcionais](testing/functional.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[End-to-end tests](testing/end-to-end.md)" +msgstr "[Testes end-to-end](testing/end-to-end.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Static analysis and mutation testing](testing/quality-tools.md)" +msgstr "[Análise estática e testes de mutação](testing/quality-tools.md)" + +#. type: Title ## +#: ../src/guide/index.md +#, no-wrap +msgid "Special topics" +msgstr "Tópicos especiais" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Console applications](tutorial/console-applications.md)" +msgstr "[Aplicações de console](tutorial/console-applications.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Mailing](tutorial/mailing.md)" +msgstr "[Envio de e-mails](tutorial/mailing.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Performance tuning](tutorial/performance-tuning.md)" +msgstr "[Ajuste de desempenho](tutorial/performance-tuning.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Using Yii with event loop](tutorial/using-with-event-loop.md)" +msgstr "[Usando o Yii com event loop](tutorial/using-with-event-loop.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Using Yii with FrankenPHP](tutorial/using-yii-with-frankenphp.md)" +msgstr "[Usando o Yii com FrankenPHP](tutorial/using-yii-with-frankenphp.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Using Yii with Rapira](tutorial/using-yii-with-rapira.md)" +msgstr "[Usando o Yii com Rapira](tutorial/using-yii-with-rapira.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Using Yii with RoadRunner](tutorial/using-yii-with-roadrunner.md)" +msgstr "[Usando o Yii com RoadRunner](tutorial/using-yii-with-roadrunner.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Using Yii with Swoole](tutorial/using-yii-with-swoole.md)" +msgstr "[Usando o Yii com Swoole](tutorial/using-yii-with-swoole.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Docker in application templates](tutorial/docker.md)" +msgstr "[Docker nos templates de aplicação](tutorial/docker.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Internationalization](tutorial/i18n.md)" +msgstr "[Internacionalização](tutorial/i18n.md)" + +#. type: Title ## +#: ../src/guide/index.md +#, no-wrap +msgid "Helpers" +msgstr "Helpers" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Arrays](https://github.com/yiisoft/arrays/)" +msgstr "[Arrays](https://github.com/yiisoft/arrays/)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Files](https://github.com/yiisoft/files/)" +msgstr "[Arquivos](https://github.com/yiisoft/files/)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Html](https://github.com/yiisoft/html/)" +msgstr "[Html](https://github.com/yiisoft/html/)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Json](https://github.com/yiisoft/json)" +msgstr "[Json](https://github.com/yiisoft/json)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Network utilities](https://github.com/yiisoft/network-utilities/)" +msgstr "[Utilitários de rede](https://github.com/yiisoft/network-utilities/)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[VarDumper](https://github.com/yiisoft/var-dumper)" +msgstr "[VarDumper](https://github.com/yiisoft/var-dumper)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Strings](https://github.com/yiisoft/strings)" +msgstr "[Strings](https://github.com/yiisoft/strings)" + +#. type: Title ## +#: ../src/guide/index.md +#, no-wrap +msgid "Extras" +msgstr "Extras" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Cookbook](../cookbook/index.md)" +msgstr "[Cookbook](../cookbook/index.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Glossary](glossary.md)" +msgstr "[Glossário](glossary.md)" diff --git a/_translations/po/pt-BR/guide_intro_upgrade-from-v1.md.po b/_translations/po/pt-BR/guide_intro_upgrade-from-v1.md.po new file mode 100644 index 00000000..6280c39a --- /dev/null +++ b/_translations/po/pt-BR/guide_intro_upgrade-from-v1.md.po @@ -0,0 +1,1487 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-09-25 14:35+0000\n" +"PO-Revision-Date: 2026-09-25 14:35+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/deployment/angie-docker-proxy.md ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Project structure" +msgstr "Estrutura do projeto" + +#. type: Fenced code block (json) +#: ../src/guide/concept/autoloading.md ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"{\n" +" \"autoload\": {\n" +" \"psr-4\": {\n" +" \"App\\\\\": \"src/\"\n" +" }\n" +" }\n" +"}\n" +msgstr "" +"{\n" +" \"autoload\": {\n" +" \"psr-4\": {\n" +" \"App\\\\\": \"src/\"\n" +" }\n" +" }\n" +"}\n" + +#. type: Title # +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "Upgrading from Version 1.1" +msgstr "Migrando da versão 1.1" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"> If you haven't used Yii 1.1, you can skip this section and get directly to\n" +"> \"[getting started](../start/prerequisites.md)\" section.\n" +msgstr "" +"> Se você não usou o Yii 1.1, pode pular esta seção e ir direto para a seção\n" +"> \"[primeiros passos](../start/prerequisites.md)\".\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii3 is not an incremental upgrade from Yii 1.1. Yii 2.0 was a full rewrite, and Yii3 changes the architecture again: Composer packages, namespaces, PHP 8, PSR interfaces, dependency injection, explicit routes, middleware, and separate packages for features that were built into the framework in Yii 1.1." +msgstr "O Yii3 não é um upgrade incremental do Yii 1.1. O Yii 2.0 foi uma reescrita completa, e o Yii3 muda a arquitetura de novo: pacotes Composer, namespaces, PHP 8, interfaces PSR, injeção de dependência, rotas explícitas, middleware e pacotes separados para funcionalidades que no Yii 1.1 eram embutidas no framework." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Treat this as building a new Yii3 application with the benefit of Yii 1.1 experience. Reuse the domain knowledge, database schema, user workflows, and selected code after refactoring. Do not try to reproduce the Yii 1.1 application structure in Yii3. A direct search-and-replace conversion is not realistic." +msgstr "Encare isso como a construção de uma nova aplicação Yii3 aproveitando a experiência com o Yii 1.1. Reaproveite o conhecimento do domínio, o esquema do banco de dados, os fluxos dos usuários e partes selecionadas do código após refatorá-las. Não tente reproduzir a estrutura da aplicação Yii 1.1 no Yii3. Uma conversão direta por busca e substituição não é realista." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "For additional background, read the Yii 2.0 guide section [Upgrading from Version 1.1](https://www.yiiframework.com/doc/guide/2.0/en/intro-upgrade-from-v1). It explains the first major break from Yii 1.1: Composer, namespaces, object configuration, view changes, controller return values, widgets, assets, helpers, forms, query builder, Active Record, and URL management. Yii3 builds on many of those changes and makes dependencies more explicit." +msgstr "Para mais contexto, leia a seção do guia do Yii 2.0 [Upgrading from Version 1.1](https://www.yiiframework.com/doc/guide/2.0/en/intro-upgrade-from-v1). Ela explica a primeira grande ruptura com o Yii 1.1: Composer, namespaces, configuração de objetos, mudanças nas views, valores de retorno dos controllers, widgets, assets, helpers, formulários, query builder, Active Record e gerenciamento de URLs. O Yii3 se apoia em muitas dessas mudanças e torna as dependências mais explícitas." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Recommended approach" +msgstr "Abordagem recomendada" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Choose one of these paths:" +msgstr "Escolha um destes caminhos:" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Build a new Yii3 application directly when the Yii 1.1 application is small or you are already rewriting request flows." +msgstr "Construa uma nova aplicação Yii3 diretamente quando a aplicação Yii 1.1 for pequena ou você já estiver reescrevendo os fluxos de requisição." + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Move Yii 1.1 concepts to Yii 2.0 first when the team needs a smaller conceptual step." +msgstr "Migre primeiro os conceitos do Yii 1.1 para o Yii 2.0 quando o time precisar de um passo conceitual menor." + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Keep Yii 1.1 running and rebuild critical flows in Yii3 one by one." +msgstr "Mantenha o Yii 1.1 rodando e reconstrua os fluxos críticos no Yii3 um a um." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "For most long-lived applications, the third option is the least risky. Create a Yii3 application, connect it to the same database, and build vertical slices: route, action, input validation, persistence, view, assets, and tests. Each slice should be idiomatic Yii3, even when it is based on behavior from the Yii 1.1 application." +msgstr "Para a maioria das aplicações de longa duração, a terceira opção é a de menor risco. Crie uma aplicação Yii3, conecte-a ao mesmo banco de dados e construa vertical slices: rota, action, validação de entrada, persistência, view, assets e testes. Cada slice deve ser Yii3 idiomático, mesmo quando se baseia no comportamento da aplicação Yii 1.1." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "Prepare the Yii 1.1 application" +msgstr "Prepare a aplicação Yii 1.1" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Useful preparation can happen before the Yii3 application is ready. These refactorings make old behavior easier to understand and reduce the amount of Yii 1.1 framework state that crosses into the new code:" +msgstr "Uma preparação útil pode acontecer antes de a aplicação Yii3 estar pronta. Estas refatorações tornam o comportamento antigo mais fácil de entender e reduzem a quantidade de estado do framework Yii 1.1 que passa para o código novo:" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Remove direct `Yii::app()` access from reusable code where practical. If a full refactoring is too large, keep `Yii::app()` calls near controllers, widgets, and commands, then pass values and services to lower-level code explicitly." +msgstr "Remova o acesso direto a `Yii::app()` do código reutilizável onde for viável. Se uma refatoração completa for grande demais, mantenha as chamadas a `Yii::app()` perto de controllers, widgets e comandos, e passe valores e serviços explicitamente para o código de nível mais baixo." + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Introduce repositories or query services for database reads currently spread across controllers, views, `CActiveRecord` methods, and widgets. Yii3 can use Active Record, but it does not require it for every persistence task." +msgstr "Introduza repositórios ou serviços de consulta para as leituras do banco de dados hoje espalhadas por controllers, views, métodos de `CActiveRecord` e widgets. O Yii3 pode usar Active Record, mas não o exige para toda tarefa de persistência." + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Separate business rules from framework infrastructure. Code that does not extend `CComponent`, read global application state, or render views is easier to reuse as a specification for Yii3 code." +msgstr "Separe as regras de negócio da infraestrutura do framework. Código que não estende `CComponent`, não lê o estado global da aplicação nem renderiza views é mais fácil de reutilizar como especificação para o código Yii3." + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Move reusable behavior out of large controllers and Active Record classes into Yii 1.1 application components or plain services. Yii3 services are configured and injected differently, but the responsibility boundary is similar." +msgstr "Mova o comportamento reutilizável de controllers e classes Active Record grandes para componentes de aplicação do Yii 1.1 ou serviços simples. Os serviços do Yii3 são configurados e injetados de outra forma, mas a fronteira de responsabilidade é parecida." + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Add tests or characterization checks around routes and workflows you plan to rebuild first. They become the executable specification for the Yii3 slice." +msgstr "Adicione testes ou verificações de caracterização em torno das rotas e fluxos que você planeja reconstruir primeiro. Eles se tornam a especificação executável do slice Yii3." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "For example, instead of reading post archive data directly from several controllers or widgets, create a small service that describes the application need:" +msgstr "Por exemplo, em vez de ler os dados do arquivo de posts diretamente em vários controllers ou widgets, crie um pequeno serviço que descreva a necessidade da aplicação:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"class PostRepository extends CComponent\n" +"{\n" +" public function getArchive()\n" +" {\n" +" // ...\n" +" }\n" +"\n" +" public function getTopForFrontPage($limit = 10)\n" +" {\n" +" // ...\n" +" }\n" +"}\n" +msgstr "" +"class PostRepository extends CComponent\n" +"{\n" +" public function getArchive()\n" +" {\n" +" // ...\n" +" }\n" +"\n" +" public function getTopForFrontPage($limit = 10)\n" +" {\n" +" // ...\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "The Yii3 implementation may use `yiisoft/active-record`, `yiisoft/db`, or another persistence layer. The important point is that controllers and views no longer need to know that detail." +msgstr "A implementação no Yii3 pode usar `yiisoft/active-record`, `yiisoft/db` ou outra camada de persistência. O importante é que controllers e views não precisem mais conhecer esse detalhe." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Things to learn before starting" +msgstr "O que aprender antes de começar" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Some Yii3 application-template choices are likely to be new in a Yii 1.1 codebase:" +msgstr "Algumas escolhas do template de aplicação do Yii3 provavelmente serão novidade para uma base de código Yii 1.1:" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "[Composer](https://getcomposer.org/). Yii3 applications and packages are installed through Composer and loaded with PSR-4 autoloading." +msgstr "[Composer](https://getcomposer.org/). Aplicações e pacotes Yii3 são instalados pelo Composer e carregados com autoloading PSR-4." + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "[Namespaces](https://www.php.net/manual/en/language.namespaces.php). Yii3 classes are namespaced instead of using Yii 1.1-style class prefixes and path aliases for class loading." +msgstr "[Namespaces](https://www.php.net/manual/en/language.namespaces.php). As classes do Yii3 usam namespaces em vez dos prefixos de classe e path aliases do Yii 1.1 para o carregamento de classes." + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "[Docker](https://www.docker.com/get-started/). The default Yii3 application template includes Docker configuration. Using it gives each application its own repeatable environment and reduces differences between local development and production." +msgstr "[Docker](https://www.docker.com/get-started/). O template de aplicação padrão do Yii3 inclui configuração do Docker. Usá-lo dá a cada aplicação seu próprio ambiente reproduzível e reduz as diferenças entre o desenvolvimento local e a produção." + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "[Environment variables](https://en.wikipedia.org/wiki/Environment_variable). Yii3 templates commonly use them for environment-specific settings and secrets, especially in Docker-based deployments. This follows the same idea as [12-factor app configuration](https://12factor.net/config)." +msgstr "[Variáveis de ambiente](https://en.wikipedia.org/wiki/Environment_variable). Os templates do Yii3 costumam usá-las para configurações específicas de ambiente e segredos, especialmente em deploys baseados em Docker. Isso segue a mesma ideia da [configuração de aplicações 12-factor](https://12factor.net/config)." + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "[Actions](../structure/action.md). Yii3 does not require controller inheritance. A route can point to any callable, and the default template uses invokable action classes." +msgstr "[Actions](../structure/action.md). O Yii3 não exige herança de controller. Uma rota pode apontar para qualquer callable, e o template padrão usa classes de action invocáveis." + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "[Application structure](../structure/overview.md). Yii3's default structure is different from Yii 1.1. Start with the Yii3 template and change it only when the application needs it." +msgstr "[Estrutura da aplicação](../structure/overview.md). A estrutura padrão do Yii3 é diferente da do Yii 1.1. Comece com o template do Yii3 e altere-o apenas quando a aplicação precisar." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "PHP, Composer, and namespaces" +msgstr "PHP, Composer e namespaces" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii 1.1 applications commonly rely on PHP 5-era code, class prefixes such as `CController`, and autoloading by class name. Yii3 applications require modern PHP and Composer autoloading." +msgstr "Aplicações Yii 1.1 costumam depender de código da era do PHP 5, prefixos de classe como `CController` e autoloading pelo nome da classe. Aplicações Yii3 exigem PHP moderno e autoloading do Composer." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii 1.1:" +msgstr "Yii 1.1:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"class SiteController extends CController\n" +"{\n" +"}\n" +msgstr "" +"class SiteController extends CController\n" +"{\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii3:" +msgstr "Yii3:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"namespace App\\Web\\HomePage;\n" +"\n" +"final readonly class Action\n" +"{\n" +"}\n" +msgstr "" +"namespace App\\Web\\HomePage;\n" +"\n" +"final readonly class Action\n" +"{\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "Configure your application namespace with PSR-4:" +msgstr "Configure o namespace da sua aplicação com PSR-4:" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Run:" +msgstr "Execute:" + +#. type: Fenced code block (shell) +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "composer dump-autoload\n" +msgstr "composer dump-autoload\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "When reusing a class, give it a namespace, add strict types, replace Yii 1.1 base classes, and inject dependencies instead of reading them from global application state. If these changes make the class awkward, use the old class as a specification and write a new Yii3 class instead." +msgstr "Ao reutilizar uma classe, dê a ela um namespace, adicione strict types, substitua as classes base do Yii 1.1 e injete as dependências em vez de lê-las do estado global da aplicação. Se essas mudanças deixarem a classe estranha, use a classe antiga como especificação e escreva uma nova classe Yii3." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "A Yii 1.1 application often uses:" +msgstr "Uma aplicação Yii 1.1 frequentemente usa:" + +#. type: Fenced code block (text) +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"protected/\n" +" commands/\n" +" components/\n" +" config/\n" +" controllers/\n" +" extensions/\n" +" messages/\n" +" migrations/\n" +" models/\n" +" views/\n" +"themes/\n" +"webroot/\n" +msgstr "" +"protected/\n" +" commands/\n" +" components/\n" +" config/\n" +" controllers/\n" +" extensions/\n" +" messages/\n" +" migrations/\n" +" models/\n" +" views/\n" +"themes/\n" +"webroot/\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "The current Yii3 application template uses:" +msgstr "O template de aplicação atual do Yii3 usa:" + +#. type: Fenced code block (text) +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"assets/\n" +"config/\n" +"public/\n" +"runtime/\n" +"src/\n" +"tests/\n" +msgstr "" +"assets/\n" +"config/\n" +"public/\n" +"runtime/\n" +"src/\n" +"tests/\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "Typical mappings to consider are:" +msgstr "Mapeamentos típicos a considerar:" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"| Yii 1.1 | Yii3 |\n" +"|---------|------|\n" +"| `protected/controllers` | `src/Web/*/Action.php` or controller-like services |\n" +"| `protected/models` | `src/Domain`, `src/Shared`, `src/Db`, or form models by responsibility |\n" +"| `protected/views` | templates near the feature, for example `src/Web/HomePage/template.php` |\n" +"| `protected/views/layouts` | layout templates and assets under `src/Web/Shared/Layout` |\n" +"| `protected/components` | services configured in the dependency injection container |\n" +"| `protected/extensions` | Composer packages or local packages |\n" +"| `protected/commands` | `src/Console/*Command.php` |\n" +"| `protected/messages` | translator message files |\n" +"| `protected/config` | `config/common`, `config/web`, `config/console`, `config/environments` |\n" +"| `webroot` | `public` |\n" +msgstr "" +"| Yii 1.1 | Yii3 |\n" +"|---------|------|\n" +"| `protected/controllers` | `src/Web/*/Action.php` ou serviços no estilo controller |\n" +"| `protected/models` | `src/Domain`, `src/Shared`, `src/Db` ou form models, conforme a responsabilidade |\n" +"| `protected/views` | templates perto da funcionalidade, por exemplo `src/Web/HomePage/template.php` |\n" +"| `protected/views/layouts` | templates de layout e assets em `src/Web/Shared/Layout` |\n" +"| `protected/components` | serviços configurados no container de injeção de dependência |\n" +"| `protected/extensions` | pacotes Composer ou pacotes locais |\n" +"| `protected/commands` | `src/Console/*Command.php` |\n" +"| `protected/messages` | arquivos de mensagens do tradutor |\n" +"| `protected/config` | `config/common`, `config/web`, `config/console`, `config/environments` |\n" +"| `webroot` | `public` |\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Do not recreate `protected` in Yii3. Put PHP source under `src`, public files under `public`, generated/runtime files under `runtime`, and configuration under `config`." +msgstr "Não recrie `protected` no Yii3. Coloque o código PHP em `src`, os arquivos públicos em `public`, os arquivos gerados/de runtime em `runtime` e a configuração em `config`." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "Configuration and application components" +msgstr "Configuração e componentes da aplicação" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii 1.1 configuration is usually one large array:" +msgstr "A configuração do Yii 1.1 geralmente é um único array grande:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"return [\n" +" 'basePath' => dirname(__DIR__),\n" +" 'components' => [\n" +" 'db' => [\n" +" 'connectionString' => 'mysql:host=localhost;dbname=app',\n" +" 'username' => 'root',\n" +" 'password' => '',\n" +" ],\n" +" 'urlManager' => [\n" +" 'urlFormat' => 'path',\n" +" 'rules' => [\n" +" 'post/' => 'post/view',\n" +" ],\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +"return [\n" +" 'basePath' => dirname(__DIR__),\n" +" 'components' => [\n" +" 'db' => [\n" +" 'connectionString' => 'mysql:host=localhost;dbname=app',\n" +" 'username' => 'root',\n" +" 'password' => '',\n" +" ],\n" +" 'urlManager' => [\n" +" 'urlFormat' => 'path',\n" +" 'rules' => [\n" +" 'post/' => 'post/view',\n" +" ],\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "In Yii3, configuration is split by purpose and services are wired through the container:" +msgstr "No Yii3, a configuração é dividida por finalidade e os serviços são conectados pelo container:" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "aliases in `config/common/aliases.php`;" +msgstr "aliases em `config/common/aliases.php`;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "parameters in `config/common/params.php` and environment files;" +msgstr "parâmetros em `config/common/params.php` e nos arquivos de ambiente;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "shared service definitions in `config/common/di/*.php`;" +msgstr "definições de serviços compartilhadas em `config/common/di/*.php`;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "web-only service definitions in `config/web/di/*.php`;" +msgstr "definições de serviços apenas para web em `config/web/di/*.php`;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "routes in `config/common/routes.php`;" +msgstr "rotas em `config/common/routes.php`;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "console commands in `config/console/*.php`." +msgstr "comandos de console em `config/console/*.php`." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "The default template's console DI group reuses shared definitions from `config/common/di/*.php`. If you need console-only container definitions, add files for them to the `di-console` group in `config/configuration.php` and rebuild the merge plan." +msgstr "O grupo de DI de console do template padrão reutiliza as definições compartilhadas de `config/common/di/*.php`. Se você precisar de definições de container apenas para o console, adicione arquivos para elas ao grupo `di-console` em `config/configuration.php` e reconstrua o merge plan." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "Replace `Yii::app()->componentName` with constructor-injected services:\n" +msgstr "Substitua `Yii::app()->componentName` por serviços injetados pelo construtor:\n" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"use Yiisoft\\Db\\Connection\\ConnectionInterface;\n" +"use Yiisoft\\Router\\UrlGeneratorInterface;\n" +"\n" +"final readonly class PostRepository\n" +"{\n" +" public function __construct(\n" +" private ConnectionInterface $db,\n" +" private UrlGeneratorInterface $urlGenerator,\n" +" ) {\n" +" }\n" +"}\n" +msgstr "" +"use Yiisoft\\Db\\Connection\\ConnectionInterface;\n" +"use Yiisoft\\Router\\UrlGeneratorInterface;\n" +"\n" +"final readonly class PostRepository\n" +"{\n" +" public function __construct(\n" +" private ConnectionInterface $db,\n" +" private UrlGeneratorInterface $urlGenerator,\n" +" ) {\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "See [Configuration](../concept/configuration.md), [Aliases](../concept/aliases.md), and [Dependency injection container](../concept/di-container.md)." +msgstr "Veja [Configuração](../concept/configuration.md), [Aliases](../concept/aliases.md) e [Container de injeção de dependência](../concept/di-container.md)." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "Entry script" +msgstr "Script de entrada" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii 1.1 entry scripts commonly load `yii.php` and create a web application:" +msgstr "Os scripts de entrada do Yii 1.1 geralmente carregam `yii.php` e criam uma aplicação web:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"require_once __DIR__ . '/../framework/yii.php';\n" +"\n" +"Yii::createWebApplication($config)->run();\n" +msgstr "" +"require_once __DIR__ . '/../framework/yii.php';\n" +"\n" +"Yii::createWebApplication($config)->run();\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii3 entry scripts load Composer and bootstrap the configured application. Start with the `public/index.php` file from `yiisoft/app` and adjust configuration instead of building the application manually in the entry script." +msgstr "Os scripts de entrada do Yii3 carregam o Composer e inicializam a aplicação configurada. Comece com o arquivo `public/index.php` do `yiisoft/app` e ajuste a configuração em vez de montar a aplicação manualmente no script de entrada." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "See [Entry scripts](../structure/entry-script.md) and [Application workflow](../start/workflow.md)." +msgstr "Veja [Scripts de entrada](../structure/entry-script.md) e [Fluxo da aplicação](../start/workflow.md)." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "Controllers, actions, and routes" +msgstr "Controllers, actions e rotas" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii 1.1 controllers extend `CController`, and actions are methods named `actionName`:" +msgstr "Os controllers do Yii 1.1 estendem `CController`, e as actions são métodos chamados `actionName`:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"class PostController extends CController\n" +"{\n" +" public function actionView($id)\n" +" {\n" +" $post = Post::model()->findByPk($id);\n" +"\n" +" if ($post === null) {\n" +" throw new CHttpException(404);\n" +" }\n" +"\n" +" $this->render('view', ['post' => $post]);\n" +" }\n" +"}\n" +msgstr "" +"class PostController extends CController\n" +"{\n" +" public function actionView($id)\n" +" {\n" +" $post = Post::model()->findByPk($id);\n" +"\n" +" if ($post === null) {\n" +" throw new CHttpException(404);\n" +" }\n" +"\n" +" $this->render('view', ['post' => $post]);\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii3 does not require controller inheritance. The current template uses invokable action classes:" +msgstr "O Yii3 não exige herança de controller. O template atual usa classes de action invocáveis:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"namespace App\\Web\\Post\\View;\n" +"\n" +"use App\\Post\\PostRepository;\n" +"use Psr\\Http\\Message\\ResponseInterface;\n" +"use Yiisoft\\Router\\CurrentRoute;\n" +"use Yiisoft\\Yii\\View\\Renderer\\WebViewRenderer;\n" +"\n" +"final readonly class Action\n" +"{\n" +" public function __construct(\n" +" private CurrentRoute $currentRoute,\n" +" private PostRepository $posts,\n" +" private WebViewRenderer $viewRenderer,\n" +" ) {\n" +" }\n" +"\n" +" public function __invoke(): ResponseInterface\n" +" {\n" +" $post = $this->posts->findById((int) $this->currentRoute->getArgument('id'));\n" +"\n" +" return $this->viewRenderer->render(__DIR__ . '/template', [\n" +" 'post' => $post,\n" +" ]);\n" +" }\n" +"}\n" +msgstr "" +"namespace App\\Web\\Post\\View;\n" +"\n" +"use App\\Post\\PostRepository;\n" +"use Psr\\Http\\Message\\ResponseInterface;\n" +"use Yiisoft\\Router\\CurrentRoute;\n" +"use Yiisoft\\Yii\\View\\Renderer\\WebViewRenderer;\n" +"\n" +"final readonly class Action\n" +"{\n" +" public function __construct(\n" +" private CurrentRoute $currentRoute,\n" +" private PostRepository $posts,\n" +" private WebViewRenderer $viewRenderer,\n" +" ) {\n" +" }\n" +"\n" +" public function __invoke(): ResponseInterface\n" +" {\n" +" $post = $this->posts->findById((int) $this->currentRoute->getArgument('id'));\n" +"\n" +" return $this->viewRenderer->render(__DIR__ . '/template', [\n" +" 'post' => $post,\n" +" ]);\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "The route is explicit:" +msgstr "A rota é explícita:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"use App\\Web\\Post\\View;\n" +"use Yiisoft\\Router\\Route;\n" +"\n" +"return [\n" +" Route::get('/post/{id:\\d+}')\n" +" ->action(View\\Action::class)\n" +" ->name('post/view'),\n" +"];\n" +msgstr "" +"use App\\Web\\Post\\View;\n" +"use Yiisoft\\Router\\Route;\n" +"\n" +"return [\n" +" Route::get('/post/{id:\\d+}')\n" +" ->action(View\\Action::class)\n" +" ->name('post/view'),\n" +"];\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Define routes before action bodies. It gives you a checklist of request flows you decided to keep in the Yii3 application." +msgstr "Defina as rotas antes do corpo das actions. Isso dá a você uma checklist dos fluxos de requisição que você decidiu manter na aplicação Yii3." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "See [Actions](../structure/action.md), [Middleware](../structure/middleware.md), and [Routing and URL generation](../runtime/routing.md)." +msgstr "Veja [Actions](../structure/action.md), [Middleware](../structure/middleware.md) e [Roteamento e geração de URLs](../runtime/routing.md)." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "Requests, responses, redirects, sessions, and cookies" +msgstr "Requisições, respostas, redirecionamentos, sessões e cookies" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii 1.1 code often reads and writes through `Yii::app()`:" +msgstr "O código Yii 1.1 frequentemente lê e escreve por meio de `Yii::app()`:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"$id = Yii::app()->request->getParam('id');\n" +"Yii::app()->user->setFlash('success', 'Saved.');\n" +"$this->redirect(['post/view', 'id' => $id]);\n" +msgstr "" +"$id = Yii::app()->request->getParam('id');\n" +"Yii::app()->user->setFlash('success', 'Saved.');\n" +"$this->redirect(['post/view', 'id' => $id]);\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii3 uses PSR-7 request and response objects and injectable services. Request input is available from `ServerRequestInterface`; redirects, sessions, cookies, and responses are explicit dependencies." +msgstr "O Yii3 usa objetos de requisição e resposta PSR-7 e serviços injetáveis. A entrada da requisição está disponível em `ServerRequestInterface`; redirecionamentos, sessões, cookies e respostas são dependências explícitas." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "See [Request](../runtime/request.md), [Response](../runtime/response.md), [Sessions](../runtime/sessions.md), and [Cookies](../runtime/cookies.md)." +msgstr "Veja [Requisição](../runtime/request.md), [Resposta](../runtime/response.md), [Sessões](../runtime/sessions.md) e [Cookies](../runtime/cookies.md)." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "Views and layouts" +msgstr "Views e layouts" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii 1.1 views use `$this` as the controller or widget context. Layouts and partials are rendered through controller methods:" +msgstr "As views do Yii 1.1 usam `$this` como o contexto do controller ou do widget. Layouts e partials são renderizados por métodos do controller:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"\n" +"\n" +"

title); ?>

\n" +msgstr "" +"\n" +"\n" +"

title); ?>

\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "In Yii3 templates, `$this` is a `Yiisoft\\View\\WebView` instance:" +msgstr "Nos templates do Yii3, `$this` é uma instância de `Yiisoft\\View\\WebView`:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"use Yiisoft\\Html\\Html;\n" +"use Yiisoft\\View\\WebView;\n" +"\n" +"/**\n" +" * @var WebView $this\n" +" * @var Post $post\n" +" */\n" +"\n" +"$this->setTitle($post->getTitle());\n" +"?>\n" +"\n" +"

getTitle()) ?>

\n" +msgstr "" +"use Yiisoft\\Html\\Html;\n" +"use Yiisoft\\View\\WebView;\n" +"\n" +"/**\n" +" * @var WebView $this\n" +" * @var Post $post\n" +" */\n" +"\n" +"$this->setTitle($post->getTitle());\n" +"?>\n" +"\n" +"

getTitle()) ?>

\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Move controller-specific view logic to the action or to a presenter. Pass only the data a template needs." +msgstr "Mova a lógica de view específica do controller para a action ou para um presenter. Passe apenas os dados de que o template precisa." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "See [View](../views/view.md), [View injections](../views/view-injections.md), and [Template engines](../views/template-engines.md)." +msgstr "Veja [View](../views/view.md), [Injeções de view](../views/view-injections.md) e [Template engines](../views/template-engines.md)." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "Assets and client scripts" +msgstr "Assets e scripts do cliente" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii 1.1 applications often use `CClientScript`, themes, and extension-specific asset publishing:" +msgstr "Aplicações Yii 1.1 frequentemente usam `CClientScript`, temas e publicação de assets específica de extensões:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"Yii::app()->clientScript->registerCssFile('/css/site.css');\n" +"Yii::app()->clientScript->registerScriptFile('/js/site.js');\n" +msgstr "" +"Yii::app()->clientScript->registerCssFile('/css/site.css');\n" +"Yii::app()->clientScript->registerScriptFile('/js/site.js');\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii3 uses asset bundles from `yiisoft/assets`:" +msgstr "O Yii3 usa asset bundles do `yiisoft/assets`:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"namespace App\\Web\\Shared\\Layout\\Main;\n" +"\n" +"use Yiisoft\\Assets\\AssetBundle;\n" +"\n" +"final class MainAsset extends AssetBundle\n" +"{\n" +" public ?string $basePath = '@assets/main';\n" +" public ?string $baseUrl = '@assetsUrl/main';\n" +" public ?string $sourcePath = '@assetsSource/main';\n" +"\n" +" public array $css = ['site.css'];\n" +" public array $js = ['site.js'];\n" +"}\n" +msgstr "" +"namespace App\\Web\\Shared\\Layout\\Main;\n" +"\n" +"use Yiisoft\\Assets\\AssetBundle;\n" +"\n" +"final class MainAsset extends AssetBundle\n" +"{\n" +" public ?string $basePath = '@assets/main';\n" +" public ?string $baseUrl = '@assetsUrl/main';\n" +" public ?string $sourcePath = '@assetsSource/main';\n" +"\n" +" public array $css = ['site.css'];\n" +" public array $js = ['site.js'];\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Register bundles through the asset manager in layouts or views." +msgstr "Registre os bundles pelo gerenciador de assets nos layouts ou views." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "See [Assets](../views/asset.md) and [Scripts, styles and metatags](../views/script-style-meta.md)." +msgstr "Veja [Assets](../views/asset.md) e [Scripts, estilos e metatags](../views/script-style-meta.md)." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "Models, forms, and validation" +msgstr "Models, formulários e validação" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii 1.1 has `CModel`, `CFormModel`, and `CActiveRecord`. It is common for one model class to contain input data, labels, validation rules, database persistence, and business logic." +msgstr "O Yii 1.1 tem `CModel`, `CFormModel` e `CActiveRecord`. É comum uma única classe de model conter os dados de entrada, rótulos, regras de validação, persistência no banco de dados e lógica de negócio." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii3 works better when these responsibilities are split:" +msgstr "O Yii3 funciona melhor quando essas responsabilidades são separadas:" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "form data and labels: `yiisoft/form-model`;" +msgstr "dados e rótulos do formulário: `yiisoft/form-model`;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "validation rules: `yiisoft/validator`;" +msgstr "regras de validação: `yiisoft/validator`;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "form rendering: `yiisoft/form`;" +msgstr "renderização de formulários: `yiisoft/form`;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "persistence: repositories, `yiisoft/db`, or `yiisoft/active-record`;" +msgstr "persistência: repositórios, `yiisoft/db` ou `yiisoft/active-record`;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "business workflows: application services." +msgstr "fluxos de negócio: serviços da aplicação." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii 1.1 form model:" +msgstr "Form model no Yii 1.1:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"class ContactForm extends CFormModel\n" +"{\n" +" public $name;\n" +" public $email;\n" +"\n" +" public function rules()\n" +" {\n" +" return [\n" +" ['name, email', 'required'],\n" +" ['email', 'email'],\n" +" ];\n" +" }\n" +"}\n" +msgstr "" +"class ContactForm extends CFormModel\n" +"{\n" +" public $name;\n" +" public $email;\n" +"\n" +" public function rules()\n" +" {\n" +" return [\n" +" ['name, email', 'required'],\n" +" ['email', 'email'],\n" +" ];\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii3 form model:" +msgstr "Form model no Yii3:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"use Yiisoft\\FormModel\\FormModel;\n" +"use Yiisoft\\Validator\\Rule\\Email;\n" +"use Yiisoft\\Validator\\Rule\\Required;\n" +"\n" +"final class ContactForm extends FormModel\n" +"{\n" +" #[Required]\n" +" public ?string $name = null;\n" +"\n" +" #[Required]\n" +" #[Email]\n" +" public ?string $email = null;\n" +"}\n" +msgstr "" +"use Yiisoft\\FormModel\\FormModel;\n" +"use Yiisoft\\Validator\\Rule\\Email;\n" +"use Yiisoft\\Validator\\Rule\\Required;\n" +"\n" +"final class ContactForm extends FormModel\n" +"{\n" +" #[Required]\n" +" public ?string $name = null;\n" +"\n" +" #[Required]\n" +" #[Email]\n" +" public ?string $email = null;\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "See [Working with forms](../start/forms.md), [Validating input](https://github.com/yiisoft/validator/blob/master/docs/guide/en/README.md), [yiisoft/form](https://github.com/yiisoft/form), and [yiisoft/form-model](https://github.com/yiisoft/form-model)." +msgstr "Veja [Trabalhando com formulários](../start/forms.md), [Validando a entrada](https://github.com/yiisoft/validator/blob/master/docs/guide/en/README.md), [yiisoft/form](https://github.com/yiisoft/form) e [yiisoft/form-model](https://github.com/yiisoft/form-model)." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "Active Record" +msgstr "Active Record" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii 1.1 Active Record uses `CActiveRecord::model()` and dynamic attributes:" +msgstr "O Active Record do Yii 1.1 usa `CActiveRecord::model()` e atributos dinâmicos:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"class Post extends CActiveRecord\n" +"{\n" +" public static function model($className = __CLASS__)\n" +" {\n" +" return parent::model($className);\n" +" }\n" +"\n" +" public function tableName()\n" +" {\n" +" return '{{post}}';\n" +" }\n" +"\n" +" public function rules()\n" +" {\n" +" return [\n" +" ['title, body', 'required'],\n" +" ['title', 'length', 'max' => 255],\n" +" ];\n" +" }\n" +"}\n" +msgstr "" +"class Post extends CActiveRecord\n" +"{\n" +" public static function model($className = __CLASS__)\n" +" {\n" +" return parent::model($className);\n" +" }\n" +"\n" +" public function tableName()\n" +" {\n" +" return '{{post}}';\n" +" }\n" +"\n" +" public function rules()\n" +" {\n" +" return [\n" +" ['title, body', 'required'],\n" +" ['title', 'length', 'max' => 255],\n" +" ];\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "The incremental Yii3 option is [yiisoft/active-record](https://github.com/yiisoft/active-record):" +msgstr "A opção incremental no Yii3 é o [yiisoft/active-record](https://github.com/yiisoft/active-record):" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"use Yiisoft\\ActiveRecord\\ActiveRecord;\n" +"\n" +"final class Post extends ActiveRecord\n" +"{\n" +" protected int $id;\n" +" protected string $title;\n" +" protected string $body;\n" +"\n" +" public function tableName(): string\n" +" {\n" +" return '{{%post}}';\n" +" }\n" +"\n" +" public function getTitle(): ?string\n" +" {\n" +" return $this->title ?? null;\n" +" }\n" +"\n" +" public function setTitle(string $title): void\n" +" {\n" +" $this->title = $title;\n" +" }\n" +"}\n" +msgstr "" +"use Yiisoft\\ActiveRecord\\ActiveRecord;\n" +"\n" +"final class Post extends ActiveRecord\n" +"{\n" +" protected int $id;\n" +" protected string $title;\n" +" protected string $body;\n" +"\n" +" public function tableName(): string\n" +" {\n" +" return '{{%post}}';\n" +" }\n" +"\n" +" public function getTitle(): ?string\n" +" {\n" +" return $this->title ?? null;\n" +" }\n" +"\n" +" public function setTitle(string $title): void\n" +" {\n" +" $this->title = $title;\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Move Yii 1.1 `rules()` to a form model, validator rules, or a service. Keep Active Record focused on persistence: table mapping, properties, relations, and database operations." +msgstr "Mova o `rules()` do Yii 1.1 para um form model, regras do validator ou um serviço. Mantenha o Active Record focado em persistência: mapeamento de tabelas, propriedades, relações e operações no banco de dados." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "For more complex applications, consider replacing Active Record-heavy code with repositories and domain objects. That is more work initially, but it avoids carrying Yii 1.1 form and persistence coupling into the new application." +msgstr "Em aplicações mais complexas, considere substituir o código muito dependente de Active Record por repositórios e objetos de domínio. Dá mais trabalho no início, mas evita carregar o acoplamento entre formulário e persistência do Yii 1.1 para a nova aplicação." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "See [Working with databases](../start/databases.md), [Migrations](../databases/db-migrations.md), and [yiisoft/active-record](https://github.com/yiisoft/active-record)." +msgstr "Veja [Trabalhando com banco de dados](../start/databases.md), [Migrations](../databases/db-migrations.md) e [yiisoft/active-record](https://github.com/yiisoft/active-record)." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "Database queries and migrations" +msgstr "Consultas ao banco de dados e migrations" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii 1.1 code may use `CDbCriteria`, `CDbCommand`, `CActiveDataProvider`, and `CGridView` data providers. In Yii3, use `yiisoft/db` for database access and query building, and `yiisoft/data` / `yiisoft/yii-dataview` for data readers and widgets." +msgstr "O código Yii 1.1 pode usar `CDbCriteria`, `CDbCommand`, `CActiveDataProvider` e data providers do `CGridView`. No Yii3, use `yiisoft/db` para acesso ao banco de dados e construção de consultas, e `yiisoft/data` / `yiisoft/yii-dataview` para data readers e widgets." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Migrations are not compatible across Yii 1.1 and Yii3. For an existing application, create a baseline from the current schema and use Yii3 migrations for new changes." +msgstr "As migrations não são compatíveis entre o Yii 1.1 e o Yii3. Para uma aplicação existente, crie uma base a partir do esquema atual e use migrations do Yii3 para as novas mudanças." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "See [Working with databases](../start/databases.md) and [Migrations](../databases/db-migrations.md)." +msgstr "Veja [Trabalhando com banco de dados](../start/databases.md) e [Migrations](../databases/db-migrations.md)." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "GridView and data widgets" +msgstr "GridView e widgets de dados" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii 1.1 `CGridView` is often configured with `CActiveDataProvider`:" +msgstr "O `CGridView` do Yii 1.1 costuma ser configurado com `CActiveDataProvider`:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"$this->widget('zii.widgets.grid.CGridView', [\n" +" 'dataProvider' => $dataProvider,\n" +" 'columns' => [\n" +" 'id',\n" +" 'title',\n" +" [\n" +" 'class' => 'CButtonColumn',\n" +" ],\n" +" ],\n" +"]);\n" +msgstr "" +"$this->widget('zii.widgets.grid.CGridView', [\n" +" 'dataProvider' => $dataProvider,\n" +" 'columns' => [\n" +" 'id',\n" +" 'title',\n" +" [\n" +" 'class' => 'CButtonColumn',\n" +" ],\n" +" ],\n" +"]);\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii3 uses [yiisoft/yii-dataview](https://github.com/yiisoft/yii-dataview):" +msgstr "O Yii3 usa o [yiisoft/yii-dataview](https://github.com/yiisoft/yii-dataview):" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"use Yiisoft\\Data\\Reader\\ReadableDataInterface;\n" +"use Yiisoft\\Yii\\DataView\\Column\\DataColumn;\n" +"use Yiisoft\\Yii\\DataView\\GridView\\Column\\ActionColumn;\n" +"use Yiisoft\\Yii\\DataView\\GridView\\GridView;\n" +"\n" +"/**\n" +" * @var ReadableDataInterface $dataReader\n" +" */\n" +"\n" +"echo GridView::widget()\n" +" ->dataReader($dataReader)\n" +" ->columns(\n" +" new DataColumn('id'),\n" +" new DataColumn('title'),\n" +" new ActionColumn(),\n" +" );\n" +msgstr "" +"use Yiisoft\\Data\\Reader\\ReadableDataInterface;\n" +"use Yiisoft\\Yii\\DataView\\Column\\DataColumn;\n" +"use Yiisoft\\Yii\\DataView\\GridView\\Column\\ActionColumn;\n" +"use Yiisoft\\Yii\\DataView\\GridView\\GridView;\n" +"\n" +"/**\n" +" * @var ReadableDataInterface $dataReader\n" +" */\n" +"\n" +"echo GridView::widget()\n" +" ->dataReader($dataReader)\n" +" ->columns(\n" +" new DataColumn('id'),\n" +" new DataColumn('title'),\n" +" new ActionColumn(),\n" +" );\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Replace the old data provider with a query service that returns a data reader. Model filters as validator rules and route or query parameters." +msgstr "Substitua o antigo data provider por um serviço de consulta que retorne um data reader. Modele os filtros como regras do validator e parâmetros de rota ou de consulta." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "See [Using htmx for partial reloads](../../cookbook/using-htmx-for-partial-reloads.md) and [yii-dataview GridView docs](https://github.com/yiisoft/yii-dataview/blob/master/docs/en/guide/gridview.md)." +msgstr "Veja [Usando htmx para recarregamentos parciais](../../cookbook/using-htmx-for-partial-reloads.md) e a [documentação do GridView do yii-dataview](https://github.com/yiisoft/yii-dataview/blob/master/docs/en/guide/gridview.md)." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "URL management" +msgstr "Gerenciamento de URLs" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"echo CHtml::link('View', ['post/view', 'id' => $post->id]);\n" +"$url = Yii::app()->createUrl('post/view', ['id' => $post->id]);\n" +msgstr "" +"echo CHtml::link('View', ['post/view', 'id' => $post->id]);\n" +"$url = Yii::app()->createUrl('post/view', ['id' => $post->id]);\n" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"use Yiisoft\\Html\\Html;\n" +"use Yiisoft\\Router\\UrlGeneratorInterface;\n" +"\n" +"$url = $urlGenerator->generate('post/view', ['id' => $post->getId()]);\n" +"\n" +"echo Html::a('View', $url)->render();\n" +msgstr "" +"use Yiisoft\\Html\\Html;\n" +"use Yiisoft\\Router\\UrlGeneratorInterface;\n" +"\n" +"$url = $urlGenerator->generate('post/view', ['id' => $post->getId()]);\n" +"\n" +"echo Html::a('View', $url)->render();\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Prefer named routes. They make views and GridView action columns easier to design and maintain." +msgstr "Prefira rotas nomeadas. Elas tornam as views e as colunas de action do GridView mais fáceis de projetar e manter." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "See [Routing and URL generation](../runtime/routing.md)." +msgstr "Veja [Roteamento e geração de URLs](../runtime/routing.md)." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "Filters, access control, and authentication" +msgstr "Filtros, controle de acesso e autenticação" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii 1.1 controller filters are controller methods or filter classes:" +msgstr "Os filtros de controller do Yii 1.1 são métodos do controller ou classes de filtro:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"public function filters()\n" +"{\n" +" return [\n" +" 'accessControl',\n" +" ];\n" +"}\n" +msgstr "" +"public function filters()\n" +"{\n" +" return [\n" +" 'accessControl',\n" +" ];\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii3 uses middleware and focused packages. Move authentication, authorization, CSRF, locale detection, and request body parsing out of controllers and into middleware or services." +msgstr "O Yii3 usa middleware e pacotes focados. Mova autenticação, autorização, CSRF, detecção de idioma e parsing do corpo da requisição para fora dos controllers, em middlewares ou serviços." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "See [Middleware](../structure/middleware.md), [Authentication](../security/authentication.md), and [Authorization](../security/authorization.md)." +msgstr "Veja [Middleware](../structure/middleware.md), [Autenticação](../security/authentication.md) e [Autorização](../security/authorization.md)." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "Widgets, helpers, and extensions" +msgstr "Widgets, helpers e extensões" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii 1.1 widgets and helpers usually depend on Yii-specific base classes such as `CWidget`, `CHtml`, and extension autoloading. In Yii3:" +msgstr "Os widgets e helpers do Yii 1.1 geralmente dependem de classes base específicas do Yii, como `CWidget` e `CHtml`, e do autoloading de extensões. No Yii3:" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "replace helper calls with `yiisoft/html`, `yiisoft/arrays`, `yiisoft/strings`, or application helpers;" +msgstr "substitua as chamadas a helpers por `yiisoft/html`, `yiisoft/arrays`, `yiisoft/strings` ou helpers da aplicação;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "replace extensions with Composer packages;" +msgstr "substitua as extensões por pacotes Composer;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "rebuild custom widgets with `yiisoft/widget` or plain services/templates;" +msgstr "reconstrua widgets personalizados com `yiisoft/widget` ou com serviços/templates simples;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "replace jQuery UI and Bootstrap widgets with current frontend packages or Yii3 widget packages where available." +msgstr "substitua os widgets do jQuery UI e do Bootstrap por pacotes de frontend atuais ou pacotes de widgets do Yii3, quando disponíveis." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "See [Widgets](../views/widget.md)." +msgstr "Veja [Widgets](../views/widget.md)." + +#. type: Title # +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/tutorial/console-applications.md +#, no-wrap +msgid "Console applications" +msgstr "Aplicações de console" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii 1.1 console commands extend `CConsoleCommand`:" +msgstr "Os comandos de console do Yii 1.1 estendem `CConsoleCommand`:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"class ReportCommand extends CConsoleCommand\n" +"{\n" +" public function actionSend()\n" +" {\n" +" }\n" +"}\n" +msgstr "" +"class ReportCommand extends CConsoleCommand\n" +"{\n" +" public function actionSend()\n" +" {\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii3 console commands are Symfony Console commands configured as services:" +msgstr "Os comandos de console do Yii3 são comandos do Symfony Console configurados como serviços:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "" +"namespace App\\Console;\n" +"\n" +"use Symfony\\Component\\Console\\Attribute\\AsCommand;\n" +"use Symfony\\Component\\Console\\Command\\Command;\n" +"use Symfony\\Component\\Console\\Input\\InputInterface;\n" +"use Symfony\\Component\\Console\\Output\\OutputInterface;\n" +"\n" +"#[AsCommand(name: 'report/send')]\n" +"final class SendReportCommand extends Command\n" +"{\n" +" protected function execute(InputInterface $input, OutputInterface $output): int\n" +" {\n" +" return Command::SUCCESS;\n" +" }\n" +"}\n" +msgstr "" +"namespace App\\Console;\n" +"\n" +"use Symfony\\Component\\Console\\Attribute\\AsCommand;\n" +"use Symfony\\Component\\Console\\Command\\Command;\n" +"use Symfony\\Component\\Console\\Input\\InputInterface;\n" +"use Symfony\\Component\\Console\\Output\\OutputInterface;\n" +"\n" +"#[AsCommand(name: 'report/send')]\n" +"final class SendReportCommand extends Command\n" +"{\n" +" protected function execute(InputInterface $input, OutputInterface $output): int\n" +" {\n" +" return Command::SUCCESS;\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "See [Console applications](../tutorial/console-applications.md)." +msgstr "Veja [Aplicações de console](../tutorial/console-applications.md)." + +#. type: Title # +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "Internationalization" +msgstr "Internacionalização" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "Yii 1.1 message files under `protected/messages` can usually be kept conceptually, but configuration changes. Yii3 uses translator packages and explicit message sources. Move message files into the structure expected by the selected translator message package and inject translation services where needed." +msgstr "Os arquivos de mensagens do Yii 1.1 em `protected/messages` geralmente podem ser mantidos conceitualmente, mas a configuração muda. O Yii3 usa pacotes de tradução e fontes de mensagens explícitas. Mova os arquivos de mensagens para a estrutura esperada pelo pacote de mensagens do tradutor escolhido e injete os serviços de tradução onde for necessário." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "See [Internationalization](../tutorial/i18n.md)." +msgstr "Veja [Internacionalização](../tutorial/i18n.md)." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v1.md +#, no-wrap +msgid "What to refactor before reusing" +msgstr "O que refatorar antes de reutilizar" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "These Yii 1.1 refactorings make the old behavior easier to understand and reuse:" +msgstr "Estas refatorações no Yii 1.1 tornam o comportamento antigo mais fácil de entender e reutilizar:" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "isolate database queries from controllers;" +msgstr "isole as consultas ao banco de dados dos controllers;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "remove direct `Yii::app()` access from domain code;" +msgstr "remova o acesso direto a `Yii::app()` do código de domínio;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "move validation out of Active Record when it describes request input rather than database invariants;" +msgstr "tire a validação do Active Record quando ela descreve a entrada da requisição, e não invariantes do banco de dados;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "replace large controller actions with services;" +msgstr "substitua actions grandes de controller por serviços;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "document all routes and URL rules;" +msgstr "documente todas as rotas e regras de URL;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "add tests around the flows you plan to rebuild first;" +msgstr "adicione testes em torno dos fluxos que você planeja reconstruir primeiro;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md +msgid "upgrade PHP syntax gradually if the old runtime allows it." +msgstr "atualize a sintaxe PHP gradualmente, se o runtime antigo permitir." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md +msgid "The goal is not to make Yii 1.1 look like Yii3. The goal is to reduce hidden coupling before the code crosses the framework boundary." +msgstr "O objetivo não é fazer o Yii 1.1 parecer com o Yii3. O objetivo é reduzir o acoplamento oculto antes que o código cruze a fronteira do framework." diff --git a/_translations/po/pt-BR/guide_intro_upgrade-from-v2.md.po b/_translations/po/pt-BR/guide_intro_upgrade-from-v2.md.po new file mode 100644 index 00000000..cff915a9 --- /dev/null +++ b/_translations/po/pt-BR/guide_intro_upgrade-from-v2.md.po @@ -0,0 +1,1754 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-09-25 14:35+0000\n" +"PO-Revision-Date: 2026-09-25 14:35+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/deployment/angie-docker-proxy.md ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Project structure" +msgstr "Estrutura do projeto" + +#. type: Title ### +#: ../src/cookbook/making-http-requests.md ../src/guide/index.md ../src/guide/intro/upgrade-from-v2.md ../src/guide/testing/overview.md ../src/guide/tutorial/docker.md +#, no-wrap +msgid "Testing" +msgstr "Testes" + +#. type: Fenced code block (json) +#: ../src/guide/concept/autoloading.md ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"{\n" +" \"autoload\": {\n" +" \"psr-4\": {\n" +" \"App\\\\\": \"src/\"\n" +" }\n" +" }\n" +"}\n" +msgstr "" +"{\n" +" \"autoload\": {\n" +" \"psr-4\": {\n" +" \"App\\\\\": \"src/\"\n" +" }\n" +" }\n" +"}\n" + +#. type: Fenced code block (php) +#: ../src/guide/concept/configuration.md ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"use App\\Web;\n" +"use Yiisoft\\Router\\Group;\n" +"use Yiisoft\\Router\\Route;\n" +"\n" +"return [\n" +" Group::create()\n" +" ->routes(\n" +" Route::get('/')\n" +" ->action(Web\\HomePage\\Action::class)\n" +" ->name('home'),\n" +" ),\n" +"];\n" +msgstr "" +"use App\\Web;\n" +"use Yiisoft\\Router\\Group;\n" +"use Yiisoft\\Router\\Route;\n" +"\n" +"return [\n" +" Group::create()\n" +" ->routes(\n" +" Route::get('/')\n" +" ->action(Web\\HomePage\\Action::class)\n" +" ->name('home'),\n" +" ),\n" +"];\n" + +#. type: Title ## +#: ../src/guide/index.md ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "REST APIs" +msgstr "APIs REST" + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Recommended approach" +msgstr "Abordagem recomendada" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "For example, instead of reading post archive data directly from several controllers or widgets, create a small service that describes the application need:" +msgstr "Por exemplo, em vez de ler os dados do arquivo de posts diretamente em vários controllers ou widgets, crie um pequeno serviço que descreva a necessidade da aplicação:" + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Things to learn before starting" +msgstr "O que aprender antes de começar" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "[Docker](https://www.docker.com/get-started/). The default Yii3 application template includes Docker configuration. Using it gives each application its own repeatable environment and reduces differences between local development and production." +msgstr "[Docker](https://www.docker.com/get-started/). O template de aplicação padrão do Yii3 inclui configuração do Docker. Usá-lo dá a cada aplicação seu próprio ambiente reproduzível e reduz as diferenças entre o desenvolvimento local e a produção." + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "[Environment variables](https://en.wikipedia.org/wiki/Environment_variable). Yii3 templates commonly use them for environment-specific settings and secrets, especially in Docker-based deployments. This follows the same idea as [12-factor app configuration](https://12factor.net/config)." +msgstr "[Variáveis de ambiente](https://en.wikipedia.org/wiki/Environment_variable). Os templates do Yii3 costumam usá-las para configurações específicas de ambiente e segredos, especialmente em deploys baseados em Docker. Isso segue a mesma ideia da [configuração de aplicações 12-factor](https://12factor.net/config)." + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "[Actions](../structure/action.md). Yii3 does not require controller inheritance. A route can point to any callable, and the default template uses invokable action classes." +msgstr "[Actions](../structure/action.md). O Yii3 não exige herança de controller. Uma rota pode apontar para qualquer callable, e o template padrão usa classes de action invocáveis." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "Configure your application namespace with PSR-4:" +msgstr "Configure o namespace da sua aplicação com PSR-4:" + +#. type: Fenced code block (shell) +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "composer dump-autoload\n" +msgstr "composer dump-autoload\n" + +#. type: Fenced code block (text) +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"assets/\n" +"config/\n" +"public/\n" +"runtime/\n" +"src/\n" +"tests/\n" +msgstr "" +"assets/\n" +"config/\n" +"public/\n" +"runtime/\n" +"src/\n" +"tests/\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "Typical mappings to consider are:" +msgstr "Mapeamentos típicos a considerar:" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "See [Configuration](../concept/configuration.md), [Aliases](../concept/aliases.md), and [Dependency injection container](../concept/di-container.md)." +msgstr "Veja [Configuração](../concept/configuration.md), [Aliases](../concept/aliases.md) e [Container de injeção de dependência](../concept/di-container.md)." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "See [Entry scripts](../structure/entry-script.md) and [Application workflow](../start/workflow.md)." +msgstr "Veja [Scripts de entrada](../structure/entry-script.md) e [Fluxo da aplicação](../start/workflow.md)." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "See [Actions](../structure/action.md), [Middleware](../structure/middleware.md), and [Routing and URL generation](../runtime/routing.md)." +msgstr "Veja [Actions](../structure/action.md), [Middleware](../structure/middleware.md) e [Roteamento e geração de URLs](../runtime/routing.md)." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "See [Request](../runtime/request.md), [Response](../runtime/response.md), [Sessions](../runtime/sessions.md), and [Cookies](../runtime/cookies.md)." +msgstr "Veja [Requisição](../runtime/request.md), [Resposta](../runtime/response.md), [Sessões](../runtime/sessions.md) e [Cookies](../runtime/cookies.md)." + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"use Yiisoft\\FormModel\\FormModel;\n" +"use Yiisoft\\Validator\\Rule\\Email;\n" +"use Yiisoft\\Validator\\Rule\\Required;\n" +"\n" +"final class ContactForm extends FormModel\n" +"{\n" +" #[Required]\n" +" public ?string $name = null;\n" +"\n" +" #[Required]\n" +" #[Email]\n" +" public ?string $email = null;\n" +"}\n" +msgstr "" +"use Yiisoft\\FormModel\\FormModel;\n" +"use Yiisoft\\Validator\\Rule\\Email;\n" +"use Yiisoft\\Validator\\Rule\\Required;\n" +"\n" +"final class ContactForm extends FormModel\n" +"{\n" +" #[Required]\n" +" public ?string $name = null;\n" +"\n" +" #[Required]\n" +" #[Email]\n" +" public ?string $email = null;\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "See [Working with forms](../start/forms.md), [Validating input](https://github.com/yiisoft/validator/blob/master/docs/guide/en/README.md), [yiisoft/form](https://github.com/yiisoft/form), and [yiisoft/form-model](https://github.com/yiisoft/form-model)." +msgstr "Veja [Trabalhando com formulários](../start/forms.md), [Validando a entrada](https://github.com/yiisoft/validator/blob/master/docs/guide/en/README.md), [yiisoft/form](https://github.com/yiisoft/form) e [yiisoft/form-model](https://github.com/yiisoft/form-model)." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "See [Working with databases](../start/databases.md), [Migrations](../databases/db-migrations.md), and [yiisoft/active-record](https://github.com/yiisoft/active-record)." +msgstr "Veja [Trabalhando com banco de dados](../start/databases.md), [Migrations](../databases/db-migrations.md) e [yiisoft/active-record](https://github.com/yiisoft/active-record)." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "GridView and data widgets" +msgstr "GridView e widgets de dados" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "See [Middleware](../structure/middleware.md), [Authentication](../security/authentication.md), and [Authorization](../security/authorization.md)." +msgstr "Veja [Middleware](../structure/middleware.md), [Autenticação](../security/authentication.md) e [Autorização](../security/authorization.md)." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/intro/upgrade-from-v2.md +msgid "See [Console applications](../tutorial/console-applications.md)." +msgstr "Veja [Aplicações de console](../tutorial/console-applications.md)." + +#. type: Title # +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Upgrading from Version 2.0" +msgstr "Migrando da versão 2.0" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"> If you haven't used Yii 2.0, you can skip this section and get directly to \"[getting started](../start/prerequisites.md)\"\n" +"> section.\n" +msgstr "" +"> Se você não usou o Yii 2.0, pode pular esta seção e ir direto para a seção \"[primeiros passos](../start/prerequisites.md)\"\n" +"> do guia.\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Yii3 keeps many Yii ideas, but it is not a drop-in replacement for Yii 2.0. It uses PHP 8 features, PSR interfaces, dependency injection, explicit package composition, and a different application template. Use your Yii 2.0 experience to design a new Yii3 application deliberately instead of trying to reproduce the old application structure." +msgstr "O Yii3 mantém muitas ideias do Yii, mas não é um substituto direto do Yii 2.0. Ele usa recursos do PHP 8, interfaces PSR, injeção de dependência, composição explícita de pacotes e um template de aplicação diferente. Use sua experiência com o Yii 2.0 para projetar uma nova aplicação Yii3 de forma deliberada, em vez de tentar reproduzir a estrutura da aplicação antiga." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "For source applications, compare against:" +msgstr "Para as aplicações de origem, compare com:" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "[yiisoft/yii2-app-basic](https://github.com/yiisoft/yii2-app-basic)" +msgstr "[yiisoft/yii2-app-basic](https://github.com/yiisoft/yii2-app-basic)" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "[yiisoft/yii2-app-advanced](https://github.com/yiisoft/yii2-app-advanced)" +msgstr "[yiisoft/yii2-app-advanced](https://github.com/yiisoft/yii2-app-advanced)" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "For the target structure, compare against:" +msgstr "Para a estrutura de destino, compare com:" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "[yiisoft/app](https://github.com/yiisoft/app)" +msgstr "[yiisoft/app](https://github.com/yiisoft/app)" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "[Yii3 guide](../index.md)" +msgstr "[Guia do Yii3](../index.md)" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Before starting, [check maintenance policy and end-of-life dates for Yii 2.0](https://www.yiiframework.com/release-cycle). Keeping a mature Yii 2.0 application on Yii 2.0 can be a valid choice. A Yii3 project is most useful when you want the new package ecosystem, stricter typing, PSR middleware, and a more explicit architecture." +msgstr "Antes de começar, [confira a política de manutenção e as datas de fim de vida do Yii 2.0](https://www.yiiframework.com/release-cycle). Manter uma aplicação Yii 2.0 madura no Yii 2.0 pode ser uma escolha válida. Um projeto Yii3 é mais útil quando você quer o novo ecossistema de pacotes, tipagem mais rigorosa, middleware PSR e uma arquitetura mais explícita." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Think of the work as building a Yii3 application that is informed by the old one. The old project tells you which routes, forms, database tables, business rules, and user workflows matter. The Yii3 project should decide again where these responsibilities belong." +msgstr "Pense no trabalho como a construção de uma aplicação Yii3 guiada pela antiga. O projeto antigo diz quais rotas, formulários, tabelas do banco de dados, regras de negócio e fluxos dos usuários importam. O projeto Yii3 deve decidir de novo onde cada uma dessas responsabilidades fica." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Build it in vertical slices:" +msgstr "Construa em vertical slices:" + +#. type: Bullet: '1. ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Create a new Yii3 application with `yiisoft/app`." +msgstr "Crie uma nova aplicação Yii3 com `yiisoft/app`." + +#. type: Bullet: '2. ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Configure Composer autoloading and add only the code needed for the slice you are building." +msgstr "Configure o autoloading do Composer e adicione só o código necessário para o slice que você está construindo." + +#. type: Bullet: '3. ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Define configuration and routes before writing actions." +msgstr "Defina a configuração e as rotas antes de escrever as actions." + +#. type: Bullet: '4. ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Build one request flow at a time: route, action, input model, service, persistence, view, assets, tests." +msgstr "Construa um fluxo de requisição por vez: rota, action, modelo de entrada, serviço, persistência, view, assets, testes." + +#. type: Bullet: '5. ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Keep the Yii 2.0 application running until each flow is verified in Yii3." +msgstr "Mantenha a aplicação Yii 2.0 rodando até cada fluxo ser verificado no Yii3." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Avoid moving the whole directory tree first. Yii3's defaults are intentionally different, and a mechanical copy tends to preserve Yii 2.0 service-locator assumptions. Prefer small, reviewed decisions over carrying old structure forward because it is familiar." +msgstr "Evite mover toda a árvore de diretórios primeiro. Os padrões do Yii3 são intencionalmente diferentes, e uma cópia mecânica tende a preservar as suposições de service locator do Yii 2.0. Prefira decisões pequenas e revisadas a carregar a estrutura antiga só porque ela é familiar." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Prepare the Yii 2.0 application" +msgstr "Prepare a aplicação Yii 2.0" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Useful preparation can happen before the Yii3 application is ready. These refactorings improve the Yii 2.0 project itself and make the later rewrite less dependent on hidden framework state:" +msgstr "Uma preparação útil pode acontecer antes de a aplicação Yii3 estar pronta. Estas refatorações melhoram o próprio projeto Yii 2.0 e deixam a reescrita posterior menos dependente de estado oculto do framework:" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Replace `Yii::$app` access in reusable code with constructor arguments where practical. If a full dependency injection refactoring is too large, keep `Yii::$app` calls near controllers and widgets, then pass values and services to lower-level code explicitly." +msgstr "Substitua o acesso a `Yii::$app` no código reutilizável por argumentos do construtor onde for viável. Se uma refatoração completa para injeção de dependência for grande demais, mantenha as chamadas a `Yii::$app` perto de controllers e widgets, e passe valores e serviços explicitamente para o código de nível mais baixo." + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Introduce repositories or query services for database reads that are currently scattered across controllers, views, widgets, and Active Record methods. Yii3 does not require Active Record for persistence, so a repository boundary gives you a natural place to change the implementation later." +msgstr "Introduza repositórios ou serviços de consulta para as leituras do banco de dados hoje espalhadas por controllers, views, widgets e métodos do Active Record. O Yii3 não exige Active Record para persistência, então uma fronteira de repositório dá a você um lugar natural para trocar a implementação depois." + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Separate business rules from framework infrastructure. Domain code that does not extend Yii classes, read global application state, or render views is much easier to reuse or rewrite." +msgstr "Separe as regras de negócio da infraestrutura do framework. Código de domínio que não estende classes do Yii, não lê o estado global da aplicação nem renderiza views é muito mais fácil de reutilizar ou reescrever." + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Move reusable behavior into Yii 2.0 components or services instead of keeping it inside large controllers and Active Record classes. Yii3 services are configured and injected differently, but the responsibility boundary is similar." +msgstr "Mova o comportamento reutilizável para componentes ou serviços do Yii 2.0 em vez de mantê-lo dentro de controllers e classes Active Record grandes. Os serviços do Yii3 são configurados e injetados de outra forma, mas a fronteira de responsabilidade é parecida." + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Add tests around routes and workflows you plan to rebuild first. They become the executable specification for the Yii3 slice." +msgstr "Adicione testes em torno das rotas e fluxos que você planeja reconstruir primeiro. Eles se tornam a especificação executável do slice Yii3." + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"final class PostRepository\n" +"{\n" +" public function getArchive(): array\n" +" {\n" +" // ...\n" +" }\n" +"\n" +" public function getTopForFrontPage(int $limit = 10): array\n" +" {\n" +" // ...\n" +" }\n" +"}\n" +msgstr "" +"final class PostRepository\n" +"{\n" +" public function getArchive(): array\n" +" {\n" +" // ...\n" +" }\n" +"\n" +" public function getTopForFrontPage(int $limit = 10): array\n" +" {\n" +" // ...\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "The Yii3 implementation may still use Active Record, or it may use `yiisoft/db` queries. The important point is that controllers and views no longer need to know that detail." +msgstr "A implementação no Yii3 ainda pode usar Active Record, ou pode usar consultas do `yiisoft/db`. O importante é que controllers e views não precisem mais conhecer esse detalhe." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Some Yii3 application-template choices are worth learning before you start moving features:" +msgstr "Vale a pena conhecer algumas escolhas do template de aplicação do Yii3 antes de começar a mover funcionalidades:" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "[Application structure](../structure/overview.md). Yii3's default structure is different from Yii 2.0. The structure is flexible, but start with the Yii3 template and change it only when the application needs it." +msgstr "[Estrutura da aplicação](../structure/overview.md). A estrutura padrão do Yii3 é diferente da do Yii 2.0. Ela é flexível, mas comece com o template do Yii3 e altere-o apenas quando a aplicação precisar." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "PHP requirements" +msgstr "Requisitos de PHP" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Yii3 application templates require PHP 8.2 or above. As a result, application code can use language features that were not common in Yii 2.0 applications:" +msgstr "Os templates de aplicação do Yii3 exigem PHP 8.2 ou superior. Com isso, o código da aplicação pode usar recursos da linguagem que não eram comuns em aplicações Yii 2.0:" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "[Type declarations](https://www.php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration)" +msgstr "[Declarações de tipo](https://www.php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration)" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "[Return type declarations](https://www.php.net/manual/en/functions.returning-values.php#functions.returning-values.type-declaration)" +msgstr "[Declarações de tipo de retorno](https://www.php.net/manual/en/functions.returning-values.php#functions.returning-values.type-declaration)" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "[Class constant visibility](https://www.php.net/manual/en/language.oop5.constants.php)" +msgstr "[Visibilidade de constantes de classe](https://www.php.net/manual/en/language.oop5.constants.php)" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "[Named arguments](https://www.php.net/manual/en/functions.arguments.php#functions.named-arguments)" +msgstr "[Argumentos nomeados](https://www.php.net/manual/en/functions.arguments.php#functions.named-arguments)" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "[Anonymous classes](https://www.php.net/manual/en/language.oop5.anonymous.php)" +msgstr "[Classes anônimas](https://www.php.net/manual/en/language.oop5.anonymous.php)" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "[::class](https://www.php.net/manual/en/language.oop5.basic.php#language.oop5.basic.class.class)" +msgstr "[::class](https://www.php.net/manual/en/language.oop5.basic.php#language.oop5.basic.class.class)" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "[Generators](https://www.php.net/manual/en/language.generators.php)" +msgstr "[Generators](https://www.php.net/manual/en/language.generators.php)" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "[Variadic functions](https://www.php.net/manual/en/functions.arguments.php#functions.variable-arg-list)" +msgstr "[Funções variádicas](https://www.php.net/manual/en/functions.arguments.php#functions.variable-arg-list)" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "[Readonly properties](https://www.php.net/manual/en/language.oop5.properties.php#language.oop5.properties.readonly-properties)" +msgstr "[Propriedades readonly](https://www.php.net/manual/en/language.oop5.properties.php#language.oop5.properties.readonly-properties)" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "[Readonly classes](https://www.php.net/manual/en/language.oop5.basic.php#language.oop5.basic.class.readonly)" +msgstr "[Classes readonly](https://www.php.net/manual/en/language.oop5.basic.php#language.oop5.basic.class.readonly)" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "[Constructor property promotion](https://www.php.net/manual/en/language.oop5.decon.php#language.oop5.decon.constructor.promotion)" +msgstr "[Promoção de propriedades no construtor](https://www.php.net/manual/en/language.oop5.decon.php#language.oop5.decon.constructor.promotion)" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "[Attributes](https://www.php.net/manual/en/language.attributes.php)" +msgstr "[Atributos](https://www.php.net/manual/en/language.attributes.php)" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Run static analysis and tests on Yii 2.0 before reusing code in Yii3. Code with explicit types, small services, and few implicit `Yii::$app` dependencies is easier to understand and easier to place in the new application." +msgstr "Rode análise estática e testes no Yii 2.0 antes de reutilizar código no Yii3. Código com tipos explícitos, serviços pequenos e poucas dependências implícitas de `Yii::$app` é mais fácil de entender e de encaixar na nova aplicação." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Yii 2.0 applications commonly keep framework roles in top-level directories:" +msgstr "Aplicações Yii 2.0 costumam manter os papéis do framework em diretórios de primeiro nível:" + +#. type: Fenced code block (text) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"assets/\n" +"commands/\n" +"config/\n" +"controllers/\n" +"models/\n" +"runtime/\n" +"views/\n" +"web/\n" +"widgets/\n" +msgstr "" +"assets/\n" +"commands/\n" +"config/\n" +"controllers/\n" +"models/\n" +"runtime/\n" +"views/\n" +"web/\n" +"widgets/\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "The Yii 2.0 advanced template splits the same roles by application:" +msgstr "O template advanced do Yii 2.0 divide os mesmos papéis por aplicação:" + +#. type: Fenced code block (text) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"backend/\n" +"common/\n" +"console/\n" +"frontend/\n" +msgstr "" +"backend/\n" +"common/\n" +"console/\n" +"frontend/\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "The current Yii3 application template is organized around source code, configuration, public files, and runtime files:" +msgstr "O template de aplicação atual do Yii3 é organizado em torno do código-fonte, da configuração, dos arquivos públicos e dos arquivos de runtime:" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"| Yii 2.0 basic | Yii 2.0 advanced | Yii3 |\n" +"|---------------|------------------|------|\n" +"| `controllers/` | `frontend/controllers/`, `backend/controllers/` | `src/Web/*/Action.php` or controller-like classes |\n" +"| `models/` | `common/models/`, app-specific models | `src/Domain`, `src/Shared`, `src/Web/*`, or `src/Db` by responsibility |\n" +"| `views/` | `frontend/views/`, `backend/views/` | templates near the feature, for example `src/Web/HomePage/template.php` |\n" +"| `views/layouts/` | app layout directories | layout classes/templates, for example `src/Web/Shared/Layout/Main` |\n" +"| `assets/` | app asset bundles | `assets/` for source files and `src/Web/.../*Asset.php` for bundles |\n" +"| `web/` | `frontend/web/`, `backend/web/` | `public/` |\n" +"| `commands/` | `console/controllers/` | `src/Console/*Command.php` |\n" +"| `config/*.php` | app and common config files | `config/common`, `config/web`, `config/console`, `config/environments` |\n" +msgstr "" +"| Yii 2.0 basic | Yii 2.0 advanced | Yii3 |\n" +"|---------------|------------------|------|\n" +"| `controllers/` | `frontend/controllers/`, `backend/controllers/` | `src/Web/*/Action.php` ou classes no estilo controller |\n" +"| `models/` | `common/models/`, models específicos de cada app | `src/Domain`, `src/Shared`, `src/Web/*` ou `src/Db`, conforme a responsabilidade |\n" +"| `views/` | `frontend/views/`, `backend/views/` | templates perto da funcionalidade, por exemplo `src/Web/HomePage/template.php` |\n" +"| `views/layouts/` | diretórios de layout de cada app | classes/templates de layout, por exemplo `src/Web/Shared/Layout/Main` |\n" +"| `assets/` | asset bundles de cada app | `assets/` para os arquivos-fonte e `src/Web/.../*Asset.php` para os bundles |\n" +"| `web/` | `frontend/web/`, `backend/web/` | `public/` |\n" +"| `commands/` | `console/controllers/` | `src/Console/*Command.php` |\n" +"| `config/*.php` | arquivos de configuração do app e comuns | `config/common`, `config/web`, `config/console`, `config/environments` |\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "There is no single required layout. The important change is that Yii3 applications should group code by responsibility and make dependencies explicit. If you are coming from the advanced template, treat `frontend` and `backend` as separate web contexts. Shared domain code can live in `src/Shared` or in application-specific packages." +msgstr "Não existe um layout obrigatório único. A mudança importante é que aplicações Yii3 devem agrupar o código por responsabilidade e tornar as dependências explícitas. Se você vem do template advanced, trate `frontend` e `backend` como contextos web separados. O código de domínio compartilhado pode ficar em `src/Shared` ou em pacotes específicos da aplicação." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Composer and autoloading" +msgstr "Composer e autoloading" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Yii 2.0 applications usually require `vendor/autoload.php` and `vendor/yiisoft/yii2/Yii.php` in `web/index.php`. Yii3 applications require only Composer's autoloader and application bootstrap code." +msgstr "Aplicações Yii 2.0 geralmente fazem require de `vendor/autoload.php` e `vendor/yiisoft/yii2/Yii.php` em `web/index.php`. Aplicações Yii3 precisam apenas do autoloader do Composer e do código de bootstrap da aplicação." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Then rebuild Composer autoload files:" +msgstr "Depois, reconstrua os arquivos de autoload do Composer:" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Install Yii3 packages intentionally. Yii3 is split into focused packages, so features such as database access, forms, validation, assets, data widgets, authentication, and caching are separate Composer dependencies." +msgstr "Instale os pacotes Yii3 de forma intencional. O Yii3 é dividido em pacotes focados, então funcionalidades como acesso ao banco de dados, formulários, validação, assets, widgets de dados, autenticação e cache são dependências separadas do Composer." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Configuration and services" +msgstr "Configuração e serviços" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "In Yii 2.0, many services are configured as application components and accessed through the service locator:" +msgstr "No Yii 2.0, muitos serviços são configurados como componentes da aplicação e acessados pelo service locator:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"$cache = Yii::$app->cache;\n" +"$db = Yii::$app->db;\n" +"$url = Yii::$app->urlManager->createUrl(['post/view', 'id' => $id]);\n" +msgstr "" +"$cache = Yii::$app->cache;\n" +"$db = Yii::$app->db;\n" +"$url = Yii::$app->urlManager->createUrl(['post/view', 'id' => $id]);\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "In Yii3, services are configured for the container and injected where they are needed:" +msgstr "No Yii3, os serviços são configurados no container e injetados onde são necessários:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"use Psr\\SimpleCache\\CacheInterface;\n" +"use Yiisoft\\Db\\Connection\\ConnectionInterface;\n" +"use Yiisoft\\Router\\UrlGeneratorInterface;\n" +"\n" +"final readonly class PostService\n" +"{\n" +" public function __construct(\n" +" private ConnectionInterface $db,\n" +" private CacheInterface $cache,\n" +" private UrlGeneratorInterface $urlGenerator,\n" +" ) {\n" +" }\n" +"}\n" +msgstr "" +"use Psr\\SimpleCache\\CacheInterface;\n" +"use Yiisoft\\Db\\Connection\\ConnectionInterface;\n" +"use Yiisoft\\Router\\UrlGeneratorInterface;\n" +"\n" +"final readonly class PostService\n" +"{\n" +" public function __construct(\n" +" private ConnectionInterface $db,\n" +" private CacheInterface $cache,\n" +" private UrlGeneratorInterface $urlGenerator,\n" +" ) {\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Move configuration in groups:" +msgstr "Mova a configuração por grupos:" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "aliases to `config/common/aliases.php`;" +msgstr "aliases para `config/common/aliases.php`;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "route definitions to `config/common/routes.php`;" +msgstr "definições de rotas para `config/common/routes.php`;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "shared service definitions to `config/common/di/*.php`;" +msgstr "definições de serviços compartilhadas para `config/common/di/*.php`;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "web-only service definitions to `config/web/di/*.php`;" +msgstr "definições de serviços apenas para web para `config/web/di/*.php`;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "console parameters and commands to `config/console/*.php`;" +msgstr "parâmetros e comandos de console para `config/console/*.php`;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "shared parameters to `config/common/params.php`;" +msgstr "parâmetros compartilhados para `config/common/params.php`;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "environment overrides to `config/environments`." +msgstr "sobrescritas por ambiente para `config/environments`." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "The default template's `di-console` group reuses shared definitions from `config/common/di/*.php`. If you need console-only container definitions, add the corresponding files to the `di-console` group in `config/configuration.php` and rebuild the merge plan." +msgstr "O grupo `di-console` do template padrão reutiliza as definições compartilhadas de `config/common/di/*.php`. Se você precisar de definições de container apenas para o console, adicione os arquivos correspondentes ao grupo `di-console` em `config/configuration.php` e reconstrua o merge plan." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Entry script and bootstrap" +msgstr "Script de entrada e bootstrap" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "A Yii 2.0 basic entry script commonly creates the application directly:" +msgstr "Um script de entrada do template basic do Yii 2.0 geralmente cria a aplicação diretamente:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"defined('YII_DEBUG') or define('YII_DEBUG', true);\n" +"defined('YII_ENV') or define('YII_ENV', 'dev');\n" +"\n" +"require __DIR__ . '/../vendor/autoload.php';\n" +"require __DIR__ . '/../vendor/yiisoft/yii2/Yii.php';\n" +"\n" +"$config = require __DIR__ . '/../config/web.php';\n" +"\n" +"(new yii\\web\\Application($config))->run();\n" +msgstr "" +"defined('YII_DEBUG') or define('YII_DEBUG', true);\n" +"defined('YII_ENV') or define('YII_ENV', 'dev');\n" +"\n" +"require __DIR__ . '/../vendor/autoload.php';\n" +"require __DIR__ . '/../vendor/yiisoft/yii2/Yii.php';\n" +"\n" +"$config = require __DIR__ . '/../config/web.php';\n" +"\n" +"(new yii\\web\\Application($config))->run();\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "In Yii3, use the application template entry script as the source of truth. It loads Composer and bootstraps the configured application runner. Avoid recreating the old `yii\\web\\Application` pattern in `public/index.php`; put configuration in config files and dependencies in the container." +msgstr "No Yii3, use o script de entrada do template de aplicação como fonte da verdade. Ele carrega o Composer e inicializa o runner da aplicação configurada. Evite recriar o antigo padrão `yii\\web\\Application` em `public/index.php`; coloque a configuração nos arquivos de configuração e as dependências no container." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Controllers, actions, and routing" +msgstr "Controllers, actions e roteamento" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Yii 2.0 routes usually point to controller action methods:" +msgstr "As rotas do Yii 2.0 geralmente apontam para métodos de action de controllers:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"namespace app\\controllers;\n" +"\n" +"use yii\\web\\Controller;\n" +"\n" +"final class SiteController extends Controller\n" +"{\n" +" public function actionIndex(): string\n" +" {\n" +" return $this->render('index');\n" +" }\n" +"}\n" +msgstr "" +"namespace app\\controllers;\n" +"\n" +"use yii\\web\\Controller;\n" +"\n" +"final class SiteController extends Controller\n" +"{\n" +" public function actionIndex(): string\n" +" {\n" +" return $this->render('index');\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Yii3 does not require controller base classes. The current application template uses invokable action classes:" +msgstr "O Yii3 não exige classes base de controller. O template de aplicação atual usa classes de action invocáveis:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"namespace App\\Web\\HomePage;\n" +"\n" +"use Psr\\Http\\Message\\ResponseInterface;\n" +"use Yiisoft\\Yii\\View\\Renderer\\WebViewRenderer;\n" +"\n" +"final readonly class Action\n" +"{\n" +" public function __construct(\n" +" private WebViewRenderer $viewRenderer,\n" +" ) {\n" +" }\n" +"\n" +" public function __invoke(): ResponseInterface\n" +" {\n" +" return $this->viewRenderer->render(__DIR__ . '/template');\n" +" }\n" +"}\n" +msgstr "" +"namespace App\\Web\\HomePage;\n" +"\n" +"use Psr\\Http\\Message\\ResponseInterface;\n" +"use Yiisoft\\Yii\\View\\Renderer\\WebViewRenderer;\n" +"\n" +"final readonly class Action\n" +"{\n" +" public function __construct(\n" +" private WebViewRenderer $viewRenderer,\n" +" ) {\n" +" }\n" +"\n" +" public function __invoke(): ResponseInterface\n" +" {\n" +" return $this->viewRenderer->render(__DIR__ . '/template');\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Routes are explicit:" +msgstr "As rotas são explícitas:" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "When redesigning a controller flow, list all Yii 2.0 actions and create named routes for the flows you still need. Then implement each flow as an invokable class or a controller-like service. Constructor injection replaces calls to `Yii::$app` and controller properties." +msgstr "Ao redesenhar o fluxo de um controller, liste todas as actions do Yii 2.0 e crie rotas nomeadas para os fluxos de que você ainda precisa. Depois, implemente cada fluxo como uma classe invocável ou um serviço no estilo controller. A injeção pelo construtor substitui as chamadas a `Yii::$app` e as propriedades do controller." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Requests, responses, sessions, and cookies" +msgstr "Requisições, respostas, sessões e cookies" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Yii 2.0 actions often read request data and write response data through application components:" +msgstr "As actions do Yii 2.0 frequentemente leem os dados da requisição e escrevem os dados da resposta por meio de componentes da aplicação:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"$id = Yii::$app->request->get('id');\n" +"Yii::$app->session->setFlash('success', 'Saved.');\n" +"\n" +"return $this->redirect(['post/view', 'id' => $id]);\n" +msgstr "" +"$id = Yii::$app->request->get('id');\n" +"Yii::$app->session->setFlash('success', 'Saved.');\n" +"\n" +"return $this->redirect(['post/view', 'id' => $id]);\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Yii3 uses PSR-7 request and response objects and injectable services:" +msgstr "O Yii3 usa objetos de requisição e resposta PSR-7 e serviços injetáveis:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"use Psr\\Http\\Message\\ResponseInterface;\n" +"use Psr\\Http\\Message\\ResponseFactoryInterface;\n" +"use Psr\\Http\\Message\\ServerRequestInterface;\n" +"use Yiisoft\\Http\\Status;\n" +"use Yiisoft\\Router\\UrlGeneratorInterface;\n" +"\n" +"final readonly class SavePostAction\n" +"{\n" +" public function __construct(\n" +" private ResponseFactoryInterface $responseFactory,\n" +" private UrlGeneratorInterface $urlGenerator,\n" +" ) {\n" +" }\n" +"\n" +" public function __invoke(ServerRequestInterface $request): ResponseInterface\n" +" {\n" +" $id = (int) ($request->getQueryParams()['id'] ?? 0);\n" +" $url = $this->urlGenerator->generate('post/view', ['id' => $id]);\n" +"\n" +" return $this->responseFactory\n" +" ->createResponse(Status::SEE_OTHER)\n" +" ->withHeader('Location', $url);\n" +" }\n" +"}\n" +msgstr "" +"use Psr\\Http\\Message\\ResponseInterface;\n" +"use Psr\\Http\\Message\\ResponseFactoryInterface;\n" +"use Psr\\Http\\Message\\ServerRequestInterface;\n" +"use Yiisoft\\Http\\Status;\n" +"use Yiisoft\\Router\\UrlGeneratorInterface;\n" +"\n" +"final readonly class SavePostAction\n" +"{\n" +" public function __construct(\n" +" private ResponseFactoryInterface $responseFactory,\n" +" private UrlGeneratorInterface $urlGenerator,\n" +" ) {\n" +" }\n" +"\n" +" public function __invoke(ServerRequestInterface $request): ResponseInterface\n" +" {\n" +" $id = (int) ($request->getQueryParams()['id'] ?? 0);\n" +" $url = $this->urlGenerator->generate('post/view', ['id' => $id]);\n" +"\n" +" return $this->responseFactory\n" +" ->createResponse(Status::SEE_OTHER)\n" +" ->withHeader('Location', $url);\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Design request handling early because it affects forms, filters, REST endpoints, redirects, and tests." +msgstr "Pense no tratamento de requisições logo no início, porque ele afeta formulários, filtros, endpoints REST, redirecionamentos e testes." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Views, layouts, assets, and URLs" +msgstr "Views, layouts, assets e URLs" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "In Yii 2.0, controller rendering finds files under `views/{controller}` and layouts under `views/layouts`:" +msgstr "No Yii 2.0, a renderização do controller procura arquivos em `views/{controller}` e layouts em `views/layouts`:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"return $this->render('view', [\n" +" 'model' => $model,\n" +"]);\n" +msgstr "" +"return $this->render('view', [\n" +" 'model' => $model,\n" +"]);\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "In Yii3, the template path is explicit in the action:" +msgstr "No Yii3, o caminho do template é explícito na action:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"return $this->viewRenderer->render(__DIR__ . '/view', [\n" +" 'post' => $post,\n" +"]);\n" +msgstr "" +"return $this->viewRenderer->render(__DIR__ . '/view', [\n" +" 'post' => $post,\n" +"]);\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "A Yii3 template receives a `Yiisoft\\View\\WebView` instance as `$this`:" +msgstr "Um template do Yii3 recebe uma instância de `Yiisoft\\View\\WebView` como `$this`:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"use App\\Shared\\ApplicationParams;\n" +"use Yiisoft\\Html\\Html;\n" +"use Yiisoft\\View\\WebView;\n" +"\n" +"/**\n" +" * @var WebView $this\n" +" * @var ApplicationParams $applicationParams\n" +" * @var string $title\n" +" */\n" +"\n" +"$this->setTitle($title . ' - ' . $applicationParams->name);\n" +"?>\n" +"\n" +"

\n" +msgstr "" +"use App\\Shared\\ApplicationParams;\n" +"use Yiisoft\\Html\\Html;\n" +"use Yiisoft\\View\\WebView;\n" +"\n" +"/**\n" +" * @var WebView $this\n" +" * @var ApplicationParams $applicationParams\n" +" * @var string $title\n" +" */\n" +"\n" +"$this->setTitle($title . ' - ' . $applicationParams->name);\n" +"?>\n" +"\n" +"

\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Asset bundles move from `yii\\web\\AssetBundle` to `Yiisoft\\Assets\\AssetBundle`:" +msgstr "Os asset bundles passam de `yii\\web\\AssetBundle` para `Yiisoft\\Assets\\AssetBundle`:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"namespace App\\Web\\Shared\\Layout\\Main;\n" +"\n" +"use Yiisoft\\Assets\\AssetBundle;\n" +"\n" +"final class MainAsset extends AssetBundle\n" +"{\n" +" public ?string $basePath = '@assets/main';\n" +" public ?string $baseUrl = '@assetsUrl/main';\n" +" public ?string $sourcePath = '@assetsSource/main';\n" +"\n" +" public array $css = [\n" +" 'site.css',\n" +" ];\n" +"}\n" +msgstr "" +"namespace App\\Web\\Shared\\Layout\\Main;\n" +"\n" +"use Yiisoft\\Assets\\AssetBundle;\n" +"\n" +"final class MainAsset extends AssetBundle\n" +"{\n" +" public ?string $basePath = '@assets/main';\n" +" public ?string $baseUrl = '@assetsUrl/main';\n" +" public ?string $sourcePath = '@assetsSource/main';\n" +"\n" +" public array $css = [\n" +" 'site.css',\n" +" ];\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Register assets in a layout or view via the asset manager:" +msgstr "Registre os assets em um layout ou view pelo gerenciador de assets:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"$assetManager->register(MainAsset::class);\n" +"\n" +"$this->addCssFiles($assetManager->getCssFiles());\n" +"$this->addJsFiles($assetManager->getJsFiles());\n" +msgstr "" +"$assetManager->register(MainAsset::class);\n" +"\n" +"$this->addCssFiles($assetManager->getCssFiles());\n" +"$this->addJsFiles($assetManager->getJsFiles());\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"Replace `yii\\helpers\\Url` and `Yii::$app->urlManager` usage with named routes and\n" +"`Yiisoft\\Router\\UrlGeneratorInterface`:\n" +msgstr "" +"Substitua o uso de `yii\\helpers\\Url` e `Yii::$app->urlManager` por rotas nomeadas e\n" +"`Yiisoft\\Router\\UrlGeneratorInterface`:\n" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "$url = $urlGenerator->generate('post/view', ['id' => $post->getId()]);\n" +msgstr "$url = $urlGenerator->generate('post/view', ['id' => $post->getId()]);\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "See [View](../views/view.md), [Assets](../views/asset.md), [Scripts, styles and metatags](../views/script-style-meta.md), and [Template engines](../views/template-engines.md)." +msgstr "Veja [View](../views/view.md), [Assets](../views/asset.md), [Scripts, estilos e metatags](../views/script-style-meta.md) e [Template engines](../views/template-engines.md)." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Forms and validation" +msgstr "Formulários e validação" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Yii 2.0 frequently combines form data, labels, validation, and sometimes persistence in a `yii\\base\\Model` or `yii\\db\\ActiveRecord` class:" +msgstr "O Yii 2.0 frequentemente junta dados do formulário, rótulos, validação e às vezes persistência em uma classe `yii\\base\\Model` ou `yii\\db\\ActiveRecord`:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"final class ContactForm extends \\yii\\base\\Model\n" +"{\n" +" public $name;\n" +" public $email;\n" +"\n" +" public function rules(): array\n" +" {\n" +" return [\n" +" [['name', 'email'], 'required'],\n" +" ['email', 'email'],\n" +" ];\n" +" }\n" +"}\n" +msgstr "" +"final class ContactForm extends \\yii\\base\\Model\n" +"{\n" +" public $name;\n" +" public $email;\n" +"\n" +" public function rules(): array\n" +" {\n" +" return [\n" +" [['name', 'email'], 'required'],\n" +" ['email', 'email'],\n" +" ];\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Yii3 separates these concerns. Use `yiisoft/form-model` for form data and metadata, and `yiisoft/validator` for rules:" +msgstr "O Yii3 separa essas responsabilidades. Use `yiisoft/form-model` para os dados e metadados do formulário, e `yiisoft/validator` para as regras:" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "For form rendering, replace `yii\\widgets\\ActiveForm` with `yiisoft/form` fields and form model integration. For input hydration, prefer the form-model and hydrator packages instead of mass-assigning arbitrary request data to persistence objects." +msgstr "Para a renderização de formulários, substitua `yii\\widgets\\ActiveForm` pelos campos do `yiisoft/form` e pela integração com form models. Para a hidratação da entrada, prefira os pacotes de form model e hydrator em vez de atribuir em massa dados arbitrários da requisição a objetos de persistência." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Active Record and persistence" +msgstr "Active Record e persistência" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "There are two common Yii3 choices for code that used Yii 2.0 Active Record classes." +msgstr "Existem duas escolhas comuns no Yii3 para código que usava classes Active Record do Yii 2.0." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "The first path is architectural: move business logic to services and domain objects, then use repositories for persistence. This is recommended when the Yii 2.0 model contains validation, form scenarios, authorization checks, mailing, file uploads, and database access in the same class." +msgstr "O primeiro caminho é arquitetural: mova a lógica de negócio para serviços e objetos de domínio e use repositórios para a persistência. Ele é recomendado quando o model do Yii 2.0 contém validação, cenários de formulário, verificações de autorização, envio de e-mails, upload de arquivos e acesso ao banco de dados na mesma classe." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "The second path is incremental: represent the database model with [yiisoft/active-record](https://github.com/yiisoft/active-record). This is closer to Yii 2.0 and can be significantly faster when your Active Record classes mostly describe tables and relations." +msgstr "O segundo caminho é incremental: represente o modelo do banco de dados com o [yiisoft/active-record](https://github.com/yiisoft/active-record). Ele é mais próximo do Yii 2.0 e pode ser bem mais rápido quando suas classes Active Record descrevem principalmente tabelas e relações." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Yii 2.0:" +msgstr "Yii 2.0:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"final class Post extends \\yii\\db\\ActiveRecord\n" +"{\n" +" public static function tableName(): string\n" +" {\n" +" return '{{%post}}';\n" +" }\n" +"\n" +" public function rules(): array\n" +" {\n" +" return [\n" +" [['title', 'body'], 'required'],\n" +" ['title', 'string', 'max' => 255],\n" +" ];\n" +" }\n" +"}\n" +msgstr "" +"final class Post extends \\yii\\db\\ActiveRecord\n" +"{\n" +" public static function tableName(): string\n" +" {\n" +" return '{{%post}}';\n" +" }\n" +"\n" +" public function rules(): array\n" +" {\n" +" return [\n" +" [['title', 'body'], 'required'],\n" +" ['title', 'string', 'max' => 255],\n" +" ];\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Yii3 Active Record:" +msgstr "Active Record no Yii3:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"use Yiisoft\\ActiveRecord\\ActiveRecord;\n" +"\n" +"final class Post extends ActiveRecord\n" +"{\n" +" protected int $id;\n" +" protected string $title;\n" +" protected string $body;\n" +"\n" +" public function tableName(): string\n" +" {\n" +" return '{{%post}}';\n" +" }\n" +"\n" +" public function getId(): ?int\n" +" {\n" +" return $this->id ?? null;\n" +" }\n" +"\n" +" public function getTitle(): ?string\n" +" {\n" +" return $this->title ?? null;\n" +" }\n" +"\n" +" public function setTitle(string $title): void\n" +" {\n" +" $this->title = $title;\n" +" }\n" +"}\n" +msgstr "" +"use Yiisoft\\ActiveRecord\\ActiveRecord;\n" +"\n" +"final class Post extends ActiveRecord\n" +"{\n" +" protected int $id;\n" +" protected string $title;\n" +" protected string $body;\n" +"\n" +" public function tableName(): string\n" +" {\n" +" return '{{%post}}';\n" +" }\n" +"\n" +" public function getId(): ?int\n" +" {\n" +" return $this->id ?? null;\n" +" }\n" +"\n" +" public function getTitle(): ?string\n" +" {\n" +" return $this->title ?? null;\n" +" }\n" +"\n" +" public function setTitle(string $title): void\n" +" {\n" +" $this->title = $title;\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Do not move Yii 2.0 `rules()` directly into the Active Record class. In Yii3, validation belongs to validator rules, form models, command objects, or services:" +msgstr "Não mova o `rules()` do Yii 2.0 diretamente para a classe Active Record. No Yii3, a validação pertence a regras do validator, form models, objetos de comando ou serviços:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"use Yiisoft\\FormModel\\FormModel;\n" +"use Yiisoft\\Validator\\Rule\\Length;\n" +"use Yiisoft\\Validator\\Rule\\Required;\n" +"\n" +"final class PostInput extends FormModel\n" +"{\n" +" #[Required]\n" +" #[Length(max: 255)]\n" +" public ?string $title = null;\n" +"\n" +" #[Required]\n" +" public ?string $body = null;\n" +"}\n" +msgstr "" +"use Yiisoft\\FormModel\\FormModel;\n" +"use Yiisoft\\Validator\\Rule\\Length;\n" +"use Yiisoft\\Validator\\Rule\\Required;\n" +"\n" +"final class PostInput extends FormModel\n" +"{\n" +" #[Required]\n" +" #[Length(max: 255)]\n" +" public ?string $title = null;\n" +"\n" +" #[Required]\n" +" public ?string $body = null;\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Then copy validated data into the record or pass it to an application service:" +msgstr "Depois, copie os dados validados para o registro ou passe-os para um serviço da aplicação:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"$post = new Post();\n" +"$post->setTitle($input->title);\n" +"$post->save();\n" +msgstr "" +"$post = new Post();\n" +"$post->setTitle($input->title);\n" +"$post->save();\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "When deciding what to reuse, check each Active Record method:" +msgstr "Ao decidir o que reutilizar, verifique cada método do Active Record:" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "table mapping and relations can usually move to `yiisoft/active-record`;" +msgstr "o mapeamento de tabelas e as relações geralmente podem ir para o `yiisoft/active-record`;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "validation should move to `yiisoft/validator`;" +msgstr "a validação deve ir para o `yiisoft/validator`;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "form labels and hints should move to `yiisoft/form-model`;" +msgstr "rótulos e dicas de formulário devem ir para o `yiisoft/form-model`;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "search models should become query/data-reader services;" +msgstr "os search models devem virar serviços de consulta/data reader;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "business workflows should become services;" +msgstr "os fluxos de negócio devem virar serviços;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "events should use PSR-14 events or package-specific events;" +msgstr "os eventos devem usar eventos PSR-14 ou eventos específicos de pacotes;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "direct `Yii::$app->db` usage should become injected database dependencies." +msgstr "o uso direto de `Yii::$app->db` deve virar dependências de banco de dados injetadas." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Yii 2.0 migrations and Yii3 `yiisoft/db-migration` migrations are not compatible. Start a new migration history or create structure dumps for the current schema, then use Yii3 migrations for future schema changes." +msgstr "As migrations do Yii 2.0 e as migrations do `yiisoft/db-migration` do Yii3 não são compatíveis. Comece um novo histórico de migrations ou crie dumps da estrutura do esquema atual, e use migrations do Yii3 para as mudanças futuras no esquema." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Yii 2.0 `GridView` is commonly used with `ActiveDataProvider`:" +msgstr "O `GridView` do Yii 2.0 costuma ser usado com `ActiveDataProvider`:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"use yii\\grid\\GridView;\n" +"\n" +"echo GridView::widget([\n" +" 'dataProvider' => $dataProvider,\n" +" 'filterModel' => $searchModel,\n" +" 'columns' => [\n" +" 'id',\n" +" 'title',\n" +" 'created_at:datetime',\n" +" ['class' => 'yii\\grid\\ActionColumn'],\n" +" ],\n" +"]);\n" +msgstr "" +"use yii\\grid\\GridView;\n" +"\n" +"echo GridView::widget([\n" +" 'dataProvider' => $dataProvider,\n" +" 'filterModel' => $searchModel,\n" +" 'columns' => [\n" +" 'id',\n" +" 'title',\n" +" 'created_at:datetime',\n" +" ['class' => 'yii\\grid\\ActionColumn'],\n" +" ],\n" +"]);\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Yii3 uses [yiisoft/yii-dataview](https://github.com/yiisoft/yii-dataview). It renders data from a data reader and uses fluent widget configuration:" +msgstr "O Yii3 usa o [yiisoft/yii-dataview](https://github.com/yiisoft/yii-dataview). Ele renderiza dados a partir de um data reader e usa configuração fluente do widget:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"use Yiisoft\\Data\\Reader\\ReadableDataInterface;\n" +"use Yiisoft\\Yii\\DataView\\Column\\DataColumn;\n" +"use Yiisoft\\Yii\\DataView\\GridView\\Column\\ActionColumn;\n" +"use Yiisoft\\Yii\\DataView\\GridView\\GridView;\n" +"\n" +"/**\n" +" * @var ReadableDataInterface $dataReader\n" +" */\n" +"\n" +"echo GridView::widget()\n" +" ->dataReader($dataReader)\n" +" ->columns(\n" +" new DataColumn('id'),\n" +" new DataColumn('title', header: 'Title'),\n" +" new DataColumn('created_at', header: 'Created'),\n" +" new ActionColumn(),\n" +" );\n" +msgstr "" +"use Yiisoft\\Data\\Reader\\ReadableDataInterface;\n" +"use Yiisoft\\Yii\\DataView\\Column\\DataColumn;\n" +"use Yiisoft\\Yii\\DataView\\GridView\\Column\\ActionColumn;\n" +"use Yiisoft\\Yii\\DataView\\GridView\\GridView;\n" +"\n" +"/**\n" +" * @var ReadableDataInterface $dataReader\n" +" */\n" +"\n" +"echo GridView::widget()\n" +" ->dataReader($dataReader)\n" +" ->columns(\n" +" new DataColumn('id'),\n" +" new DataColumn('title', header: 'Title'),\n" +" new DataColumn('created_at', header: 'Created'),\n" +" new ActionColumn(),\n" +" );\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "For sorting, pagination, filtering, and action URLs, wire the widget to Yii Router:" +msgstr "Para ordenação, paginação, filtragem e URLs de actions, conecte o widget ao Yii Router:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"use Yiisoft\\Yii\\DataView\\YiiRouter\\ActionColumnUrlConfig;\n" +"use Yiisoft\\Yii\\DataView\\YiiRouter\\ActionColumnUrlCreator;\n" +"use Yiisoft\\Yii\\DataView\\YiiRouter\\UrlCreator;\n" +"use Yiisoft\\Yii\\DataView\\YiiRouter\\UrlParameterProvider;\n" +"\n" +"echo GridView::widget()\n" +" ->dataReader($dataReader)\n" +" ->urlParameterProvider(new UrlParameterProvider($currentRoute))\n" +" ->urlCreator(new UrlCreator($urlGenerator))\n" +" ->columns(\n" +" new DataColumn('id'),\n" +" new DataColumn('title'),\n" +" new ActionColumn(\n" +" urlCreator: new ActionColumnUrlCreator($urlGenerator, $currentRoute),\n" +" urlConfig: new ActionColumnUrlConfig(baseRouteName: 'post'),\n" +" ),\n" +" );\n" +msgstr "" +"use Yiisoft\\Yii\\DataView\\YiiRouter\\ActionColumnUrlConfig;\n" +"use Yiisoft\\Yii\\DataView\\YiiRouter\\ActionColumnUrlCreator;\n" +"use Yiisoft\\Yii\\DataView\\YiiRouter\\UrlCreator;\n" +"use Yiisoft\\Yii\\DataView\\YiiRouter\\UrlParameterProvider;\n" +"\n" +"echo GridView::widget()\n" +" ->dataReader($dataReader)\n" +" ->urlParameterProvider(new UrlParameterProvider($currentRoute))\n" +" ->urlCreator(new UrlCreator($urlGenerator))\n" +" ->columns(\n" +" new DataColumn('id'),\n" +" new DataColumn('title'),\n" +" new ActionColumn(\n" +" urlCreator: new ActionColumnUrlCreator($urlGenerator, $currentRoute),\n" +" urlConfig: new ActionColumnUrlConfig(baseRouteName: 'post'),\n" +" ),\n" +" );\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "A Yii 2.0 search model usually becomes a query service that:" +msgstr "Um search model do Yii 2.0 geralmente vira um serviço de consulta que:" + +#. type: Bullet: '1. ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "reads filter and sort parameters from the request;" +msgstr "lê os parâmetros de filtro e ordenação da requisição;" + +#. type: Bullet: '2. ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "validates them with `yiisoft/validator`;" +msgstr "valida esses parâmetros com `yiisoft/validator`;" + +#. type: Bullet: '3. ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "builds a database query or repository query;" +msgstr "monta uma consulta ao banco de dados ou ao repositório;" + +#. type: Bullet: '4. ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "exposes a data reader to GridView." +msgstr "expõe um data reader para o GridView." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "See [Using htmx for partial reloads](../../cookbook/using-htmx-for-partial-reloads.md) for a complete Yii3 GridView workflow and [yii-dataview GridView docs](https://github.com/yiisoft/yii-dataview/blob/master/docs/en/guide/gridview.md)." +msgstr "Veja [Usando htmx para recarregamentos parciais](../../cookbook/using-htmx-for-partial-reloads.md) para um fluxo completo de GridView no Yii3 e a [documentação do GridView do yii-dataview](https://github.com/yiisoft/yii-dataview/blob/master/docs/en/guide/gridview.md)." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Filters, middleware, and access control" +msgstr "Filtros, middleware e controle de acesso" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Yii 2.0 controller filters and behaviors usually look like this:" +msgstr "Os filtros e behaviors de controller do Yii 2.0 geralmente são assim:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"public function behaviors(): array\n" +"{\n" +" return [\n" +" 'access' => [\n" +" 'class' => \\yii\\filters\\AccessControl::class,\n" +" 'rules' => [\n" +" ['allow' => true, 'roles' => ['@']],\n" +" ],\n" +" ],\n" +" ];\n" +"}\n" +msgstr "" +"public function behaviors(): array\n" +"{\n" +" return [\n" +" 'access' => [\n" +" 'class' => \\yii\\filters\\AccessControl::class,\n" +" 'rules' => [\n" +" ['allow' => true, 'roles' => ['@']],\n" +" ],\n" +" ],\n" +" ];\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "In Yii3, request processing is middleware-based. Move cross-cutting concerns such as authentication, authorization, body parsing, locale negotiation, CSRF checks, and error handling to middleware or dedicated services. Keep actions focused on the request flow they implement." +msgstr "No Yii3, o processamento das requisições é baseado em middleware. Mova responsabilidades transversais, como autenticação, autorização, parsing do corpo, negociação de idioma, verificação de CSRF e tratamento de erros, para middlewares ou serviços dedicados. Mantenha as actions focadas no fluxo de requisição que elas implementam." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v2.md ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "Console commands" +msgstr "Comandos de console" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Yii 2.0 console commands extend `yii\\console\\Controller`:" +msgstr "Os comandos de console do Yii 2.0 estendem `yii\\console\\Controller`:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"final class ReportController extends \\yii\\console\\Controller\n" +"{\n" +" public function actionSend(): int\n" +" {\n" +" // ...\n" +" return self::EXIT_CODE_NORMAL;\n" +" }\n" +"}\n" +msgstr "" +"final class ReportController extends \\yii\\console\\Controller\n" +"{\n" +" public function actionSend(): int\n" +" {\n" +" // ...\n" +" return self::EXIT_CODE_NORMAL;\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Yii3 console commands are services in `src/Console`:" +msgstr "Os comandos de console do Yii3 são serviços em `src/Console`:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"namespace App\\Console;\n" +"\n" +"use Symfony\\Component\\Console\\Attribute\\AsCommand;\n" +"use Symfony\\Component\\Console\\Command\\Command;\n" +"use Symfony\\Component\\Console\\Input\\InputInterface;\n" +"use Symfony\\Component\\Console\\Output\\OutputInterface;\n" +"\n" +"#[AsCommand(name: 'report/send')]\n" +"final class SendReportCommand extends Command\n" +"{\n" +" protected function execute(InputInterface $input, OutputInterface $output): int\n" +" {\n" +" // ...\n" +" return Command::SUCCESS;\n" +" }\n" +"}\n" +msgstr "" +"namespace App\\Console;\n" +"\n" +"use Symfony\\Component\\Console\\Attribute\\AsCommand;\n" +"use Symfony\\Component\\Console\\Command\\Command;\n" +"use Symfony\\Component\\Console\\Input\\InputInterface;\n" +"use Symfony\\Component\\Console\\Output\\OutputInterface;\n" +"\n" +"#[AsCommand(name: 'report/send')]\n" +"final class SendReportCommand extends Command\n" +"{\n" +" protected function execute(InputInterface $input, OutputInterface $output): int\n" +" {\n" +" // ...\n" +" return Command::SUCCESS;\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Move command dependencies to constructor injection and register commands in console configuration." +msgstr "Passe as dependências dos comandos para injeção pelo construtor e registre os comandos na configuração de console." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Yii 2.0 REST controllers, serializers, and response formatters do not move directly to Yii3. Start from PSR-7 responses and explicit routing. Build one resource at a time:" +msgstr "Os controllers REST, serializers e formatadores de resposta do Yii 2.0 não passam diretamente para o Yii3. Comece pelas respostas PSR-7 e pelo roteamento explícito. Construa um recurso por vez:" + +#. type: Bullet: '1. ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "define routes for collection and item operations;" +msgstr "defina rotas para as operações de coleção e de item;" + +#. type: Bullet: '2. ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "inject request, persistence, serializer, and response factory dependencies;" +msgstr "injete as dependências de requisição, persistência, serializer e response factory;" + +#. type: Bullet: '3. ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "validate input with `yiisoft/validator`;" +msgstr "valide a entrada com `yiisoft/validator`;" + +#. type: Bullet: '4. ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "return JSON responses through Yii3 response helpers or PSR-7 factories;" +msgstr "retorne respostas JSON pelos helpers de resposta do Yii3 ou por factories PSR-7;" + +#. type: Bullet: '5. ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "move authentication and rate limiting to middleware." +msgstr "mova a autenticação e o rate limiting para middlewares." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "See [Response](../runtime/response.md), [Authentication](../security/authentication.md), and [Authorization](../security/authorization.md)." +msgstr "Veja [Resposta](../runtime/response.md), [Autenticação](../security/authentication.md) e [Autorização](../security/authorization.md)." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Do not postpone tests until the whole Yii3 application is done. For each new request flow, add:" +msgstr "Não deixe os testes para quando a aplicação Yii3 inteira estiver pronta. Para cada novo fluxo de requisição, adicione:" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "unit tests for services and validators;" +msgstr "testes unitários para serviços e validadores;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "functional tests for actions and middleware;" +msgstr "testes funcionais para actions e middlewares;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "end-to-end tests for critical browser flows;" +msgstr "testes end-to-end para os fluxos críticos no navegador;" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "static analysis for stricter type checks." +msgstr "análise estática para verificações de tipo mais rigorosas." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Yii3 code is more explicit, so tests should assert services directly instead of constructing large application component arrays." +msgstr "O código Yii3 é mais explícito, então os testes devem verificar os serviços diretamente, em vez de montar grandes arrays de componentes da aplicação." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "See [Testing overview](../testing/overview.md), [Unit tests](../testing/unit.md), [Functional tests](../testing/functional.md), and [End-to-end tests](../testing/end-to-end.md)." +msgstr "Veja [Visão geral dos testes](../testing/overview.md), [Testes unitários](../testing/unit.md), [Testes funcionais](../testing/functional.md) e [Testes end-to-end](../testing/end-to-end.md)." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Refactoring Yii 2.0 code before reusing it" +msgstr "Refatorando o código Yii 2.0 antes de reutilizá-lo" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "These changes are useful even if the old application stays on Yii 2.0 for a while:" +msgstr "Estas mudanças são úteis mesmo que a aplicação antiga continue no Yii 2.0 por um tempo:" + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Replace `Yii::$app` access in domain code with constructor arguments." +msgstr "Substitua o acesso a `Yii::$app` no código de domínio por argumentos do construtor." + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Move queries out of controllers and views into repositories or query services." +msgstr "Tire as consultas dos controllers e views e leve-as para repositórios ou serviços de consulta." + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Move business workflows out of Active Record classes." +msgstr "Tire os fluxos de negócio das classes Active Record." + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Separate form models from persistence models." +msgstr "Separe os form models dos models de persistência." + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Add return types and parameter types." +msgstr "Adicione tipos de retorno e tipos de parâmetros." + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Replace route arrays scattered in views with named route constants or helper methods." +msgstr "Substitua arrays de rotas espalhados pelas views por constantes de rotas nomeadas ou métodos helper." + +#. type: Bullet: '- ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Add tests around each flow before rebuilding it in Yii3." +msgstr "Adicione testes em torno de cada fluxo antes de reconstruí-lo no Yii3." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "The less framework state your Yii 2.0 code assumes, the easier it is to understand what should be reused and what should be redesigned for Yii3." +msgstr "Quanto menos estado do framework o seu código Yii 2.0 pressupor, mais fácil fica entender o que deve ser reutilizado e o que deve ser redesenhado para o Yii3." diff --git a/_translations/po/pt-BR/guide_intro_what-is-yii.md.po b/_translations/po/pt-BR/guide_intro_what-is-yii.md.po new file mode 100644 index 00000000..c299478e --- /dev/null +++ b/_translations/po/pt-BR/guide_intro_what-is-yii.md.po @@ -0,0 +1,153 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-01-08 08:54+0000\n" +"PO-Revision-Date: 2026-01-08 08:54+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Plain text +#: ../src/cookbook/preface.md ../src/guide/intro/what-is-yii.md +msgid "Yii is a high-performance, package-based PHP framework for developing modern applications. The name Yii (pronounced `Yee` or `[ji:]`) means \"simple and evolutionary\" in Chinese. You can also think about it as an acronym for **Yes It Is**!" +msgstr "O Yii é um framework PHP de alto desempenho, baseado em pacotes, para desenvolver aplicações modernas. O nome Yii (pronuncia-se `Yee` ou `[ji:]`) significa \"simples e evolutivo\" em chinês. Você também pode pensar nele como um acrônimo de **Yes It Is**!" + +#. type: Plain text +#: ../src/cookbook/preface.md ../src/guide/intro/what-is-yii.md +msgid "Yii is a generic Web programming framework. You can use it for developing all kinds of Web applications using PHP. Because of its architecture and sophisticated caching support, it's especially suitable for developing large-scale applications such as portals, content management systems, e-commerce, REST APIs, etc." +msgstr "O Yii é um framework genérico de programação web. Você pode usá-lo para desenvolver todo tipo de aplicação web com PHP. Por causa da sua arquitetura e do suporte sofisticado a cache, ele é especialmente indicado para aplicações de grande porte, como portais, sistemas de gerenciamento de conteúdo, e-commerce, APIs REST etc." + +#. type: Title # +#: ../src/guide/intro/what-is-yii.md +#, no-wrap +msgid "What is Yii" +msgstr "O que é o Yii" + +#. type: Title ## +#: ../src/guide/intro/what-is-yii.md +#, no-wrap +msgid "What's Yii best for" +msgstr "Para que o Yii é mais indicado" + +#. type: Title ## +#: ../src/guide/intro/what-is-yii.md +#, no-wrap +msgid "How does Yii compare with other frameworks?" +msgstr "Como o Yii se compara a outros frameworks?" + +#. type: Plain text +#: ../src/guide/intro/what-is-yii.md +msgid "If you're already familiar with another framework, you may appreciate knowing how Yii compares:" +msgstr "Se você já conhece outro framework, talvez queira saber como o Yii se compara a ele:" + +#. type: Bullet: '- ' +#: ../src/guide/intro/what-is-yii.md +msgid "Yii takes the [philosophy of being practical and helpful](../../internals/001-yii-values.md) achieving:" +msgstr "O Yii segue a [filosofia de ser prático e útil](../../internals/001-yii-values.md), buscando:" + +#. type: Bullet: ' - ' +#: ../src/guide/intro/what-is-yii.md +msgid "Performance in both development and execution." +msgstr "Desempenho tanto no desenvolvimento quanto na execução." + +#. type: Bullet: ' - ' +#: ../src/guide/intro/what-is-yii.md +msgid "Convenient customizable defaults." +msgstr "Padrões convenientes e personalizáveis." + +#. type: Bullet: ' - ' +#: ../src/guide/intro/what-is-yii.md +msgid "Practice-orientation." +msgstr "Foco na prática." + +#. type: Bullet: ' - ' +#: ../src/guide/intro/what-is-yii.md +msgid "Simplicity." +msgstr "Simplicidade." + +#. type: Bullet: ' - ' +#: ../src/guide/intro/what-is-yii.md +msgid "Explicitness." +msgstr "Clareza." + +#. type: Bullet: ' - ' +#: ../src/guide/intro/what-is-yii.md +msgid "Consistency." +msgstr "Consistência." + +#. type: Plain text +#: ../src/guide/intro/what-is-yii.md +#, no-wrap +msgid "" +" Yii will never try to over-design things mainly to follow some design patterns.\n" +"- Yii extensively uses PSR interfaces with the ability to reuse what PHP community created and even\n" +" replace core implementations if needed.\n" +"- Yii is both a set of libraries and a full-stack framework providing many proven and ready-to-use features:\n" +" caching, logging, template engine, data abstraction, development tools, code generation, and more.\n" +"- Yii is extensible. You can customize or replace every piece of the core's code. You can also\n" +" take advantage of Yii's solid architecture to use or develop redistributable packages.\n" +"- High performance is always a primary goal of Yii.\n" +msgstr "" +" O Yii nunca tenta complicar o design só para seguir algum padrão de projeto.\n" +"- O Yii usa amplamente as interfaces PSR, o que permite reaproveitar o que a comunidade PHP criou e até\n" +" substituir implementações do core quando necessário.\n" +"- O Yii é ao mesmo tempo um conjunto de bibliotecas e um framework full-stack com muitos recursos testados e prontos para uso:\n" +" cache, logs, template engine, abstração de dados, ferramentas de desenvolvimento, geração de código e mais.\n" +"- O Yii é extensível. Você pode personalizar ou substituir qualquer parte do código do core. Também pode\n" +" aproveitar a arquitetura sólida do Yii para usar ou desenvolver pacotes redistribuíveis.\n" +"- Alto desempenho é sempre um objetivo principal do Yii.\n" + +#. type: Plain text +#: ../src/guide/intro/what-is-yii.md +msgid "Yii is backed up by a [strong core developer team](https://www.yiiframework.com/team/) financially backed from an [OpenCollective foundation](https://opencollective.com/yiisoft), as well as a large community of professionals constantly contributing to Yii's development. The Yii developer team keeps a close eye on the latest Web development trends and on the best practices and features found in other frameworks and projects. The most relevant best practices and features found elsewhere are incorporated into the core framework and exposed via simple and elegant interfaces." +msgstr "O Yii conta com um [time principal de desenvolvedores sólido](https://www.yiiframework.com/team/), apoiado financeiramente pela [fundação no OpenCollective](https://opencollective.com/yiisoft), e com uma grande comunidade de profissionais que contribuem constantemente para o desenvolvimento do Yii. O time do Yii acompanha de perto as tendências mais recentes do desenvolvimento web e as boas práticas e recursos de outros frameworks e projetos. As boas práticas e os recursos mais relevantes encontrados em outros lugares são incorporados ao core do framework e expostos por meio de interfaces simples e elegantes." + +#. type: Title ## +#: ../src/guide/intro/what-is-yii.md +#, no-wrap +msgid "Yii versions" +msgstr "Versões do Yii" + +#. type: Plain text +#: ../src/guide/intro/what-is-yii.md +msgid "Yii currently has three major versions available: 1.1, 2.0, and 3.0." +msgstr "Atualmente o Yii tem três versões principais disponíveis: 1.1, 2.0 e 3.0." + +#. type: Bullet: '- ' +#: ../src/guide/intro/what-is-yii.md +msgid "Version 1.1 is the old generation and is now in the feature freeze bugfix mode." +msgstr "A versão 1.1 é a geração antiga e está congelada, recebendo apenas correções de bugs." + +#. type: Bullet: '- ' +#: ../src/guide/intro/what-is-yii.md +msgid "Version 2.0 is a current stable version in the feature freeze bugfix mode." +msgstr "A versão 2.0 é a versão estável atual e está congelada, recebendo apenas correções de bugs." + +#. type: Bullet: '- ' +#: ../src/guide/intro/what-is-yii.md +msgid "Version 3.0 is the current version in development. This guide is mainly about version 3." +msgstr "A versão 3.0 é a versão atual em desenvolvimento. Este guia trata principalmente da versão 3." + +#. type: Title ## +#: ../src/guide/intro/what-is-yii.md +#, no-wrap +msgid "Requirements and prerequisites" +msgstr "Requisitos e pré-requisitos" + +#. type: Plain text +#: ../src/guide/intro/what-is-yii.md +msgid "Yii3 requires PHP 8.2 or above, but some packages work with older PHP, such as PHP 7.4." +msgstr "O Yii3 exige PHP 8.2 ou superior, mas alguns pacotes funcionam com versões mais antigas, como o PHP 7.4." + +#. type: Plain text +#: ../src/guide/intro/what-is-yii.md +msgid "Using Yii requires basic knowledge of object-oriented programming (OOP), as Yii is a pure OOP-based framework. Yii3 also makes use of the latest PHP features, such as type declarations and generators. Understanding these concepts will help you pick up Yii3 faster." +msgstr "Usar o Yii exige conhecimento básico de programação orientada a objetos (POO), já que o Yii é um framework totalmente orientado a objetos. O Yii3 também usa recursos recentes do PHP, como declarações de tipo e generators. Entender esses conceitos vai ajudar você a aprender o Yii3 mais rápido." diff --git a/_translations/po/pt-BR/guide_rest_quick-start.md.po b/_translations/po/pt-BR/guide_rest_quick-start.md.po new file mode 100644 index 00000000..5f2339f4 --- /dev/null +++ b/_translations/po/pt-BR/guide_rest_quick-start.md.po @@ -0,0 +1,709 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-05-29 09:35+0000\n" +"PO-Revision-Date: 2026-05-29 09:35+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/rest/quick-start.md +#, no-wrap +msgid "Quick start" +msgstr "Início rápido" + +#. type: Plain text +#: ../src/guide/rest/quick-start.md +msgid "Yii works with JSON APIs through the same PSR-7 request and response objects used by web pages. For API endpoints, the usual flow is:" +msgstr "O Yii trabalha com APIs JSON usando os mesmos objetos de requisição e resposta PSR-7 das páginas web. Para endpoints de API, o fluxo comum é:" + +#. type: Bullet: '* ' +#: ../src/guide/rest/quick-start.md +msgid "Parse the request body when the client sends JSON." +msgstr "Ler o corpo da requisição quando o cliente envia JSON." + +#. type: Bullet: '* ' +#: ../src/guide/rest/quick-start.md +msgid "Map request data to a typed input object." +msgstr "Mapear os dados da requisição para um objeto de entrada tipado." + +#. type: Bullet: '* ' +#: ../src/guide/rest/quick-start.md +msgid "Validate the input object." +msgstr "Validar o objeto de entrada." + +#. type: Bullet: '* ' +#: ../src/guide/rest/quick-start.md +msgid "Return a response whose data is formatted as JSON." +msgstr "Retornar uma resposta cujos dados são formatados como JSON." + +#. type: Plain text +#: ../src/guide/rest/quick-start.md +msgid "This guide assumes that you use the [API application template](https://github.com/yiisoft/app-api). It already includes request body parsing, request input resolving, JSON data responses, and presenter examples. For complete applications with different structures, see [Demo applications](../start/demo-apps.md)." +msgstr "Este guia assume que você usa o [template de aplicação API](https://github.com/yiisoft/app-api). Ele já inclui a leitura do corpo da requisição, a resolução da entrada da requisição, respostas de dados em JSON e exemplos de presenters. Para aplicações completas com outras estruturas, veja [Aplicações demo](../start/demo-apps.md)." + +#. type: Title ## +#: ../src/guide/rest/quick-start.md +#, no-wrap +msgid "Creating request input" +msgstr "Criando a entrada da requisição" + +#. type: Plain text +#: ../src/guide/rest/quick-start.md +msgid "Use [yiisoft/input-http](https://github.com/yiisoft/input-http) to describe request data as a typed input object. Attach `#[FromBody]` when all values should come from the parsed request body." +msgstr "Use o [yiisoft/input-http](https://github.com/yiisoft/input-http) para descrever os dados da requisição como um objeto de entrada tipado. Adicione `#[FromBody]` quando todos os valores devem vir do corpo da requisição já interpretado." + +#. type: Plain text +#: ../src/guide/rest/quick-start.md +msgid "Create `src/Api/Post/CreatePostInput.php`:" +msgstr "Crie `src/Api/Post/CreatePostInput.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/rest/quick-start.md +#, no-wrap +msgid "" +"getValidationResult();\n" +"\n" +" if (!$result->isValid()) {\n" +" return $responseFactory->failValidation($result);\n" +" }\n" +"\n" +" return $responseFactory\n" +" ->success([\n" +" 'title' => $input->title,\n" +" 'content' => $input->content,\n" +" ])\n" +" ->withStatus(Status::CREATED);\n" +" }\n" +"}\n" +msgstr "" +"getValidationResult();\n" +"\n" +" if (!$result->isValid()) {\n" +" return $responseFactory->failValidation($result);\n" +" }\n" +"\n" +" return $responseFactory\n" +" ->success([\n" +" 'title' => $input->title,\n" +" 'content' => $input->content,\n" +" ])\n" +" ->withStatus(Status::CREATED);\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/rest/quick-start.md +msgid "You can validate the input in the action as shown above. Alternatively, configure `RequestInputParametersResolver` to throw `Yiisoft\\Input\\Http\\InputValidationException` and convert that exception to a JSON response in one error handler. The API application template uses this centralized approach." +msgstr "Você pode validar a entrada na action como mostrado acima. Outra opção é configurar o `RequestInputParametersResolver` para lançar `Yiisoft\\Input\\Http\\InputValidationException` e converter essa exceção em uma resposta JSON em um único tratador de erros. O template de aplicação API usa essa abordagem centralizada." + +#. type: Title ## +#: ../src/guide/rest/quick-start.md +#, no-wrap +msgid "Returning JSON responses" +msgstr "Retornando respostas JSON" + +#. type: Plain text +#: ../src/guide/rest/quick-start.md +msgid "For small endpoints, you can write JSON to a PSR-7 response manually as shown in [Responding with JSON](../runtime/response.md#responding-with-json). For APIs, prefer [yiisoft/data-response](https://github.com/yiisoft/data-response), which formats response data and sets the `Content-Type` header." +msgstr "Para endpoints pequenos, você pode escrever o JSON em uma resposta PSR-7 manualmente, como mostrado em [Respondendo com JSON](../runtime/response.md#respondendo-com-json). Para APIs, prefira o [yiisoft/data-response](https://github.com/yiisoft/data-response), que formata os dados da resposta e define o header `Content-Type`." + +#. type: Plain text +#: ../src/guide/rest/quick-start.md +msgid "The API application template keeps response formatting in `src/Api/Shared/ResponseFactory.php`:" +msgstr "O template de aplicação API mantém a formatação das respostas em `src/Api/Shared/ResponseFactory.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/rest/quick-start.md +#, no-wrap +msgid "" +"dataResponseFactory->createResponse([\n" +" 'status' => 'success',\n" +" 'data' => $presenter->present($data),\n" +" ]);\n" +" }\n" +"\n" +" public function failValidation(Result $result): ResponseInterface\n" +" {\n" +" return $this->dataResponseFactory\n" +" ->createResponse([\n" +" 'status' => 'failed',\n" +" 'error_message' => 'Validation failed.',\n" +" 'error_data' => (new ValidationResultPresenter())->present($result),\n" +" ])\n" +" ->withStatus(Status::UNPROCESSABLE_ENTITY);\n" +" }\n" +"}\n" +msgstr "" +"dataResponseFactory->createResponse([\n" +" 'status' => 'success',\n" +" 'data' => $presenter->present($data),\n" +" ]);\n" +" }\n" +"\n" +" public function failValidation(Result $result): ResponseInterface\n" +" {\n" +" return $this->dataResponseFactory\n" +" ->createResponse([\n" +" 'status' => 'failed',\n" +" 'error_message' => 'Validation failed.',\n" +" 'error_data' => (new ValidationResultPresenter())->present($result),\n" +" ])\n" +" ->withStatus(Status::UNPROCESSABLE_ENTITY);\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/rest/quick-start.md +msgid "Presenters are application-level abstractions that transform application objects to API output arrays. Keep them separate from domain entities so changing an API response doesn't force changes in business objects." +msgstr "Presenters são abstrações da camada de aplicação que transformam objetos da aplicação em arrays de saída da API. Mantenha-os separados das entidades de domínio, para que mudar uma resposta da API não force mudanças nos objetos de negócio." + +#. type: Plain text +#: ../src/guide/rest/quick-start.md +msgid "Create `src/Api/Post/PostPresenter.php`:" +msgstr "Crie `src/Api/Post/PostPresenter.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/rest/quick-start.md +#, no-wrap +msgid "" +"\n" +" */\n" +"final readonly class PostPresenter implements PresenterInterface\n" +"{\n" +" public function present(mixed $value): array\n" +" {\n" +" return [\n" +" 'id' => $value->id,\n" +" 'title' => $value->title,\n" +" 'content' => $value->content,\n" +" ];\n" +" }\n" +"}\n" +msgstr "" +"\n" +" */\n" +"final readonly class PostPresenter implements PresenterInterface\n" +"{\n" +" public function present(mixed $value): array\n" +" {\n" +" return [\n" +" 'id' => $value->id,\n" +" 'title' => $value->title,\n" +" 'content' => $value->content,\n" +" ];\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/rest/quick-start.md +msgid "The API template contains a fuller implementation of [response factory](https://github.com/yiisoft/app-api/blob/master/src/Api/Shared/ResponseFactory.php) and [presenters](https://github.com/yiisoft/app-api/tree/master/src/Api/Shared/Presenter)." +msgstr "O template de API contém uma implementação mais completa da [response factory](https://github.com/yiisoft/app-api/blob/master/src/Api/Shared/ResponseFactory.php) e dos [presenters](https://github.com/yiisoft/app-api/tree/master/src/Api/Shared/Presenter)." + +#. type: Title ## +#: ../src/guide/rest/quick-start.md +#, no-wrap +msgid "Routing an endpoint" +msgstr "Roteando um endpoint" + +#. type: Plain text +#: ../src/guide/rest/quick-start.md +msgid "Register API routes in `config/common/routes.php`:" +msgstr "Registre as rotas da API em `config/common/routes.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/rest/quick-start.md +#, no-wrap +msgid "" +"use App\\Api\\Post\\CreatePostAction;\n" +"use Yiisoft\\Http\\Method;\n" +"use Yiisoft\\Router\\Route;\n" +"\n" +"return [\n" +" Route::methods([Method::POST], '/posts')\n" +" ->action(CreatePostAction::class)\n" +" ->name('api/posts/create'),\n" +"];\n" +msgstr "" +"use App\\Api\\Post\\CreatePostAction;\n" +"use Yiisoft\\Http\\Method;\n" +"use Yiisoft\\Router\\Route;\n" +"\n" +"return [\n" +" Route::methods([Method::POST], '/posts')\n" +" ->action(CreatePostAction::class)\n" +" ->name('api/posts/create'),\n" +"];\n" + +#. type: Plain text +#: ../src/guide/rest/quick-start.md +msgid "Send JSON by setting `Content-Type: application/json`. Ask for JSON responses with `Accept: application/json`." +msgstr "Envie JSON definindo `Content-Type: application/json`. Peça respostas JSON com `Accept: application/json`." + +#. type: Fenced code block (shell) +#: ../src/guide/rest/quick-start.md +#, no-wrap +msgid "" +"curl -X POST http://localhost:8080/posts \\\n" +" -H 'Content-Type: application/json' \\\n" +" -H 'Accept: application/json' \\\n" +" -d '{\"title\":\"First post\",\"content\":\"Text\"}'\n" +msgstr "" +"curl -X POST http://localhost:8080/posts \\\n" +" -H 'Content-Type: application/json' \\\n" +" -H 'Accept: application/json' \\\n" +" -d '{\"title\":\"First post\",\"content\":\"Text\"}'\n" + +#. type: Plain text +#: ../src/guide/rest/quick-start.md +msgid "Validation errors are returned as JSON with HTTP status `422 Unprocessable Entity`. Successful creation usually returns `201 Created`." +msgstr "Erros de validação são retornados como JSON com status HTTP `422 Unprocessable Entity`. Uma criação bem-sucedida normalmente retorna `201 Created`." + +#. type: Title ## +#: ../src/guide/rest/quick-start.md +#, no-wrap +msgid "Existing applications" +msgstr "Aplicações existentes" + +#. type: Plain text +#: ../src/guide/rest/quick-start.md +msgid "If you add JSON API endpoints to an existing web application, install the API packages first:" +msgstr "Se você for adicionar endpoints de API JSON a uma aplicação web existente, primeiro instale os pacotes de API:" + +#. type: Fenced code block (shell) +#: ../src/guide/rest/quick-start.md +#, no-wrap +msgid "composer require yiisoft/input-http yiisoft/request-body-parser yiisoft/data-response\n" +msgstr "composer require yiisoft/input-http yiisoft/request-body-parser yiisoft/data-response\n" + +#. type: Plain text +#: ../src/guide/rest/quick-start.md +msgid "If you use Docker:" +msgstr "Se você usa Docker:" + +#. type: Fenced code block (shell) +#: ../src/guide/rest/quick-start.md +#, no-wrap +msgid "make composer require yiisoft/input-http yiisoft/request-body-parser yiisoft/data-response\n" +msgstr "make composer require yiisoft/input-http yiisoft/request-body-parser yiisoft/data-response\n" + +#. type: Plain text +#: ../src/guide/rest/quick-start.md +msgid "In `config/web/di/application.php`, add `RequestBodyParser` before `Router` so JSON requests are parsed before actions run:" +msgstr "Em `config/web/di/application.php`, adicione o `RequestBodyParser` antes do `Router`, para que as requisições JSON sejam lidas antes de as actions rodarem:" + +#. type: Fenced code block (php) +#: ../src/guide/rest/quick-start.md +#, no-wrap +msgid "" +"use Yiisoft\\Request\\Body\\RequestBodyParser;\n" +"use Yiisoft\\Router\\Middleware\\Router;\n" +"\n" +"return [\n" +" RequestBodyParser::class,\n" +" Router::class,\n" +"];\n" +msgstr "" +"use Yiisoft\\Request\\Body\\RequestBodyParser;\n" +"use Yiisoft\\Router\\Middleware\\Router;\n" +"\n" +"return [\n" +" RequestBodyParser::class,\n" +" Router::class,\n" +"];\n" + +#. type: Plain text +#: ../src/guide/rest/quick-start.md +msgid "In the same file, add JSON data response middleware before error handling and routing:" +msgstr "No mesmo arquivo, adicione o middleware de resposta de dados JSON antes do tratamento de erros e do roteamento:" + +#. type: Fenced code block (php) +#: ../src/guide/rest/quick-start.md +#, no-wrap +msgid "" +"use Yiisoft\\DataResponse\\Formatter\\JsonFormatter;\n" +"use Yiisoft\\DataResponse\\Middleware\\ContentNegotiatorDataResponseMiddleware;\n" +"\n" +"return [\n" +" static fn() => new ContentNegotiatorDataResponseMiddleware(\n" +" formatters: [\n" +" 'application/json' => new JsonFormatter(),\n" +" ],\n" +" fallback: new JsonFormatter(),\n" +" ),\n" +" // error handling, request body parser, router, and not-found middleware\n" +"];\n" +msgstr "" +"use Yiisoft\\DataResponse\\Formatter\\JsonFormatter;\n" +"use Yiisoft\\DataResponse\\Middleware\\ContentNegotiatorDataResponseMiddleware;\n" +"\n" +"return [\n" +" static fn() => new ContentNegotiatorDataResponseMiddleware(\n" +" formatters: [\n" +" 'application/json' => new JsonFormatter(),\n" +" ],\n" +" fallback: new JsonFormatter(),\n" +" ),\n" +" // tratamento de erros, leitor do corpo da requisição, router e middleware de não encontrado\n" +"];\n" + +#. type: Plain text +#: ../src/guide/rest/quick-start.md +msgid "Also in `config/web/di/application.php`, configure action parameter resolvers:" +msgstr "Também em `config/web/di/application.php`, configure os resolvedores de parâmetros das actions:" + +#. type: Fenced code block (php) +#: ../src/guide/rest/quick-start.md +#, no-wrap +msgid "" +"use Yiisoft\\Definitions\\Reference;\n" +"use Yiisoft\\Input\\Http\\HydratorAttributeParametersResolver;\n" +"use Yiisoft\\Input\\Http\\RequestInputParametersResolver;\n" +"use Yiisoft\\Middleware\\Dispatcher\\CompositeParametersResolver;\n" +"use Yiisoft\\Middleware\\Dispatcher\\ParametersResolverInterface;\n" +"\n" +"return [\n" +" ParametersResolverInterface::class => [\n" +" 'class' => CompositeParametersResolver::class,\n" +" '__construct()' => [\n" +" Reference::to(HydratorAttributeParametersResolver::class),\n" +" Reference::to(RequestInputParametersResolver::class),\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +"use Yiisoft\\Definitions\\Reference;\n" +"use Yiisoft\\Input\\Http\\HydratorAttributeParametersResolver;\n" +"use Yiisoft\\Input\\Http\\RequestInputParametersResolver;\n" +"use Yiisoft\\Middleware\\Dispatcher\\CompositeParametersResolver;\n" +"use Yiisoft\\Middleware\\Dispatcher\\ParametersResolverInterface;\n" +"\n" +"return [\n" +" ParametersResolverInterface::class => [\n" +" 'class' => CompositeParametersResolver::class,\n" +" '__construct()' => [\n" +" Reference::to(HydratorAttributeParametersResolver::class),\n" +" Reference::to(RequestInputParametersResolver::class),\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/rest/quick-start.md +msgid "Use the [API application template configuration](https://github.com/yiisoft/app-api/blob/master/config/web/di/application.php) as the complete reference for middleware order and resolver setup." +msgstr "Use a [configuração do template de aplicação API](https://github.com/yiisoft/app-api/blob/master/config/web/di/application.php) como referência completa para a ordem dos middlewares e a configuração dos resolvedores." diff --git a/_translations/po/pt-BR/guide_runtime_cookies.md.po b/_translations/po/pt-BR/guide_runtime_cookies.md.po new file mode 100644 index 00000000..04a0f3a6 --- /dev/null +++ b/_translations/po/pt-BR/guide_runtime_cookies.md.po @@ -0,0 +1,409 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-09-04 11:19+0500\n" +"PO-Revision-Date: 2025-09-04 11:19+0500\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: en/runtime/cookies.md +#, no-wrap +msgid "Cookies" +msgstr "Cookies" + +#. type: Plain text +#: en/runtime/cookies.md +msgid "Cookies are for persisting data between requests by sending it to the client browser using HTTP headers. The client sends data back to the server in request headers. Thus, cookies are handy to store small amounts of data, such as tokens or flags." +msgstr "Os cookies servem para manter dados entre requisições, enviando-os ao navegador do cliente por headers HTTP. O cliente devolve os dados ao servidor nos headers da requisição. Por isso, os cookies são práticos para guardar pequenas quantidades de dados, como tokens ou flags." + +#. type: Title ## +#: en/runtime/cookies.md +#, no-wrap +msgid "Reading cookies" +msgstr "Lendo cookies" + +#. type: Plain text +#: en/runtime/cookies.md +msgid "You could obtain Cookie values from server request that's available as route handler (such as controller action) argument:" +msgstr "Você pode obter os valores dos cookies a partir da requisição do servidor, que está disponível como argumento do handler da rota (por exemplo, uma action de controller):" + +#. type: Fenced code block (php) +#: en/runtime/cookies.md +#, no-wrap +msgid "" +"private function actionProfile(\\Psr\\Http\\Message\\ServerRequestInterface $request)\n" +"{\n" +" $cookieValues = $request->getCookieParams();\n" +" $cookieValue = $cookieValues['cookieName'] ?? null;\n" +" // ...\n" +"}\n" +msgstr "" +"private function actionProfile(\\Psr\\Http\\Message\\ServerRequestInterface $request)\n" +"{\n" +" $cookieValues = $request->getCookieParams();\n" +" $cookieValue = $cookieValues['cookieName'] ?? null;\n" +" // ...\n" +"}\n" + +#. type: Plain text +#: en/runtime/cookies.md +msgid "In addition to getting cookie values directly from the server request, you can also use the [yiisoft/request-provider](https://github.com/yiisoft/request-provider) package, which provides a more structured way to handle cookies through the `\\Yiisoft\\RequestProvider\\RequestCookieProvider`. This approach can simplify your code and improve readability." +msgstr "Além de obter os valores dos cookies direto da requisição do servidor, você também pode usar o pacote [yiisoft/request-provider](https://github.com/yiisoft/request-provider), que oferece uma forma mais estruturada de lidar com cookies por meio do `\\Yiisoft\\RequestProvider\\RequestCookieProvider`. Essa abordagem pode simplificar o código e melhorar a legibilidade." + +#. type: Plain text +#: en/runtime/cookies.md +msgid "Here’s an example of how to work with cookies using the `\\Yiisoft\\RequestProvider\\RequestCookieProvider`:" +msgstr "Veja um exemplo de como trabalhar com cookies usando o `\\Yiisoft\\RequestProvider\\RequestCookieProvider`:" + +#. type: Fenced code block (php) +#: en/runtime/cookies.md +#, no-wrap +msgid "" +"final readonly class MyService\n" +"{\n" +" public function __construct(\n" +" private \\Yiisoft\\RequestProvider\\RequestCookieProvider $cookies\n" +" ) {}\n" +"\n" +" public function go(): void\n" +" {\n" +" // Check if a specific cookie exists\n" +" if ($this->cookies->has('foo')) {\n" +" // Retrieve the value of the cookie\n" +" $fooValue = $this->cookies->get('foo');\n" +" // Do something with the cookie value\n" +" }\n" +"\n" +" // Retrieve another cookie value\n" +" $barValue = $this->cookies->get('bar');\n" +" // Do something with the bar cookie value\n" +" }\n" +"}\n" +"\n" +"## Sending cookies\n" +"\n" +"Since sending cookies is, in fact, sending a header but since forming the header isn't trivial, there is\n" +"`\\Yiisoft\\Cookies\\Cookie` class to help with it:\n" +"\n" +"```php\n" +"$cookie = (new \\Yiisoft\\Cookies\\Cookie('cookieName', 'value'))\n" +" ->withPath('/')\n" +" ->withDomain('yiiframework.com')\n" +" ->withHttpOnly(true)\n" +" ->withSecure(true)\n" +" ->withSameSite(\\Yiisoft\\Cookies\\Cookie::SAME_SITE_STRICT)\n" +" ->withMaxAge(new \\DateInterval('P7D'));\n" +"\n" +"return $cookie->addToResponse($response);\n" +msgstr "" +"final readonly class MyService\n" +"{\n" +" public function __construct(\n" +" private \\Yiisoft\\RequestProvider\\RequestCookieProvider $cookies\n" +" ) {}\n" +"\n" +" public function go(): void\n" +" {\n" +" // Check if a specific cookie exists\n" +" if ($this->cookies->has('foo')) {\n" +" // Retrieve the value of the cookie\n" +" $fooValue = $this->cookies->get('foo');\n" +" // Do something with the cookie value\n" +" }\n" +"\n" +" // Retrieve another cookie value\n" +" $barValue = $this->cookies->get('bar');\n" +" // Do something with the bar cookie value\n" +" }\n" +"}\n" +"\n" +"## Sending cookies\n" +"\n" +"Since sending cookies is, in fact, sending a header but since forming the header isn't trivial, there is\n" +"`\\Yiisoft\\Cookies\\Cookie` class to help with it:\n" +"\n" +"```php\n" +"$cookie = (new \\Yiisoft\\Cookies\\Cookie('cookieName', 'value'))\n" +" ->withPath('/')\n" +" ->withDomain('yiiframework.com')\n" +" ->withHttpOnly(true)\n" +" ->withSecure(true)\n" +" ->withSameSite(\\Yiisoft\\Cookies\\Cookie::SAME_SITE_STRICT)\n" +" ->withMaxAge(new \\DateInterval('P7D'));\n" +"\n" +"return $cookie->addToResponse($response);\n" + +#. type: Plain text +#: en/runtime/cookies.md +msgid "After forming a cookie call `addToResponse()` passing an instance of `\\Psr\\Http\\Message\\ResponseInterface` to add corresponding HTTP headers to it." +msgstr "Depois de montar o cookie, chame `addToResponse()` passando uma instância de `\\Psr\\Http\\Message\\ResponseInterface` para adicionar os headers HTTP correspondentes a ela." + +#. type: Title ## +#: en/runtime/cookies.md +#, no-wrap +msgid "Signing and encrypting cookies" +msgstr "Assinando e criptografando cookies" + +#. type: Plain text +#: en/runtime/cookies.md +msgid "To prevent the substitution of the cookie value, the package provides two implementations:" +msgstr "Para evitar que o valor do cookie seja substituído, o pacote oferece duas implementações:" + +#. type: Plain text +#: en/runtime/cookies.md +msgid "`Yiisoft\\Cookies\\CookieSigner` - signs each cookie with a unique prefix hash based on the value of the cookie and a secret key. `Yiisoft\\Cookies\\CookieEncryptor` - encrypts each cookie with a secret key." +msgstr "`Yiisoft\\Cookies\\CookieSigner` - assina cada cookie com um prefixo de hash único baseado no valor do cookie e em uma chave secreta. `Yiisoft\\Cookies\\CookieEncryptor` - criptografa cada cookie com uma chave secreta." + +#. type: Plain text +#: en/runtime/cookies.md +msgid "Encryption is more secure than signing but has lower performance." +msgstr "A criptografia é mais segura que a assinatura, mas tem desempenho menor." + +#. type: Fenced code block (php) +#: en/runtime/cookies.md +#, no-wrap +msgid "" +"$cookie = new \\Yiisoft\\Cookies\\Cookie('identity', 'identityValue');\n" +"\n" +"// The secret key used to sign and validate cookies.\n" +"$key = '0my1xVkjCJnD_q1yr6lUxcAdpDlTMwiU';\n" +"\n" +"$signer = new \\Yiisoft\\Cookies\\CookieSigner($key);\n" +"$encryptor = new \\Yiisoft\\Cookies\\CookieEncryptor($key);\n" +"\n" +"$signedCookie = $signer->sign($cookie);\n" +"$encryptedCookie = $encryptor->encrypt($cookie);\n" +msgstr "" +"$cookie = new \\Yiisoft\\Cookies\\Cookie('identity', 'identityValue');\n" +"\n" +"// The secret key used to sign and validate cookies.\n" +"$key = '0my1xVkjCJnD_q1yr6lUxcAdpDlTMwiU';\n" +"\n" +"$signer = new \\Yiisoft\\Cookies\\CookieSigner($key);\n" +"$encryptor = new \\Yiisoft\\Cookies\\CookieEncryptor($key);\n" +"\n" +"$signedCookie = $signer->sign($cookie);\n" +"$encryptedCookie = $encryptor->encrypt($cookie);\n" + +#. type: Plain text +#: en/runtime/cookies.md +msgid "To validate and get back the pure value, use the `validate()` and `decrypt()` method." +msgstr "Para validar e obter de volta o valor puro, use os métodos `validate()` e `decrypt()`." + +#. type: Fenced code block (php) +#: en/runtime/cookies.md +#, no-wrap +msgid "" +"$cookie = $signer->validate($signedCookie);\n" +"$cookie = $encryptor->decrypt($encryptedCookie);\n" +msgstr "" +"$cookie = $signer->validate($signedCookie);\n" +"$cookie = $encryptor->decrypt($encryptedCookie);\n" + +#. type: Plain text +#: en/runtime/cookies.md +msgid "If the cookie value is tampered with or hasn't been signed/encrypted before, a `\\RuntimeException` will be thrown. Therefore, if you aren't sure that the cookie value was signed/encrypted earlier, first use the `isSigned()` and `isEncrypted()` methods, respectively." +msgstr "Se o valor do cookie tiver sido adulterado ou não tiver sido assinado/criptografado antes, uma `\\RuntimeException` será lançada. Por isso, se você não tem certeza de que o valor do cookie foi assinado/criptografado antes, use primeiro os métodos `isSigned()` e `isEncrypted()`, respectivamente." + +#. type: Fenced code block (php) +#: en/runtime/cookies.md +#, no-wrap +msgid "" +"if ($signer->isSigned($cookie)) {\n" +" $cookie = $signer->validate($cookie);\n" +"}\n" +"\n" +"if ($encryptor->isEncrypted($cookie)) {\n" +" $cookie = $encryptor->decrypt($cookie);\n" +"}\n" +msgstr "" +"if ($signer->isSigned($cookie)) {\n" +" $cookie = $signer->validate($cookie);\n" +"}\n" +"\n" +"if ($encryptor->isEncrypted($cookie)) {\n" +" $cookie = $encryptor->decrypt($cookie);\n" +"}\n" + +#. type: Plain text +#: en/runtime/cookies.md +msgid "It makes sense to sign or encrypt the value of a cookie if you store important data that a user shouldn't change." +msgstr "Faz sentido assinar ou criptografar o valor de um cookie quando você guarda dados importantes que o usuário não deve alterar." + +#. type: Title ### +#: en/runtime/cookies.md +#, no-wrap +msgid "Automating encryption and signing" +msgstr "Automatizando a criptografia e a assinatura" + +#. type: Plain text +#: en/runtime/cookies.md +msgid "To automate the encryption/signing and decryption/validation of cookie values, use an instance of `Yiisoft\\Cookies\\CookieMiddleware`, which is [PSR-15](https://www.php-fig.org/psr/psr-15/) middleware." +msgstr "Para automatizar a criptografia/assinatura e a descriptografia/validação dos valores dos cookies, use uma instância de `Yiisoft\\Cookies\\CookieMiddleware`, que é um middleware [PSR-15](https://www.php-fig.org/psr/psr-15/)." + +#. type: Plain text +#: en/runtime/cookies.md +msgid "This middleware provides the following features:" +msgstr "Esse middleware oferece os seguintes recursos:" + +#. type: Bullet: '- ' +#: en/runtime/cookies.md +msgid "Validates and decrypts the cookie parameter values from the request." +msgstr "Valida e descriptografa os valores dos cookies vindos da requisição." + +#. type: Bullet: '- ' +#: en/runtime/cookies.md +msgid "Excludes the cookie parameter from the request if it was tampered with and logs information about it." +msgstr "Remove o cookie da requisição se ele tiver sido adulterado e registra essa informação no log." + +#. type: Bullet: '- ' +#: en/runtime/cookies.md +msgid "Encrypts/signs cookie values and replaces their clean values in the `Set-Cookie` headers in the response." +msgstr "Criptografa/assina os valores dos cookies e substitui os valores puros nos headers `Set-Cookie` da resposta." + +#. type: Plain text +#: en/runtime/cookies.md +msgid "In order for the middleware to know which values of which cookies need to be encrypted/signed, an array of settings must be passed to its constructor. The array keys are cookie name patterns and values are constant values of `CookieMiddleware::ENCRYPT` or `CookieMiddleware::SIGN`." +msgstr "Para o middleware saber quais valores de quais cookies precisam ser criptografados/assinados, é preciso passar um array de configurações para o construtor dele. As chaves do array são padrões de nomes de cookies e os valores são as constantes `CookieMiddleware::ENCRYPT` ou `CookieMiddleware::SIGN`." + +#. type: Fenced code block (php) +#: en/runtime/cookies.md +#, no-wrap +msgid "" +"use Yiisoft\\Cookies\\CookieMiddleware;\n" +"\n" +"$cookiesSettings = [\n" +" // Exact match with the name `identity`.\n" +" 'identity' => CookieMiddleware::ENCRYPT,\n" +" // Matches any number from 1 to 9 after the underscore.\n" +" 'name_[1-9]' => CookieMiddleware::SIGN,\n" +" // Matches any string after the prefix, including an\n" +" // empty string, except for the delimiters \"/\" and \"\\\".\n" +" 'prefix*' => CookieMiddleware::SIGN,\n" +"];\n" +msgstr "" +"use Yiisoft\\Cookies\\CookieMiddleware;\n" +"\n" +"$cookiesSettings = [\n" +" // Exact match with the name `identity`.\n" +" 'identity' => CookieMiddleware::ENCRYPT,\n" +" // Matches any number from 1 to 9 after the underscore.\n" +" 'name_[1-9]' => CookieMiddleware::SIGN,\n" +" // Matches any string after the prefix, including an\n" +" // empty string, except for the delimiters \"/\" and \"\\\".\n" +" 'prefix*' => CookieMiddleware::SIGN,\n" +"];\n" + +#. type: Plain text +#: en/runtime/cookies.md +msgid "For more information on using the wildcard pattern, see the [yiisoft/strings](https://github.com/yiisoft/strings#wildcardpattern-usage) package." +msgstr "Para mais informações sobre o uso de padrões com curinga, veja o pacote [yiisoft/strings](https://github.com/yiisoft/strings#wildcardpattern-usage)." + +#. type: Plain text +#: en/runtime/cookies.md +msgid "Creating and using middleware:" +msgstr "Criando e usando o middleware:" + +#. type: Fenced code block (php) +#: en/runtime/cookies.md +#, no-wrap +msgid "" +"/**\n" +" * @var \\Psr\\Http\\Message\\ServerRequestInterface $request\n" +" * @var \\Psr\\Http\\Server\\RequestHandlerInterface $handler\n" +" * @var \\Psr\\Log\\LoggerInterface $logger\n" +" */\n" +"\n" +"// The secret key used to sign and validate cookies.\n" +"$key = '0my1xVkjCJnD_q1yr6lUxcAdpDlTMwiU';\n" +"$signer = new \\Yiisoft\\Cookies\\CookieSigner($key);\n" +"$encryptor = new \\Yiisoft\\Cookies\\CookieEncryptor($key);\n" +"\n" +"$cookiesSettings = [\n" +" 'identity' => \\Yiisoft\\Cookies\\CookieMiddleware::ENCRYPT,\n" +" 'session' => \\Yiisoft\\Cookies\\CookieMiddleware::SIGN,\n" +"];\n" +"\n" +"$middleware = new \\Yiisoft\\Cookies\\CookieMiddleware(\n" +" $logger\n" +" $encryptor,\n" +" $signer,\n" +" $cookiesSettings,\n" +");\n" +"\n" +"// The cookie parameter values from the request are decrypted/validated.\n" +"// The cookie values are encrypted/signed and appended to the response.\n" +"$response = $middleware->process($request, $handler);\n" +msgstr "" +"/**\n" +" * @var \\Psr\\Http\\Message\\ServerRequestInterface $request\n" +" * @var \\Psr\\Http\\Server\\RequestHandlerInterface $handler\n" +" * @var \\Psr\\Log\\LoggerInterface $logger\n" +" */\n" +"\n" +"// The secret key used to sign and validate cookies.\n" +"$key = '0my1xVkjCJnD_q1yr6lUxcAdpDlTMwiU';\n" +"$signer = new \\Yiisoft\\Cookies\\CookieSigner($key);\n" +"$encryptor = new \\Yiisoft\\Cookies\\CookieEncryptor($key);\n" +"\n" +"$cookiesSettings = [\n" +" 'identity' => \\Yiisoft\\Cookies\\CookieMiddleware::ENCRYPT,\n" +" 'session' => \\Yiisoft\\Cookies\\CookieMiddleware::SIGN,\n" +"];\n" +"\n" +"$middleware = new \\Yiisoft\\Cookies\\CookieMiddleware(\n" +" $logger\n" +" $encryptor,\n" +" $signer,\n" +" $cookiesSettings,\n" +");\n" +"\n" +"// The cookie parameter values from the request are decrypted/validated.\n" +"// The cookie values are encrypted/signed and appended to the response.\n" +"$response = $middleware->process($request, $handler);\n" + +#. type: Plain text +#: en/runtime/cookies.md +msgid "If the `$cookiesSettings` array is empty, no cookies will be encrypted and signed." +msgstr "Se o array `$cookiesSettings` estiver vazio, nenhum cookie será criptografado ou assinado." + +#. type: Title ## +#: en/runtime/cookies.md +#, no-wrap +msgid "Cookies security" +msgstr "Segurança dos cookies" + +#. type: Plain text +#: en/runtime/cookies.md +msgid "You should configure each cookie to be secure. Important security settings are:" +msgstr "Você deve configurar cada cookie para ser seguro. As configurações de segurança importantes são:" + +#. type: Bullet: '- ' +#: en/runtime/cookies.md +msgid "`httpOnly`. Setting it to `true` would prevent JavaScript to access cookie value." +msgstr "`httpOnly`. Definir como `true` impede que o JavaScript acesse o valor do cookie." + +#. type: Bullet: '- ' +#: en/runtime/cookies.md +msgid "`secure`. Setting it to `true` would prevent sending cookie via `HTTP`. It will be sent via `HTTPS` only." +msgstr "`secure`. Definir como `true` impede o envio do cookie via `HTTP`. Ele só será enviado via `HTTPS`." + +#. type: Bullet: '- ' +#: en/runtime/cookies.md +msgid "`sameSite`, if set to either `SAME_SITE_LAX` or `SAME_SITE_STRICT` would prevent sending a cookie in cross-site browsing context. `SAME_SITE_LAX` would prevent cookie sending during CSRF-prone request methods (e.g., POST, PUT, PATCH, etc.). `SAME_SITE_STRICT` would prevent cookies sending for all methods." +msgstr "`sameSite`, se definido como `SAME_SITE_LAX` ou `SAME_SITE_STRICT`, impede o envio do cookie em contexto de navegação entre sites. `SAME_SITE_LAX` impede o envio do cookie em métodos de requisição sujeitos a CSRF (por exemplo, POST, PUT, PATCH etc.). `SAME_SITE_STRICT` impede o envio dos cookies em todos os métodos." + +#. type: Bullet: '- ' +#: en/runtime/cookies.md +msgid "Sign or encrypt the value of the cookie to prevent spoofing of values if the data in the value shouldn't be tampered with." +msgstr "Assine ou criptografe o valor do cookie para evitar falsificação quando os dados não puderem ser adulterados." diff --git a/_translations/po/pt-BR/guide_runtime_handling-errors.md.po b/_translations/po/pt-BR/guide_runtime_handling-errors.md.po new file mode 100644 index 00000000..9612056b --- /dev/null +++ b/_translations/po/pt-BR/guide_runtime_handling-errors.md.po @@ -0,0 +1,638 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-05-05 22:01+0000\n" +"PO-Revision-Date: 2026-05-05 22:01+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/runtime/handling-errors.md +#, no-wrap +msgid "Handling errors" +msgstr "Tratamento de erros" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "Yii has a [yiisoft/error-handler](https://github.com/yiisoft/error-handler) package that makes error handling a much more pleasant experience than before. In particular, the Yii error handler provides the following:" +msgstr "O Yii tem o pacote [yiisoft/error-handler](https://github.com/yiisoft/error-handler), que torna o tratamento de erros muito mais agradável do que antes. Em particular, o error handler do Yii oferece:" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/handling-errors.md +msgid "[PSR-15](https://www.php-fig.org/psr/psr-15/) middleware for catching unhandled errors." +msgstr "Middleware [PSR-15](https://www.php-fig.org/psr/psr-15/) para capturar erros não tratados." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/handling-errors.md +msgid "PSR-15 middleware for mapping certain exceptions to custom responses." +msgstr "Middleware PSR-15 para mapear certas exceções para respostas personalizadas." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/handling-errors.md +msgid "Production and debug modes." +msgstr "Modos de produção e de debug." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/handling-errors.md +msgid "Debug mode displays details, stacktrace, has dark and light themes and handy buttons to search for error without typing." +msgstr "O modo debug mostra detalhes e o stacktrace, tem temas claro e escuro e botões práticos para pesquisar o erro sem digitar." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/handling-errors.md +msgid "Takes PHP settings into account." +msgstr "Leva em conta as configurações do PHP." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/handling-errors.md +msgid "Handles out of memory errors, fatal errors, warnings, notices, and exceptions." +msgstr "Trata erros de falta de memória, erros fatais, warnings, notices e exceções." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/handling-errors.md +msgid "Can use any [PSR-3](https://www.php-fig.org/psr/psr-3/) compatible logger for error logging." +msgstr "Pode usar qualquer logger compatível com a [PSR-3](https://www.php-fig.org/psr/psr-3/) para registrar os erros." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/handling-errors.md +msgid "Detects a response format based on a mime type of the request." +msgstr "Detecta o formato da resposta com base no mime type da requisição." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/handling-errors.md +msgid "Supports responding with HTML, plain text, JSON, XML, and headers out of the box." +msgstr "Suporta respostas em HTML, texto puro, JSON, XML e headers sem configuração extra." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/handling-errors.md +msgid "You can implement your own error rendering for extra types." +msgstr "Você pode implementar a sua própria renderização de erros para outros tipos." + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "This guide describes how to use the error handler in the [Yii framework](https://www.yiiframework.com/), for information about using it separate from Yii, see the [package description](https://github.com/yiisoft/error-handler)." +msgstr "Este guia descreve como usar o error handler no [framework Yii](https://www.yiiframework.com/). Para usá-lo separado do Yii, veja a [descrição do pacote](https://github.com/yiisoft/error-handler)." + +#. type: Title ## +#: ../src/guide/runtime/handling-errors.md +#, no-wrap +msgid "Using error handler" +msgstr "Usando o error handler" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "The error handler consists of two parts. One part is `Yiisoft\\ErrorHandler\\Middleware\\ErrorCatcher` middleware that, when registered, catches exceptions that may appear during middleware stack execution and passes them to the handler. Another part is the error handler itself, `Yiisoft\\ErrorHandler\\ErrorHandler`, that's catching exceptions occurring outside the middleware stack and fatal errors. The handler also converts warnings and notices to exceptions and does more handy things." +msgstr "O error handler tem duas partes. Uma é o middleware `Yiisoft\\ErrorHandler\\Middleware\\ErrorCatcher`, que, quando registrado, captura as exceções que podem surgir durante a execução da pilha de middlewares e as passa para o handler. A outra é o próprio error handler, `Yiisoft\\ErrorHandler\\ErrorHandler`, que captura as exceções que ocorrem fora da pilha de middlewares e os erros fatais. O handler também converte warnings e notices em exceções e faz outras coisas úteis." + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "Error handler is registered in the application itself. Usually it happens in `ApplicationRunner`. By default, the handler configuration comes from the container. You may configure it in the application configuration, `config/web.php` like the following:" +msgstr "O error handler é registrado na própria aplicação. Normalmente isso acontece no `ApplicationRunner`. Por padrão, a configuração do handler vem do container. Você pode configurá-lo na configuração da aplicação, `config/web.php`, assim:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/handling-errors.md +#, no-wrap +msgid "" +"use Psr\\Log\\LoggerInterface;\n" +"use Yiisoft\\ErrorHandler\\ErrorHandler;\n" +"use Yiisoft\\ErrorHandler\\Renderer\\HtmlRenderer;\n" +"use Yiisoft\\ErrorHandler\\ThrowableRendererInterface;\n" +"\n" +"return [\n" +" // ...\n" +" ErrorHandler::class => static function (LoggerInterface $logger, ThrowableRendererInterface $renderer) {\n" +" $errorHandler = new ErrorHandler($logger, $renderer);\n" +" // Set the size of the reserved memory to 512 KB. Defaults to 256KB.\n" +" $errorHandler->memoryReserveSize(524_288);\n" +" return $errorHandler;\n" +" },\n" +" \n" +" ThrowableRendererInterface::class => static fn () => new HtmlRenderer([\n" +" // Defaults to the package file \"templates/production.php\".\n" +" 'template' => '/full/path/to/production/template/file',\n" +" // Defaults to package file \"templates/development.php\".\n" +" 'verboseTemplate' => '/full/path/to/development/template/file',\n" +" // Maximum number of source code lines to be displayed. Defaults to 19.\n" +" 'maxSourceLines' => 20,\n" +" // Maximum number of trace source code lines to be displayed. Defaults to 13.\n" +" 'maxTraceLines' => 5,\n" +" // Trace the header line with placeholders (file, line, icon) to be substituted. Defaults to `null`.\n" +" 'traceHeaderLine' => '{icon}',\n" +" ]),\n" +" // ...\n" +"];\n" +msgstr "" +"use Psr\\Log\\LoggerInterface;\n" +"use Yiisoft\\ErrorHandler\\ErrorHandler;\n" +"use Yiisoft\\ErrorHandler\\Renderer\\HtmlRenderer;\n" +"use Yiisoft\\ErrorHandler\\ThrowableRendererInterface;\n" +"\n" +"return [\n" +" // ...\n" +" ErrorHandler::class => static function (LoggerInterface $logger, ThrowableRendererInterface $renderer) {\n" +" $errorHandler = new ErrorHandler($logger, $renderer);\n" +" // Set the size of the reserved memory to 512 KB. Defaults to 256KB.\n" +" $errorHandler->memoryReserveSize(524_288);\n" +" return $errorHandler;\n" +" },\n" +" \n" +" ThrowableRendererInterface::class => static fn () => new HtmlRenderer([\n" +" // Defaults to the package file \"templates/production.php\".\n" +" 'template' => '/full/path/to/production/template/file',\n" +" // Defaults to package file \"templates/development.php\".\n" +" 'verboseTemplate' => '/full/path/to/development/template/file',\n" +" // Maximum number of source code lines to be displayed. Defaults to 19.\n" +" 'maxSourceLines' => 20,\n" +" // Maximum number of trace source code lines to be displayed. Defaults to 13.\n" +" 'maxTraceLines' => 5,\n" +" // Trace the header line with placeholders (file, line, icon) to be substituted. Defaults to `null`.\n" +" 'traceHeaderLine' => '{icon}',\n" +" ]),\n" +" // ...\n" +"];\n" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "As aforementioned, the error handler turns all non-fatal PHP errors into catchable exceptions (`Yiisoft\\ErrorHandler\\Exception\\ErrorException`). This means you can use the following code to deal with PHP errors:" +msgstr "Como dito acima, o error handler transforma todos os erros não fatais do PHP em exceções que podem ser capturadas (`Yiisoft\\ErrorHandler\\Exception\\ErrorException`). Isso significa que você pode usar o código a seguir para lidar com erros do PHP:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/handling-errors.md +#, no-wrap +msgid "" +"try {\n" +" 10 / 0;\n" +"} catch (\\Yiisoft\\ErrorHandler\\Exception\\ErrorException $e) {\n" +" // Write a log or something else.\n" +"}\n" +"// execution continues...\n" +msgstr "" +"try {\n" +" 10 / 0;\n" +"} catch (\\Yiisoft\\ErrorHandler\\Exception\\ErrorException $e) {\n" +" // Write a log or something else.\n" +"}\n" +"// execution continues...\n" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "The package has another middleware, `Yiisoft\\ErrorHandler\\Middleware\\ExceptionResponder`. This middleware maps certain exceptions to custom responses. Configure it in the application configuration as follows:" +msgstr "O pacote tem outro middleware, `Yiisoft\\ErrorHandler\\Middleware\\ExceptionResponder`. Esse middleware mapeia certas exceções para respostas personalizadas. Configure-o na configuração da aplicação assim:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/handling-errors.md +#, no-wrap +msgid "" +"use Psr\\Http\\Message\\ResponseFactoryInterface;\n" +"use Yiisoft\\ErrorHandler\\Middleware\\ExceptionResponder;\n" +"use Yiisoft\\Injector\\Injector;\n" +"\n" +"return [\n" +" // ...\n" +" ExceptionResponder::class => static function (ResponseFactoryInterface $responseFactory, Injector $injector) {\n" +" $exceptionMap = [\n" +" // Status code with which the factory creates the response.\n" +" MyNotFoundException::class => 404,\n" +" // PHP callable that must return a `Psr\\Http\\Message\\ResponseInterface`.\n" +" MyHttpException::class => static fn (MyHttpException $exception) => new MyResponse($exception),\n" +" // ...\n" +" ];\n" +" \n" +" return new ExceptionResponder($exceptionMap, $responseFactory, $injector);\n" +" },\n" +"];\n" +msgstr "" +"use Psr\\Http\\Message\\ResponseFactoryInterface;\n" +"use Yiisoft\\ErrorHandler\\Middleware\\ExceptionResponder;\n" +"use Yiisoft\\Injector\\Injector;\n" +"\n" +"return [\n" +" // ...\n" +" ExceptionResponder::class => static function (ResponseFactoryInterface $responseFactory, Injector $injector) {\n" +" $exceptionMap = [\n" +" // Status code with which the factory creates the response.\n" +" MyNotFoundException::class => 404,\n" +" // PHP callable that must return a `Psr\\Http\\Message\\ResponseInterface`.\n" +" MyHttpException::class => static fn (MyHttpException $exception) => new MyResponse($exception),\n" +" // ...\n" +" ];\n" +" \n" +" return new ExceptionResponder($exceptionMap, $responseFactory, $injector);\n" +" },\n" +"];\n" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "Note that when configuring application middleware stack, you must place `Yiisoft\\ErrorHandler\\Middleware\\ExceptionResponder` before `Yiisoft\\ErrorHandler\\Middleware\\ErrorCatcher`." +msgstr "Ao configurar a pilha de middlewares da aplicação, você deve colocar `Yiisoft\\ErrorHandler\\Middleware\\ExceptionResponder` antes de `Yiisoft\\ErrorHandler\\Middleware\\ErrorCatcher`." + +#. type: Title ## +#: ../src/guide/runtime/handling-errors.md +#, no-wrap +msgid "Rendering error data" +msgstr "Renderizando os dados do erro" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "One of the renderers could render error data into a certain format. The following renderers are available out of the box:" +msgstr "Cada renderer converte os dados do erro para um formato específico. Os seguintes renderers já vêm prontos:" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/handling-errors.md +msgid "`Yiisoft\\ErrorHandler\\Renderer\\HeaderRenderer` - Renders error into HTTP headers. It's used for `HEAD` request." +msgstr "`Yiisoft\\ErrorHandler\\Renderer\\HeaderRenderer` - Renderiza o erro em headers HTTP. É usado em requisições `HEAD`." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/handling-errors.md +msgid "`Yiisoft\\ErrorHandler\\Renderer\\HtmlRenderer` - Renders error into HTML." +msgstr "`Yiisoft\\ErrorHandler\\Renderer\\HtmlRenderer` - Renderiza o erro em HTML." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/handling-errors.md +msgid "`Yiisoft\\ErrorHandler\\Renderer\\JsonRenderer` - Renders error into JSON." +msgstr "`Yiisoft\\ErrorHandler\\Renderer\\JsonRenderer` - Renderiza o erro em JSON." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/handling-errors.md +msgid "`Yiisoft\\ErrorHandler\\Renderer\\PlainTextRenderer` - Renders error into plain text." +msgstr "`Yiisoft\\ErrorHandler\\Renderer\\PlainTextRenderer` - Renderiza o erro em texto puro." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/handling-errors.md +msgid "`Yiisoft\\ErrorHandler\\Renderer\\XmlRenderer` - Renders error into XML." +msgstr "`Yiisoft\\ErrorHandler\\Renderer\\XmlRenderer` - Renderiza o erro em XML." + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "The renderer produces detailed error data depending on whether debug mode is enabled or disabled." +msgstr "O renderer gera dados de erro mais ou menos detalhados conforme o modo debug esteja ativado ou não." + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "An Example of header rendering with a debugging mode turned off:" +msgstr "Exemplo de renderização em headers com o modo debug desativado:" + +#. type: Fenced code block +#: ../src/guide/runtime/handling-errors.md +#, no-wrap +msgid "" +"...\n" +"X-Error-Message: An internal server error occurred.\n" +"...\n" +msgstr "" +"...\n" +"X-Error-Message: An internal server error occurred.\n" +"...\n" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "An Example of header rendering with a debugging mode turned on:" +msgstr "Exemplo de renderização em headers com o modo debug ativado:" + +#. type: Fenced code block +#: ../src/guide/runtime/handling-errors.md +#, no-wrap +msgid "" +"...\n" +"X-Error-Type: Error\n" +"X-Error-Message: Call to undefined function App\\Controller\\myFunc()\n" +"X-Error-Code: 0\n" +"X-Error-File: /var/www/yii/app/src/Controller/SiteController.php\n" +"X-Error-Line: 21\n" +"...\n" +msgstr "" +"...\n" +"X-Error-Type: Error\n" +"X-Error-Message: Call to undefined function App\\Controller\\myFunc()\n" +"X-Error-Code: 0\n" +"X-Error-File: /var/www/yii/app/src/Controller/SiteController.php\n" +"X-Error-Line: 21\n" +"...\n" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "Example of JSON rendering output with a debugging mode turned off:" +msgstr "Exemplo de saída JSON com o modo debug desativado:" + +#. type: Fenced code block (json) +#: ../src/guide/runtime/handling-errors.md +#, no-wrap +msgid "{\"message\":\"An internal server error occurred.\"}\n" +msgstr "{\"message\":\"An internal server error occurred.\"}\n" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "An Example of JSON rendering output with debugging mode turned on:" +msgstr "Exemplo de saída JSON com o modo debug ativado:" + +#. type: Fenced code block (json) +#: ../src/guide/runtime/handling-errors.md +#, no-wrap +msgid "" +"{\n" +" \"type\": \"Error\",\n" +" \"message\": \"Call to undefined function App\\\\Controller\\\\myFunc()\",\n" +" \"code\": 0,\n" +" \"file\": \"/var/www/yii/app/src/Controller/SiteController.php\",\n" +" \"line\": 21,\n" +" \"trace\": [\n" +" {\n" +" \"function\": \"index\",\n" +" \"class\": \"App\\\\Controller\\\\SiteController\",\n" +" \"type\": \"->\"\n" +" },\n" +" {\n" +" \"file\": \"/var/www/yii/app/vendor/yiisoft/injector/src/Injector.php\",\n" +" \"line\": 63,\n" +" \"function\": \"invokeArgs\",\n" +" \"class\": \"ReflectionFunction\",\n" +" \"type\": \"->\"\n" +" },\n" +" ...\n" +" ]\n" +"}\n" +msgstr "" +"{\n" +" \"type\": \"Error\",\n" +" \"message\": \"Call to undefined function App\\\\Controller\\\\myFunc()\",\n" +" \"code\": 0,\n" +" \"file\": \"/var/www/yii/app/src/Controller/SiteController.php\",\n" +" \"line\": 21,\n" +" \"trace\": [\n" +" {\n" +" \"function\": \"index\",\n" +" \"class\": \"App\\\\Controller\\\\SiteController\",\n" +" \"type\": \"->\"\n" +" },\n" +" {\n" +" \"file\": \"/var/www/yii/app/vendor/yiisoft/injector/src/Injector.php\",\n" +" \"line\": 63,\n" +" \"function\": \"invokeArgs\",\n" +" \"class\": \"ReflectionFunction\",\n" +" \"type\": \"->\"\n" +" },\n" +" ...\n" +" ]\n" +"}\n" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "Example of HTML rendering with debugging mode turned off:" +msgstr "Exemplo de renderização HTML com o modo debug desativado:" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "![View production](/images/guide/runtime/view-production.png)" +msgstr "![Tela de produção](/images/guide/runtime/view-production.png)" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "Example of HTML rendering with debugging mode on and a light theme:" +msgstr "Exemplo de renderização HTML com o modo debug ativado e tema claro:" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "![View development with light theme](/images/guide/runtime/view-development-light.png)" +msgstr "![Tela de desenvolvimento com tema claro](/images/guide/runtime/view-development-light.png)" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "Example of HTML rendering with debugging mode on and a dark theme:" +msgstr "Exemplo de renderização HTML com o modo debug ativado e tema escuro:" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "![View development with dark theme](/images/guide/runtime/view-development-dark.png)" +msgstr "![Tela de desenvolvimento com tema escuro](/images/guide/runtime/view-development-dark.png)" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "The error catcher chooses how to render an exception based on `accept` HTTP header. If it's `text/html` or any unknown content type, it will use the error or exception HTML template to display errors. For other mime types, the error handler will choose different renderers registered in a renderer provider. By default, it supports JSON, XML, and plain text." +msgstr "O error catcher escolhe como renderizar uma exceção com base no header HTTP `accept`. Se ele for `text/html` ou um tipo de conteúdo desconhecido, usa o template HTML de erro ou de exceção para exibir os erros. Para outros mime types, o error handler escolhe entre os renderers registrados em um renderer provider. Por padrão, ele suporta JSON, XML e texto puro." + +#. type: Title ### +#: ../src/guide/runtime/handling-errors.md +#, no-wrap +msgid "Implementing your own renderer" +msgstr "Implementando o seu próprio renderer" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "You may customize the error response format by implementing `Yiisoft\\ErrorHandler\\ThrowableRendererInterface`. The renderer converts a throwable into `Yiisoft\\ErrorHandler\\ErrorData`, which contains the response body and headers." +msgstr "Você pode personalizar o formato da resposta de erro implementando `Yiisoft\\ErrorHandler\\ThrowableRendererInterface`. O renderer converte um throwable em `Yiisoft\\ErrorHandler\\ErrorData`, que contém o corpo e os headers da resposta." + +#. type: Fenced code block (php) +#: ../src/guide/runtime/handling-errors.md +#, no-wrap +msgid "" +"use Psr\\Http\\Message\\ServerRequestInterface;\n" +"use Throwable;\n" +"use Yiisoft\\ErrorHandler\\ErrorData;\n" +"use Yiisoft\\ErrorHandler\\ThrowableRendererInterface;\n" +"use Yiisoft\\Http\\Header;\n" +"\n" +"final readonly class MyRenderer implements ThrowableRendererInterface\n" +"{\n" +" public function render(Throwable $t, ?ServerRequestInterface $request = null): ErrorData\n" +" {\n" +" return new ErrorData(\n" +" '{\"message\":\"An internal server error occurred.\"}',\n" +" [Header::CONTENT_TYPE => 'application/problem+json'],\n" +" );\n" +" }\n" +"\n" +" public function renderVerbose(Throwable $t, ?ServerRequestInterface $request = null): ErrorData\n" +" {\n" +" return new ErrorData(\n" +" json_encode(\n" +" [\n" +" 'type' => $t::class,\n" +" 'message' => $t->getMessage(),\n" +" 'file' => $t->getFile(),\n" +" 'line' => $t->getLine(),\n" +" ],\n" +" JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES,\n" +" ),\n" +" [Header::CONTENT_TYPE => 'application/problem+json'],\n" +" );\n" +" }\n" +"}\n" +msgstr "" +"use Psr\\Http\\Message\\ServerRequestInterface;\n" +"use Throwable;\n" +"use Yiisoft\\ErrorHandler\\ErrorData;\n" +"use Yiisoft\\ErrorHandler\\ThrowableRendererInterface;\n" +"use Yiisoft\\Http\\Header;\n" +"\n" +"final readonly class MyRenderer implements ThrowableRendererInterface\n" +"{\n" +" public function render(Throwable $t, ?ServerRequestInterface $request = null): ErrorData\n" +" {\n" +" return new ErrorData(\n" +" '{\"message\":\"An internal server error occurred.\"}',\n" +" [Header::CONTENT_TYPE => 'application/problem+json'],\n" +" );\n" +" }\n" +"\n" +" public function renderVerbose(Throwable $t, ?ServerRequestInterface $request = null): ErrorData\n" +" {\n" +" return new ErrorData(\n" +" json_encode(\n" +" [\n" +" 'type' => $t::class,\n" +" 'message' => $t->getMessage(),\n" +" 'file' => $t->getFile(),\n" +" 'line' => $t->getLine(),\n" +" ],\n" +" JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES,\n" +" ),\n" +" [Header::CONTENT_TYPE => 'application/problem+json'],\n" +" );\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "Register the renderer in `config/common/di/error-handler.php`:" +msgstr "Registre o renderer em `config/common/di/error-handler.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/handling-errors.md +#, no-wrap +msgid "" +"use Psr\\Container\\ContainerInterface;\n" +"use App\\Error\\MyRenderer;\n" +"use Yiisoft\\Definitions\\DynamicReference;\n" +"use Yiisoft\\ErrorHandler\\Renderer\\HtmlRenderer;\n" +"use Yiisoft\\ErrorHandler\\Renderer\\JsonRenderer;\n" +"use Yiisoft\\ErrorHandler\\Renderer\\PlainTextRenderer;\n" +"use Yiisoft\\ErrorHandler\\Renderer\\XmlRenderer;\n" +"use Yiisoft\\ErrorHandler\\RendererProvider\\CompositeRendererProvider;\n" +"use Yiisoft\\ErrorHandler\\RendererProvider\\ContentTypeRendererProvider;\n" +"use Yiisoft\\ErrorHandler\\RendererProvider\\HeadRendererProvider;\n" +"use Yiisoft\\ErrorHandler\\ThrowableResponseFactory;\n" +"use Yiisoft\\ErrorHandler\\ThrowableResponseFactoryInterface;\n" +"\n" +"return [\n" +" ThrowableResponseFactoryInterface::class => [\n" +" 'class' => ThrowableResponseFactory::class,\n" +" '__construct()' => [\n" +" 'rendererProvider' => DynamicReference::to(\n" +" static fn (ContainerInterface $container) => new CompositeRendererProvider(\n" +" new HeadRendererProvider(),\n" +" new ContentTypeRendererProvider($container, [\n" +" 'application/problem+json' => MyRenderer::class,\n" +" 'application/json' => JsonRenderer::class,\n" +" 'application/xml' => XmlRenderer::class,\n" +" 'text/xml' => XmlRenderer::class,\n" +" 'text/plain' => PlainTextRenderer::class,\n" +" 'text/html' => HtmlRenderer::class,\n" +" '*/*' => HtmlRenderer::class,\n" +" ]),\n" +" ),\n" +" ),\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +"use Psr\\Container\\ContainerInterface;\n" +"use App\\Error\\MyRenderer;\n" +"use Yiisoft\\Definitions\\DynamicReference;\n" +"use Yiisoft\\ErrorHandler\\Renderer\\HtmlRenderer;\n" +"use Yiisoft\\ErrorHandler\\Renderer\\JsonRenderer;\n" +"use Yiisoft\\ErrorHandler\\Renderer\\PlainTextRenderer;\n" +"use Yiisoft\\ErrorHandler\\Renderer\\XmlRenderer;\n" +"use Yiisoft\\ErrorHandler\\RendererProvider\\CompositeRendererProvider;\n" +"use Yiisoft\\ErrorHandler\\RendererProvider\\ContentTypeRendererProvider;\n" +"use Yiisoft\\ErrorHandler\\RendererProvider\\HeadRendererProvider;\n" +"use Yiisoft\\ErrorHandler\\ThrowableResponseFactory;\n" +"use Yiisoft\\ErrorHandler\\ThrowableResponseFactoryInterface;\n" +"\n" +"return [\n" +" ThrowableResponseFactoryInterface::class => [\n" +" 'class' => ThrowableResponseFactory::class,\n" +" '__construct()' => [\n" +" 'rendererProvider' => DynamicReference::to(\n" +" static fn (ContainerInterface $container) => new CompositeRendererProvider(\n" +" new HeadRendererProvider(),\n" +" new ContentTypeRendererProvider($container, [\n" +" 'application/problem+json' => MyRenderer::class,\n" +" 'application/json' => JsonRenderer::class,\n" +" 'application/xml' => XmlRenderer::class,\n" +" 'text/xml' => XmlRenderer::class,\n" +" 'text/plain' => PlainTextRenderer::class,\n" +" 'text/html' => HtmlRenderer::class,\n" +" '*/*' => HtmlRenderer::class,\n" +" ]),\n" +" ),\n" +" ),\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "The `renderers` array maps `Accept` header content types to renderer class names. When you provide this array, it replaces the default map, so include the default renderer classes you still need." +msgstr "O array `renderers` mapeia os tipos de conteúdo do header `Accept` para nomes de classes de renderer. Quando você informa esse array, ele substitui o mapa padrão, então inclua as classes de renderer padrão que ainda precisar." + +#. type: Title ## +#: ../src/guide/runtime/handling-errors.md +#, no-wrap +msgid "Friendly exceptions" +msgstr "Exceções amigáveis" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "Yii error renderer supports [friendly exceptions](https://github.com/yiisoft/friendly-exception) that make error handling an even more pleasant experience for your team. The idea is to offer a readable name and possible solutions to the problem:" +msgstr "O renderer de erros do Yii suporta [exceções amigáveis](https://github.com/yiisoft/friendly-exception), que deixam o tratamento de erros ainda mais agradável para o seu time. A ideia é oferecer um nome legível e possíveis soluções para o problema:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/handling-errors.md +#, no-wrap +msgid "" +"use Yiisoft\\FriendlyException\\FriendlyExceptionInterface;\n" +"\n" +"final readonly class RequestTimeoutException extends \\RuntimeException implements FriendlyExceptionInterface\n" +"{\n" +" public function getName(): string\n" +" {\n" +" return 'Request timed out';\n" +" }\n" +" \n" +" public function getSolution(): ?string\n" +" {\n" +" return <<<'SOLUTION'\n" +"Likely it is a result of resource request is not responding in a timely fashion. Try increasing timeout.\n" +"SOLUTION;\n" +" }\n" +"}\n" +msgstr "" +"use Yiisoft\\FriendlyException\\FriendlyExceptionInterface;\n" +"\n" +"final readonly class RequestTimeoutException extends \\RuntimeException implements FriendlyExceptionInterface\n" +"{\n" +" public function getName(): string\n" +" {\n" +" return 'Request timed out';\n" +" }\n" +" \n" +" public function getSolution(): ?string\n" +" {\n" +" return <<<'SOLUTION'\n" +"Likely it is a result of resource request is not responding in a timely fashion. Try increasing timeout.\n" +"SOLUTION;\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "When the application throws such an exception, the error renderer would display the name and the solution if the debug mode is on." +msgstr "Quando a aplicação lança uma exceção desse tipo, o renderer de erros mostra o nome e a solução se o modo debug estiver ativado." diff --git a/_translations/po/pt-BR/guide_runtime_logging.md.po b/_translations/po/pt-BR/guide_runtime_logging.md.po new file mode 100644 index 00000000..acf26e9a --- /dev/null +++ b/_translations/po/pt-BR/guide_runtime_logging.md.po @@ -0,0 +1,910 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-10-15 10:10+0000\n" +"PO-Revision-Date: 2026-10-15 10:10+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "Logging" +msgstr "Logs" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "Yii relies on [PSR-3 interfaces](https://www.php-fig.org/psr/psr-3/) for logging, so you could configure any PSR-3 compatible logging library to do the actual job." +msgstr "O Yii usa as [interfaces PSR-3](https://www.php-fig.org/psr/psr-3/) para logs, então você pode configurar qualquer biblioteca de log compatível com a PSR-3 para fazer o trabalho." + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "Yii provides its own logger that's highly customizable and extensible. Using it, you can log various types of messages, filter them, and gather them at different targets, such as files or emails." +msgstr "O Yii oferece o seu próprio logger, que é bem personalizável e extensível. Com ele, você pode registrar vários tipos de mensagens, filtrá-las e reuni-las em destinos diferentes, como arquivos ou e-mails." + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "Using the Yii logging framework involves the following steps:" +msgstr "Usar o sistema de logs do Yii envolve os seguintes passos:" + +#. type: Bullet: '* ' +#: ../src/guide/runtime/logging.md +msgid "Record [log messages](#log-messages) at various places in your code;" +msgstr "Registrar [mensagens de log](#mensagens-de-log) em vários pontos do código;" + +#. type: Bullet: '* ' +#: ../src/guide/runtime/logging.md +msgid "Configure [log targets](#log-targets) in the application configuration to filter and export log messages;" +msgstr "Configurar [destinos de log](#destinos-de-log) na configuração da aplicação para filtrar e exportar as mensagens;" + +#. type: Bullet: '* ' +#: ../src/guide/runtime/logging.md +msgid "Examine the filtered logged messages exported by different targets (e.g. the Yii debugger)." +msgstr "Examinar as mensagens filtradas exportadas pelos diferentes destinos (por exemplo, o debugger do Yii)." + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "In this section, the focus in on the first two steps." +msgstr "Esta seção foca nos dois primeiros passos." + +#. type: Title ## +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "Default log destination" +msgstr "Destino padrão dos logs" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "Yii3 application templates ([web](https://github.com/yiisoft/app/blob/master/config/common/di/logger.php) and [API](https://github.com/yiisoft/app-api/blob/master/config/common/di/logger.php)) configure `Yiisoft\\Log\\StreamTarget`, which writes to standard output (`stdout`, or `php://stdout`) by default. They don't create application log files, such as `runtime/logs/app.log`. `StreamTarget` also supports standard error (`stderr`, or `php://stderr`), but you must configure it explicitly." +msgstr "Os templates de aplicação do Yii3 ([web](https://github.com/yiisoft/app/blob/master/config/common/di/logger.php) e [API](https://github.com/yiisoft/app-api/blob/master/config/common/di/logger.php)) configuram o `Yiisoft\\Log\\StreamTarget`, que por padrão escreve na saída padrão (`stdout`, ou `php://stdout`). Eles não criam arquivos de log da aplicação, como `runtime/logs/app.log`. O `StreamTarget` também suporta a saída de erro padrão (`stderr`, ou `php://stderr`), mas você precisa configurá-la explicitamente." + +#. type: Plain text +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "" +"This works well with Docker, which [collects container output](https://docs.docker.com/engine/logging/).\n" +"Use `docker logs ` to read it when the container's logging driver supports that command.\n" +msgstr "" +"Isso funciona bem com o Docker, que [coleta a saída dos containers](https://docs.docker.com/engine/logging/).\n" +"Use `docker logs ` para lê-la quando o driver de log do container suportar esse comando.\n" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "Without containers, the destination depends on how you start PHP and capture its output. For example, PHP-FPM discards worker output by default unless you enable `catch_workers_output`. See [web server logging configuration](../../cookbook/configuring-webservers/general.md#application-logs). To have Yii write application log files directly, configure a [file target](#logging-to-files)." +msgstr "Sem containers, o destino depende de como você inicia o PHP e captura a saída dele. Por exemplo, o PHP-FPM descarta a saída dos workers por padrão, a menos que você ative `catch_workers_output`. Veja a [configuração de logs do servidor web](../../cookbook/configuring-webservers/general.md#logs-da-aplicacao). Para o Yii escrever arquivos de log da aplicação diretamente, configure um [destino em arquivo](#logs-em-arquivos)." + +#. type: Title ## +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "Log Messages" +msgstr "Mensagens de log" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "To record log messages, you need an instance of PSR-3 logger. A class that writes log messages should receive it as a dependency:" +msgstr "Para registrar mensagens de log, você precisa de uma instância de um logger PSR-3. Uma classe que escreve mensagens de log deve recebê-lo como dependência:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "" +"class MyService\n" +"{\n" +" private $logger;\n" +" \n" +" public function __construct(\\Psr\\Log\\LoggerInterface $logger)\n" +" {\n" +" $this->logger = $logger; \n" +" }\n" +"}\n" +msgstr "" +"class MyService\n" +"{\n" +" private $logger;\n" +" \n" +" public function __construct(\\Psr\\Log\\LoggerInterface $logger)\n" +" {\n" +" $this->logger = $logger; \n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "Recording a log message is as simple as calling one of the following logging methods that correspond to log levels:" +msgstr "Registrar uma mensagem de log é tão simples quanto chamar um dos métodos a seguir, que correspondem aos níveis de log:" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/logging.md +msgid "`emergency` - System is unusable." +msgstr "`emergency` - O sistema está inutilizável." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/logging.md +msgid "`alert` - Action must be taken immediately. Example: Entire website down, database unavailable, etc. This should trigger the SMS alerts and wake you up." +msgstr "`alert` - É preciso agir imediatamente. Exemplo: site inteiro fora do ar, banco de dados indisponível etc. Isso deve disparar os alertas por SMS e acordar você." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/logging.md +msgid "`critical` - Critical conditions. Example: Application component unavailable, unexpected exception." +msgstr "`critical` - Condições críticas. Exemplo: componente da aplicação indisponível, exceção inesperada." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/logging.md +msgid "`error` - Runtime errors that don't require immediate action but should typically be logged and monitored." +msgstr "`error` - Erros em tempo de execução que não exigem ação imediata, mas normalmente devem ser registrados e monitorados." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/logging.md +msgid "`warning` - Exceptional occurrences that aren't errors. Example: Use of deprecated APIs, poor use of an API, undesirable things that aren't necessarily wrong." +msgstr "`warning` - Ocorrências excepcionais que não são erros. Exemplo: uso de APIs obsoletas, uso inadequado de uma API, coisas indesejáveis que não estão necessariamente erradas." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/logging.md +msgid "`notice` - Normal but significant events." +msgstr "`notice` - Eventos normais, mas significativos." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/logging.md +msgid "`info` - Interesting events. Example: User logs in, SQL logs." +msgstr "`info` - Eventos interessantes. Exemplo: login de usuário, logs de SQL." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/logging.md +msgid "`debug` - Detailed debug information." +msgstr "`debug` - Informações detalhadas de debug." + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "Each method has two arguments. The first is a message. The Second is a context array that typically has structured data that doesn't fit a message well but still does offer important information. In case you provide an exception as context, you should pass the \"exception\" key. Another special key is \"category.\" Categories are handy to better organize and filter log messages." +msgstr "Cada método tem dois argumentos. O primeiro é a mensagem. O segundo é um array de contexto, que normalmente tem dados estruturados que não cabem bem na mensagem, mas trazem informações importantes. Se você passar uma exceção no contexto, use a chave \"exception\". Outra chave especial é \"category\". As categorias ajudam a organizar e filtrar melhor as mensagens de log." + +#. type: Fenced code block (php) +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "" +"use \\Psr\\Log\\LoggerInterface;\n" +"\n" +"final readonly class MyService\n" +"{\n" +" public function __construct(\n" +" private LoggerInterface $logger\n" +" )\n" +" { \n" +" }\n" +"\n" +" public function serve(): void\n" +" {\n" +" $this->logger->info('MyService is serving', ['context' => __METHOD__]); \n" +" }\n" +"}\n" +msgstr "" +"use \\Psr\\Log\\LoggerInterface;\n" +"\n" +"final readonly class MyService\n" +"{\n" +" public function __construct(\n" +" private LoggerInterface $logger\n" +" )\n" +" { \n" +" }\n" +"\n" +" public function serve(): void\n" +" {\n" +" $this->logger->info('MyService is serving', ['context' => __METHOD__]); \n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "When deciding on a category for a message, you may choose a hierarchical naming scheme, which will make it easier for [log targets](#log-targets) to filter messages based on their categories. A simple yet effective naming scheme is to use the PHP magic constant `__METHOD__` for the category names. This is also the approach used in the core Yii framework code." +msgstr "Ao escolher a categoria de uma mensagem, você pode adotar um esquema de nomes hierárquico, o que facilita para os [destinos de log](#destinos-de-log) filtrarem as mensagens pela categoria. Um esquema simples e eficaz é usar a constante mágica do PHP `__METHOD__` como nome da categoria. Essa também é a abordagem usada no código do core do Yii." + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "The `__METHOD__` constant evaluates as the name of the method (prefixed with the fully qualified class name) where the constant appears. For example, it's equal to the string `'App\\\\Service\\\\MyService::serve'` if the above line of code is called within this method." +msgstr "A constante `__METHOD__` resulta no nome do método (prefixado com o nome completo da classe) onde ela aparece. Por exemplo, ela é igual à string `'App\\\\Service\\\\MyService::serve'` se a linha de código acima for chamada dentro desse método." + +#. type: Plain text +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "" +"> [!IMPORTANT]\n" +"> The logging methods described above are actually shortcuts to the [[\\Psr\\Log\\LoggerInterface::log()]].\n" +msgstr "" +"> [!IMPORTANT]\n" +"> Os métodos de log descritos acima são, na verdade, atalhos para [[\\Psr\\Log\\LoggerInterface::log()]].\n" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "Note that PSR-3 package provides `\\Psr\\Log\\NullLogger` class that provides the same set of methods but doesn't log anything. That means that you don't have to check if logger is configured with `if ($logger !== null)` and, instead, can assume that logger is always present." +msgstr "O pacote PSR-3 tem a classe `\\Psr\\Log\\NullLogger`, que oferece o mesmo conjunto de métodos, mas não registra nada. Isso significa que você não precisa verificar se o logger está configurado com `if ($logger !== null)` e pode assumir que o logger sempre existe." + +#. type: Title ## +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "Log targets" +msgstr "Destinos de log" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "A log target is an instance of a class that extends the [[\\Yiisoft\\Log\\Target]]. It filters the log messages by their severity levels and categories and then exports them to some medium. For example, a [[\\Yiisoft\\Log\\Target\\File\\FileTarget|file target]]exports the filtered log messages to a file, while a [[Yiisoft\\Log\\Target\\Email\\EmailTarget|email target]] exports the log messages to specified email addresses." +msgstr "Um destino de log é uma instância de uma classe que estende [[\\Yiisoft\\Log\\Target]]. Ele filtra as mensagens de log pelo nível de severidade e pela categoria e depois as exporta para algum meio. Por exemplo, um [[\\Yiisoft\\Log\\Target\\File\\FileTarget|destino em arquivo]] exporta as mensagens filtradas para um arquivo, enquanto um [[Yiisoft\\Log\\Target\\Email\\EmailTarget|destino por e-mail]] exporta as mensagens para os endereços de e-mail definidos." + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "You can register many log targets in an application by configuring them through the `\\Yiisoft\\Log\\Logger` constructor:" +msgstr "Você pode registrar vários destinos de log em uma aplicação configurando-os no construtor de `\\Yiisoft\\Log\\Logger`:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "" +"use \\Psr\\Log\\LogLevel;\n" +"\n" +"$fileTarget = new \\Yiisoft\\Log\\Target\\File\\FileTarget('/path/to/app.log');\n" +"$fileTarget->setLevels([LogLevel::ERROR, LogLevel::WARNING]);\n" +"\n" +"$emailTarget = new \\Yiisoft\\Log\\Target\\Email\\EmailTarget($mailer, ['to' => 'log@example.com']);\n" +"$emailTarget->setLevels([LogLevel::EMERGENCY, LogLevel::ALERT, LogLevel::CRITICAL]);\n" +"$emailTarget->setCategories(['Yiisoft\\Cache\\*']); \n" +"\n" +"$logger = new \\Yiisoft\\Log\\Logger([\n" +" $fileTarget,\n" +" $emailTarget\n" +"]);\n" +msgstr "" +"use \\Psr\\Log\\LogLevel;\n" +"\n" +"$fileTarget = new \\Yiisoft\\Log\\Target\\File\\FileTarget('/path/to/app.log');\n" +"$fileTarget->setLevels([LogLevel::ERROR, LogLevel::WARNING]);\n" +"\n" +"$emailTarget = new \\Yiisoft\\Log\\Target\\Email\\EmailTarget($mailer, ['to' => 'log@example.com']);\n" +"$emailTarget->setLevels([LogLevel::EMERGENCY, LogLevel::ALERT, LogLevel::CRITICAL]);\n" +"$emailTarget->setCategories(['Yiisoft\\Cache\\*']); \n" +"\n" +"$logger = new \\Yiisoft\\Log\\Logger([\n" +" $fileTarget,\n" +" $emailTarget\n" +"]);\n" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "In the above code, two log targets are registered:" +msgstr "No código acima, dois destinos de log são registrados:" + +#. type: Bullet: '* ' +#: ../src/guide/runtime/logging.md +msgid "the first target selects error and warning messages and writes them to `/path/to/app.log` file;" +msgstr "o primeiro seleciona as mensagens de erro e de warning e as grava no arquivo `/path/to/app.log`;" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "" +"* the second target selects emergency, alert, and critical messages under the categories whose names start with\n" +"`Yiisoft\\Cache\\`, and sends them in an email to both `admin@example.com` and `developer@example.com`.\n" +msgstr "" +"* o segundo seleciona as mensagens de emergency, alert e critical das categorias cujos nomes começam com\n" +"`Yiisoft\\Cache\\` e as envia por e-mail para `admin@example.com` e `developer@example.com`.\n" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "Yii comes with the following built-in log targets. Please refer to the API documentation about these classes to learn how to configure and use them." +msgstr "O Yii vem com os seguintes destinos de log embutidos. Consulte a documentação da API dessas classes para saber como configurá-los e usá-los." + +#. type: Bullet: '* ' +#: ../src/guide/runtime/logging.md +msgid "[[\\Yiisoft\\Log\\PsrTarget]]: passes log messages to another PSR-3 compatible logger." +msgstr "[[\\Yiisoft\\Log\\PsrTarget]]: repassa as mensagens de log para outro logger compatível com a PSR-3." + +#. type: Bullet: '* ' +#: ../src/guide/runtime/logging.md +msgid "[[\\Yiisoft\\Log\\StreamTarget]]: writes log messages into a specified output stream." +msgstr "[[\\Yiisoft\\Log\\StreamTarget]]: escreve as mensagens de log em um stream de saída definido." + +#. type: Bullet: '* ' +#: ../src/guide/runtime/logging.md +msgid "[[\\Yiisoft\\Log\\Target\\Db\\DbTarget]]: saves log messages in database." +msgstr "[[\\Yiisoft\\Log\\Target\\Db\\DbTarget]]: salva as mensagens de log no banco de dados." + +#. type: Bullet: '* ' +#: ../src/guide/runtime/logging.md +msgid "[[\\Yiisoft\\Log\\Target\\Email\\EmailTarget]]: sends log messages to pre-specified email addresses." +msgstr "[[\\Yiisoft\\Log\\Target\\Email\\EmailTarget]]: envia as mensagens de log para endereços de e-mail definidos." + +#. type: Bullet: '* ' +#: ../src/guide/runtime/logging.md +msgid "[[\\Yiisoft\\Log\\Target\\File\\FileTarget]]: saves log messages in files." +msgstr "[[\\Yiisoft\\Log\\Target\\File\\FileTarget]]: salva as mensagens de log em arquivos." + +#. type: Bullet: '* ' +#: ../src/guide/runtime/logging.md +msgid "[[\\Yiisoft\\Log\\Target\\Syslog\\SyslogTarget]]: saves log messages to syslog by calling the PHP function `syslog()`." +msgstr "[[\\Yiisoft\\Log\\Target\\Syslog\\SyslogTarget]]: salva as mensagens de log no syslog chamando a função PHP `syslog()`." + +#. type: Title ### +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "Logging to files" +msgstr "Logs em arquivos" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "To write application logs to a file, install the file target package:" +msgstr "Para gravar os logs da aplicação em um arquivo, instale o pacote do destino em arquivo:" + +#. type: Fenced code block (shell) +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "composer require yiisoft/log-target-file\n" +msgstr "composer require yiisoft/log-target-file\n" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "In your application's `config/common/di/logger.php`, replace the `StreamTarget` reference with `FileTarget`:" +msgstr "No `config/common/di/logger.php` da sua aplicação, troque a referência ao `StreamTarget` por `FileTarget`:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "" +"use Psr\\Log\\LoggerInterface;\n" +"use Yiisoft\\Definitions\\ReferencesArray;\n" +"use Yiisoft\\Log\\Logger;\n" +"use Yiisoft\\Log\\Target\\File\\FileTarget;\n" +"\n" +"return [\n" +" LoggerInterface::class => [\n" +" 'class' => Logger::class,\n" +" '__construct()' => [\n" +" 'targets' => ReferencesArray::from([\n" +" FileTarget::class,\n" +" ]),\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +"use Psr\\Log\\LoggerInterface;\n" +"use Yiisoft\\Definitions\\ReferencesArray;\n" +"use Yiisoft\\Log\\Logger;\n" +"use Yiisoft\\Log\\Target\\File\\FileTarget;\n" +"\n" +"return [\n" +" LoggerInterface::class => [\n" +" 'class' => Logger::class,\n" +" '__construct()' => [\n" +" 'targets' => ReferencesArray::from([\n" +" FileTarget::class,\n" +" ]),\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "The package's default configuration writes to `@runtime/logs/app.log` and enables log rotation. To change the path, set `$params['yiisoft/log-target-file']['fileTarget']['file']` in `config/common/params.php`. Ensure that the PHP process can write to the log directory, and keep it outside the web server's document root." +msgstr "A configuração padrão do pacote grava em `@runtime/logs/app.log` e ativa a rotação de logs. Para mudar o caminho, defina `$params['yiisoft/log-target-file']['fileTarget']['file']` em `config/common/params.php`. Garanta que o processo do PHP consiga escrever no diretório de logs e mantenha esse diretório fora do document root do servidor web." + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "The file target package's default configuration also filters out `alert`, `critical`, and `notice` messages. The templates' `StreamTarget` accepts all eight log levels. To keep that behavior, add the following entry to the array that `config/common/params.php` returns:" +msgstr "A configuração padrão do pacote de destino em arquivo também descarta as mensagens `alert`, `critical` e `notice`. O `StreamTarget` dos templates aceita os oito níveis de log. Para manter esse comportamento, adicione a seguinte entrada ao array retornado por `config/common/params.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "" +"use Psr\\Log\\LogLevel;\n" +"\n" +"return [\n" +" // Other application parameters...\n" +" 'yiisoft/log-target-file' => [\n" +" 'fileTarget' => [\n" +" 'levels' => [\n" +" LogLevel::EMERGENCY,\n" +" LogLevel::ALERT,\n" +" LogLevel::CRITICAL,\n" +" LogLevel::ERROR,\n" +" LogLevel::WARNING,\n" +" LogLevel::NOTICE,\n" +" LogLevel::INFO,\n" +" LogLevel::DEBUG,\n" +" ],\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +"use Psr\\Log\\LogLevel;\n" +"\n" +"return [\n" +" // Other application parameters...\n" +" 'yiisoft/log-target-file' => [\n" +" 'fileTarget' => [\n" +" 'levels' => [\n" +" LogLevel::EMERGENCY,\n" +" LogLevel::ALERT,\n" +" LogLevel::CRITICAL,\n" +" LogLevel::ERROR,\n" +" LogLevel::WARNING,\n" +" LogLevel::NOTICE,\n" +" LogLevel::INFO,\n" +" LogLevel::DEBUG,\n" +" ],\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "In the following, we will describe the features common to all log targets." +msgstr "A seguir, descrevemos os recursos comuns a todos os destinos de log." + +#. type: Title ### +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "Message Filtering" +msgstr "Filtragem de mensagens" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "For each log target, you can configure its levels and categories to specify which severity levels and categories of the messages the target should process." +msgstr "Para cada destino de log, você pode configurar os níveis e as categorias, definindo quais níveis de severidade e quais categorias de mensagens o destino deve processar." + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "The target `setLevels()` method takes an array consisting of one or several of `\\Psr\\Log\\LogLevel` constants." +msgstr "O método `setLevels()` do destino recebe um array com uma ou mais constantes de `\\Psr\\Log\\LogLevel`." + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "By default, the target will process messages of *any* severity level." +msgstr "Por padrão, o destino processa mensagens de *qualquer* nível de severidade." + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "The target `setCategories()` method takes an array consisting of message category names or patterns. A target will only process messages whose category can be found or match one of the patterns in this array. A category pattern is a category name prefix with an asterisk `*` at its end. A category name matches a category pattern if it starts with the same prefix of the pattern. For example, `Yiisoft\\Cache\\Cache::set` and `Yiisoft\\Cache\\Cache::get` both match the pattern `Yiisoft\\Cache\\*`." +msgstr "O método `setCategories()` do destino recebe um array com nomes ou padrões de categorias de mensagens. O destino só processa as mensagens cuja categoria esteja no array ou case com um dos padrões dele. Um padrão de categoria é um prefixo de nome de categoria com um asterisco `*` no final. Um nome de categoria casa com o padrão se começar com o mesmo prefixo. Por exemplo, `Yiisoft\\Cache\\Cache::set` e `Yiisoft\\Cache\\Cache::get` casam com o padrão `Yiisoft\\Cache\\*`." + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "By default, the target will process messages of *any* category." +msgstr "Por padrão, o destino processa mensagens de *qualquer* categoria." + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "Besides allowing the categories by the `setCategories()` method, you may also deny certain categories by the `setExcept()` method. If the category of a message is found or matches one of the patterns in this property, the target will NOT process it." +msgstr "Além de permitir categorias com o método `setCategories()`, você também pode negar certas categorias com o método `setExcept()`. Se a categoria de uma mensagem estiver nessa lista ou casar com um dos padrões dela, o destino NÃO vai processá-la." + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "The following target configuration specifies that the target should only process error and warning messages under the categories whose names match either `Yiisoft\\Cache\\*` or `App\\Exceptions\\HttpException:*`, but not `App\\Exceptions\\HttpException:404`." +msgstr "A configuração a seguir define que o destino só deve processar mensagens de erro e de warning das categorias cujos nomes casem com `Yiisoft\\Cache\\*` ou `App\\Exceptions\\HttpException:*`, mas não com `App\\Exceptions\\HttpException:404`." + +#. type: Fenced code block (php) +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "" +"$fileTarget = new \\Yiisoft\\Log\\Target\\File\\FileTarget('/path/to/app.log');\n" +"$fileTarget->setLevels([LogLevel::ERROR, LogLevel::WARNING]);\n" +"$fileTarget->setCategories(['Yiisoft\\Cache\\*', 'App\\Exceptions\\HttpException:*']);\n" +"$fileTarget->setExcept(['App\\Exceptions\\HttpException:404']);\n" +msgstr "" +"$fileTarget = new \\Yiisoft\\Log\\Target\\File\\FileTarget('/path/to/app.log');\n" +"$fileTarget->setLevels([LogLevel::ERROR, LogLevel::WARNING]);\n" +"$fileTarget->setCategories(['Yiisoft\\Cache\\*', 'App\\Exceptions\\HttpException:*']);\n" +"$fileTarget->setExcept(['App\\Exceptions\\HttpException:404']);\n" + +#. type: Title ### +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "Message Formatting" +msgstr "Formatação de mensagens" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "Log targets export the filtered log messages in a certain format. For example, if you install a log target of the class [[\\Yiisoft\\Log\\Target\\File\\FileTarget]], you may find a log message similar to the following in the log file:" +msgstr "Os destinos de log exportam as mensagens filtradas em um certo formato. Por exemplo, se você instalar um destino de log da classe [[\\Yiisoft\\Log\\Target\\File\\FileTarget]], pode encontrar no arquivo de log uma mensagem parecida com esta:" + +#. type: Fenced code block +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "" +"2020-12-05 09:27:52.223800 [info][application] Some message\n" +"\n" +"Message context:\n" +"\n" +"time: 1607160472.2238\n" +"memory: 4398536\n" +"category: 'application'\n" +msgstr "" +"2020-12-05 09:27:52.223800 [info][application] Some message\n" +"\n" +"Message context:\n" +"\n" +"time: 1607160472.2238\n" +"memory: 4398536\n" +"category: 'application'\n" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "By default, log messages have the following format:" +msgstr "Por padrão, as mensagens de log têm o seguinte formato:" + +#. type: Fenced code block +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "Timestamp Prefix[Level][Category] Message Context\n" +msgstr "Timestamp Prefix[Level][Category] Message Context\n" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "You may customize this format by calling [[\\Yiisoft\\Log\\Target::setFormat()|setFormat()]] method, which takes a PHP callable returning a custom-formatted message." +msgstr "Você pode personalizar esse formato chamando o método [[\\Yiisoft\\Log\\Target::setFormat()|setFormat()]], que recebe um callable PHP que retorna a mensagem formatada." + +#. type: Fenced code block (php) +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "" +"$fileTarget = new \\Yiisoft\\Log\\Target\\File\\FileTarget('/path/to/app.log');\n" +"\n" +"$fileTarget->setFormat(static function (\\Yiisoft\\Log\\Message $message) {\n" +" $category = strtoupper($message->context('category'));\n" +" return \"({$category}) [{$message->level()}] {$message->message()}\";\n" +"});\n" +"\n" +"$logger = new \\Yiisoft\\Log\\Logger([$fileTarget]);\n" +"$logger->info('Text message', ['category' => 'app']);\n" +"\n" +"// Result:\n" +"// (APP) [info] Text message\n" +msgstr "" +"$fileTarget = new \\Yiisoft\\Log\\Target\\File\\FileTarget('/path/to/app.log');\n" +"\n" +"$fileTarget->setFormat(static function (\\Yiisoft\\Log\\Message $message) {\n" +" $category = strtoupper($message->context('category'));\n" +" return \"({$category}) [{$message->level()}] {$message->message()}\";\n" +"});\n" +"\n" +"$logger = new \\Yiisoft\\Log\\Logger([$fileTarget]);\n" +"$logger->info('Text message', ['category' => 'app']);\n" +"\n" +"// Result:\n" +"// (APP) [info] Text message\n" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "In addition, if you're comfortable with the default message format but need to change the timestamp format or add custom data to the message, you can call the [[\\Yiisoft\\Log\\Target::setTimestampFormat()|setTimestampFormat()]] and [[\\Yiisoft\\Log\\Target::setPrefix()|setPrefix()]] methods. For example, the following code changes the timestamp format and configures a log target to prefix each log message with the current user ID (IP address and Session ID are removed for privacy reasons)." +msgstr "Além disso, se o formato padrão da mensagem servir para você, mas for preciso mudar o formato do timestamp ou adicionar dados à mensagem, você pode chamar os métodos [[\\Yiisoft\\Log\\Target::setTimestampFormat()|setTimestampFormat()]] e [[\\Yiisoft\\Log\\Target::setPrefix()|setPrefix()]]. Por exemplo, o código a seguir muda o formato do timestamp e configura um destino de log para prefixar cada mensagem com o ID do usuário atual (o endereço IP e o ID da sessão foram removidos por questões de privacidade)." + +#. type: Fenced code block (php) +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "" +"$fileTarget = new \\Yiisoft\\Log\\Target\\File\\FileTarget('/path/to/app.log');\n" +"$userId = '123e4567-e89b-12d3-a456-426655440000';\n" +"\n" +"// Default: 'Y-m-d H: i: s.u'\n" +"$fileTarget->setTimestampFormat('D d F Y');\n" +"// Default: ''\n" +"$fileTarget->setPrefix(static fn () => \"[{$userId}]\");\n" +"\n" +"$logger = new \\Yiisoft\\Log\\Logger([$fileTarget]);\n" +"$logger->info('Text', ['category' => 'user']);\n" +"\n" +"// Result:\n" +"// Fri 04 December 2020 [123e4567-e89b-12d3-a456-426655440000][info][user] Text\n" +"// Message context: ...\n" +"// Common context: ...\n" +msgstr "" +"$fileTarget = new \\Yiisoft\\Log\\Target\\File\\FileTarget('/path/to/app.log');\n" +"$userId = '123e4567-e89b-12d3-a456-426655440000';\n" +"\n" +"// Default: 'Y-m-d H: i: s.u'\n" +"$fileTarget->setTimestampFormat('D d F Y');\n" +"// Default: ''\n" +"$fileTarget->setPrefix(static fn () => \"[{$userId}]\");\n" +"\n" +"$logger = new \\Yiisoft\\Log\\Logger([$fileTarget]);\n" +"$logger->info('Text', ['category' => 'user']);\n" +"\n" +"// Result:\n" +"// Fri 04 December 2020 [123e4567-e89b-12d3-a456-426655440000][info][user] Text\n" +"// Message context: ...\n" +"// Common context: ...\n" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "The PHP callable that's passed to the [[\\Yiisoft\\Log\\Target::setFormat()|setFormat()]] and [[\\Yiisoft\\Log\\Target::setPrefix()|setPrefix()]] methods has the following signature:" +msgstr "O callable PHP passado para os métodos [[\\Yiisoft\\Log\\Target::setFormat()|setFormat()]] e [[\\Yiisoft\\Log\\Target::setPrefix()|setPrefix()]] tem a seguinte assinatura:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "function (\\Yiisoft\\Log\\Message $message, array $commonContext): string;\n" +msgstr "function (\\Yiisoft\\Log\\Message $message, array $commonContext): string;\n" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "" +"Besides message prefixes, log targets also append some common context information to each of the log messages.\n" +"You may adjust this behavior by calling target [[\\Yiisoft\\Log\\Target::setCommonContext()|setCommonContext()]]\n" +"method, passing an array of data in the `key => value` format that you want to include.\n" +"For example, the following log target configuration specifies that only the\n" +"value of the `$_SERVER` variable will be appended to the log messages.\n" +msgstr "" +"Além dos prefixos, os destinos de log também acrescentam algumas informações de contexto comuns a cada mensagem de log.\n" +"Você pode ajustar esse comportamento chamando o método [[\\Yiisoft\\Log\\Target::setCommonContext()|setCommonContext()]]\n" +"do destino, passando um array de dados no formato `key => value` com o que você quer incluir.\n" +"Por exemplo, a configuração de destino a seguir define que apenas o\n" +"valor da variável `$_SERVER` será acrescentado às mensagens de log.\n" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "" +"$fileTarget = new \\Yiisoft\\Log\\Target\\File\\FileTarget('/path/to/app.log');\n" +"$fileTarget->setCommonContext(['server' => $_SERVER]);\n" +msgstr "" +"$fileTarget = new \\Yiisoft\\Log\\Target\\File\\FileTarget('/path/to/app.log');\n" +"$fileTarget->setCommonContext(['server' => $_SERVER]);\n" + +#. type: Title ### +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "Message Trace Level" +msgstr "Nível de trace das mensagens" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "During development, it's often desirable to see where each log message is coming from. You can achieve this by calling the [[\\Yiisoft\\Log\\Logger::setTraceLevel()|setTraceLevel()]] method like the following:" +msgstr "Durante o desenvolvimento, muitas vezes é útil ver de onde vem cada mensagem de log. Você pode fazer isso chamando o método [[\\Yiisoft\\Log\\Logger::setTraceLevel()|setTraceLevel()]] assim:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "" +"$logger = new \\Yiisoft\\Log\\Logger($targets);\n" +"$logger->setTraceLevel(3);\n" +msgstr "" +"$logger = new \\Yiisoft\\Log\\Logger($targets);\n" +"$logger->setTraceLevel(3);\n" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "This application configuration sets the trace level to be 3, so each log message will be appended with at most three levels of the call stack at which the log message is recorded. You can also set a list of paths to exclude from the trace by calling the [[\\Yiisoft\\Log\\Logger::setExcludedTracePaths()|setExcludedTracePaths()]] method." +msgstr "Essa configuração define o nível de trace como 3, então cada mensagem de log recebe no máximo três níveis da pilha de chamadas do ponto em que a mensagem foi registrada. Você também pode definir uma lista de caminhos a excluir do trace chamando o método [[\\Yiisoft\\Log\\Logger::setExcludedTracePaths()|setExcludedTracePaths()]]." + +#. type: Fenced code block (php) +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "" +"$logger = new \\Yiisoft\\Log\\Logger($targets);\n" +"$logger->setExcludedTracePaths(['/path/to/file', '/path/to/folder']);\n" +msgstr "" +"$logger = new \\Yiisoft\\Log\\Logger($targets);\n" +"$logger->setExcludedTracePaths(['/path/to/file', '/path/to/folder']);\n" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "" +"> [!IMPORTANT]\n" +"> Getting call stack information isn't trivial. Therefore, you should only use this feature during development\n" +"or when debugging an application.\n" +msgstr "" +"> [!IMPORTANT]\n" +"> Obter informações da pilha de chamadas não é trivial. Por isso, use esse recurso apenas durante o desenvolvimento\n" +"ou ao depurar uma aplicação.\n" + +#. type: Title ### +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "Message flushing and exporting" +msgstr "Envio (flush) e exportação de mensagens" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "As aforementioned, log messages are maintained in an array by [[\\Yiisoft\\Log\\Logger|logger object]]. To limit the memory consumption by this array, the logger will flush the recorded messages to the [log targets](#log-targets) each time the array accumulates a certain number of log messages. You can customize this number by calling the [[\\Yiisoft\\Log\\Logger::setFlushInterval()]] method:" +msgstr "Como dito acima, as mensagens de log ficam em um array no [[\\Yiisoft\\Log\\Logger|objeto logger]]. Para limitar o consumo de memória desse array, o logger envia as mensagens registradas para os [destinos de log](#destinos-de-log) sempre que o array acumula um certo número de mensagens. Você pode personalizar esse número chamando o método [[\\Yiisoft\\Log\\Logger::setFlushInterval()]]:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "" +"$logger = new \\Yiisoft\\Log\\Logger($targets);\n" +"$logger->setFlushInterval(100); // default is 1000\n" +msgstr "" +"$logger = new \\Yiisoft\\Log\\Logger($targets);\n" +"$logger->setFlushInterval(100); // default is 1000\n" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "" +"> [!IMPORTANT]\n" +"> Message flushing also occurs when the application ends,\n" +"which ensures log targets can receive complete log messages.\n" +msgstr "" +"> [!IMPORTANT]\n" +"> O envio das mensagens também acontece quando a aplicação termina,\n" +"o que garante que os destinos de log recebam as mensagens completas.\n" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "" +"When the [[\\Yiisoft\\Log\\Logger|logger object]] flushes log messages to [log targets](#log-targets),\n" +"they don't get exported immediately. Instead, the message exporting only occurs when a log target\n" +" accumulates a certain number of the filtered messages. You can customize this number by calling the\n" +"[[\\Yiisoft\\Log\\Target::setExportInterval()|setExportInterval()]] method of individual\n" +"[log targets](#log-targets), like the following:\n" +msgstr "" +"Quando o [[\\Yiisoft\\Log\\Logger|objeto logger]] envia as mensagens para os [destinos de log](#destinos-de-log),\n" +"elas não são exportadas imediatamente. A exportação só acontece quando um destino de log\n" +" acumula um certo número de mensagens filtradas. Você pode personalizar esse número chamando o método\n" +"[[\\Yiisoft\\Log\\Target::setExportInterval()|setExportInterval()]] de cada\n" +"[destino de log](#destinos-de-log), assim:\n" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "" +"$fileTarget = new \\Yiisoft\\Log\\Target\\File\\FileTarget('/path/to/app.log');\n" +"$fileTarget->setExportInterval(100); // default is 1000\n" +msgstr "" +"$fileTarget = new \\Yiisoft\\Log\\Target\\File\\FileTarget('/path/to/app.log');\n" +"$fileTarget->setExportInterval(100); // default is 1000\n" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "Because of the flushing and exporting level setting, by default when you call any logging method, you will NOT see the log message immediately in the log targets. This could be a problem for some long-running console applications. To make each log message appear immediately in the log targets, you should set both flush interval and export interval to be 1, as shown below:" +msgstr "Por causa dessas configurações de envio e exportação, por padrão, quando você chama qualquer método de log, NÃO vai ver a mensagem imediatamente nos destinos de log. Isso pode ser um problema em aplicações de console de longa duração. Para que cada mensagem apareça imediatamente nos destinos de log, defina tanto o intervalo de envio quanto o de exportação como 1, como mostrado abaixo:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "" +"$fileTarget = new \\Yiisoft\\Log\\Target\\File\\FileTarget('/path/to/app.log');\n" +"$fileTarget->setExportInterval(1);\n" +"\n" +"$logger = new \\Yiisoft\\Log\\Logger([$fileTarget]);\n" +"$logger->setFlushInterval(1);\n" +msgstr "" +"$fileTarget = new \\Yiisoft\\Log\\Target\\File\\FileTarget('/path/to/app.log');\n" +"$fileTarget->setExportInterval(1);\n" +"\n" +"$logger = new \\Yiisoft\\Log\\Logger([$fileTarget]);\n" +"$logger->setFlushInterval(1);\n" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "" +"> [!NOTE]\n" +"> Frequent message flushing and exporting will degrade the performance of your application.\n" +msgstr "" +"> [!NOTE]\n" +"> Enviar e exportar mensagens com frequência piora o desempenho da sua aplicação.\n" + +#. type: Title ### +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "Toggling log targets" +msgstr "Ativando e desativando destinos de log" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "You can enable or disable a log target by calling its [[\\Yiisoft\\Log\\Target::enable()|enable()] ] and [[\\Yiisoft\\Log\\Target::disable()|disable()]] methods. You may do so via the log target configuration or by the following PHP statement in your code:" +msgstr "Você pode ativar ou desativar um destino de log chamando os métodos [[\\Yiisoft\\Log\\Target::enable()|enable()] ] e [[\\Yiisoft\\Log\\Target::disable()|disable()]]. Você pode fazer isso na configuração do destino de log ou com a seguinte instrução PHP no seu código:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "" +"$fileTarget = new \\Yiisoft\\Log\\Target\\File\\FileTarget('/path/to/app.log');\n" +"$logger = new \\Yiisoft\\Log\\Logger([$fileTarget, /*Other targets*/]);\n" +"\n" +"foreach ($logger->getTargets() as $target) {\n" +" if ($target instanceof \\Yiisoft\\Log\\Target\\File\\FileTarget) {\n" +" $target->disable();\n" +" }\n" +"}\n" +msgstr "" +"$fileTarget = new \\Yiisoft\\Log\\Target\\File\\FileTarget('/path/to/app.log');\n" +"$logger = new \\Yiisoft\\Log\\Logger([$fileTarget, /*Other targets*/]);\n" +"\n" +"foreach ($logger->getTargets() as $target) {\n" +" if ($target instanceof \\Yiisoft\\Log\\Target\\File\\FileTarget) {\n" +" $target->disable();\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "To check whether the log target is enabled, call the `isEnabled()` method. You also may pass callable to [[\\Yiisoft\\Log\\Target::setEnabled()|setEnabled()]] to define a dynamic condition for whether the log target should be enabled or not." +msgstr "Para verificar se o destino de log está ativado, chame o método `isEnabled()`. Você também pode passar um callable para [[\\Yiisoft\\Log\\Target::setEnabled()|setEnabled()]] para definir uma condição dinâmica que diz se o destino de log deve estar ativado ou não." + +#. type: Title ### +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "Creating new targets" +msgstr "Criando novos destinos" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "Creating a new log target class is straightforward. You mainly need to implement the [[\\Yii\\Log\\Target::export()]] abstract method that sends all accumulated log messages to a designated medium." +msgstr "Criar uma nova classe de destino de log é simples. Basicamente, você precisa implementar o método abstrato [[\\Yii\\Log\\Target::export()]], que envia todas as mensagens de log acumuladas para um meio definido." + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "The following protected methods will also be available for child targets:" +msgstr "Os seguintes métodos protegidos também ficam disponíveis para os destinos filhos:" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/logging.md +msgid "`getMessages` - Get a list of log messages ([[\\Yii\\Log\\Message]] instances)." +msgstr "`getMessages` - Retorna uma lista de mensagens de log (instâncias de [[\\Yii\\Log\\Message]])." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/logging.md +msgid "`getFormattedMessages` - Get a list of log messages formatted as strings." +msgstr "`getFormattedMessages` - Retorna uma lista de mensagens de log formatadas como strings." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/logging.md +msgid "`formatMessages` - Get all log messages formatted as a string." +msgstr "`formatMessages` - Retorna todas as mensagens de log formatadas como uma string." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/logging.md +msgid "`getCommonContext` - Get an array with common context data in the `key => value` format." +msgstr "`getCommonContext` - Retorna um array com os dados de contexto comuns no formato `key => value`." + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "For more details, you may refer to any of the log target classes included in the package." +msgstr "Para mais detalhes, consulte qualquer uma das classes de destino de log incluídas no pacote." + +#. type: Plain text +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "" +"> [!TIP]\n" +"> Instead of creating your own loggers, you may try any PSR-3 compatible logger such\n" +"as [Monolog](https://github.com/Seldaek/monolog) by using [[\\Yii\\Log\\PsrTarget]].\n" +msgstr "" +"> [!TIP]\n" +"> Em vez de criar os seus próprios loggers, você pode experimentar qualquer logger compatível com a PSR-3, como\n" +"o [Monolog](https://github.com/Seldaek/monolog), usando [[\\Yii\\Log\\PsrTarget]].\n" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "" +"/**\n" +" * @var \\Psr\\Log\\LoggerInterface $psrLogger\n" +" */\n" +"\n" +"$psrTarget = new \\Yiisoft\\Log\\PsrTarget($psrLogger);\n" +"$logger = new \\Yiisoft\\Log\\Logger([$psrTarget]);\n" +"\n" +"$logger->info('Text message');\n" +msgstr "" +"/**\n" +" * @var \\Psr\\Log\\LoggerInterface $psrLogger\n" +" */\n" +"\n" +"$psrTarget = new \\Yiisoft\\Log\\PsrTarget($psrLogger);\n" +"$logger = new \\Yiisoft\\Log\\Logger([$psrTarget]);\n" +"\n" +"$logger->info('Text message');\n" diff --git a/_translations/po/pt-BR/guide_runtime_request.md.po b/_translations/po/pt-BR/guide_runtime_request.md.po new file mode 100644 index 00000000..a11198c2 --- /dev/null +++ b/_translations/po/pt-BR/guide_runtime_request.md.po @@ -0,0 +1,714 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-06-02 21:36+0000\n" +"PO-Revision-Date: 2026-06-02 21:36+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/runtime/request.md +#, no-wrap +msgid "Request" +msgstr "Requisição" + +#. type: Plain text +#: ../src/guide/runtime/request.md +msgid "HTTP request has a method, URI, a set of headers and a body:" +msgstr "Uma requisição HTTP tem um método, uma URI, um conjunto de headers e um corpo:" + +#. type: Fenced code block +#: ../src/guide/runtime/request.md +#, no-wrap +msgid "" +"POST /contact HTTP/1.1\n" +"Host: example.org\n" +"Accept-Language: en-us\n" +"Accept-Encoding: gzip, deflate\n" +"\n" +"{\n" +" \"subject\": \"Hello\",\n" +" \"body\": \"Hello there, we need to build Yii application together!\"\n" +"}\n" +msgstr "" +"POST /contact HTTP/1.1\n" +"Host: example.org\n" +"Accept-Language: en-us\n" +"Accept-Encoding: gzip, deflate\n" +"\n" +"{\n" +" \"subject\": \"Hello\",\n" +" \"body\": \"Hello there, we need to build Yii application together!\"\n" +"}\n" + +#. type: Plain text +#: ../src/guide/runtime/request.md +msgid "The method is `POST`, URI is `/contact`. Extra headers are specifying host, preferred language and encoding. The body could be anything. In this case, it's a JSON payload." +msgstr "O método é `POST` e a URI é `/contact`. Os headers extras informam o host, o idioma preferido e a codificação. O corpo pode ser qualquer coisa. Neste caso, é um payload JSON." + +#. type: Plain text +#: ../src/guide/runtime/request.md +msgid "Yii uses [PSR-7 `ServerRequest`](https://www.php-fig.org/psr/psr-7/) as request representation. The object is available in controller actions and other types of middleware:" +msgstr "O Yii usa o [`ServerRequest` da PSR-7](https://www.php-fig.org/psr/psr-7/) para representar a requisição. O objeto está disponível nas actions de controllers e em outros tipos de middleware:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/request.md +#, no-wrap +msgid "" +"public function view(ServerRequestInterface $request): ResponseInterface\n" +"{\n" +" // ...\n" +"}\n" +msgstr "" +"public function view(ServerRequestInterface $request): ResponseInterface\n" +"{\n" +" // ...\n" +"}\n" + +#. type: Title ## +#: ../src/guide/runtime/request.md +#, no-wrap +msgid "Method" +msgstr "Método" + +#. type: Plain text +#: ../src/guide/runtime/request.md +msgid "The method could be obtained from a request object:" +msgstr "O método pode ser obtido do objeto de requisição:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/request.md +#, no-wrap +msgid "$method = $request->getMethod();\n" +msgstr "$method = $request->getMethod();\n" + +#. type: Plain text +#: ../src/guide/runtime/request.md +msgid "Usually it's one of the:" +msgstr "Normalmente ele é um destes:" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "GET" +msgstr "GET" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "POST" +msgstr "POST" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "PUT" +msgstr "PUT" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "DELETE" +msgstr "DELETE" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "HEAD" +msgstr "HEAD" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "PATCH" +msgstr "PATCH" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "OPTIONS" +msgstr "OPTIONS" + +#. type: Plain text +#: ../src/guide/runtime/request.md +msgid "In case you want to make sure the request method is of a certain type, there is a special class with method names:" +msgstr "Se você quiser garantir que o método da requisição é de um tipo específico, existe uma classe especial com os nomes dos métodos:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/request.md +#, no-wrap +msgid "" +"use Yiisoft\\Http\\Method;\n" +"\n" +"if ($request->getMethod() === Method::POST) {\n" +" // method is POST\n" +"}\n" +msgstr "" +"use Yiisoft\\Http\\Method;\n" +"\n" +"if ($request->getMethod() === Method::POST) {\n" +" // method is POST\n" +"}\n" + +#. type: Title ## +#: ../src/guide/runtime/request.md +#, no-wrap +msgid "URI" +msgstr "URI" + +#. type: Plain text +#: ../src/guide/runtime/request.md +msgid "A URI has:" +msgstr "Uma URI tem:" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "Scheme (`http`, `https`)" +msgstr "Esquema (`http`, `https`)" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "Host (`yiiframework.com`)" +msgstr "Host (`yiiframework.com`)" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "Port (`80`, `443`)" +msgstr "Porta (`80`, `443`)" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "Path (`/posts/1`)" +msgstr "Caminho (`/posts/1`)" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "Query string (`page=1&sort=+id`)" +msgstr "Query string (`page=1&sort=+id`)" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "Fragment (`#anchor`)" +msgstr "Fragmento (`#anchor`)" + +#. type: Plain text +#: ../src/guide/runtime/request.md +msgid "You can obtain `UriInterface` from request like the following:" +msgstr "Você pode obter a `UriInterface` da requisição assim:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/request.md +#, no-wrap +msgid "$uri = $request->getUri();\n" +msgstr "$uri = $request->getUri();\n" + +#. type: Plain text +#: ../src/guide/runtime/request.md +msgid "Then you can get various details from its methods:" +msgstr "Depois, pode obter vários detalhes pelos métodos dela:" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "`getScheme()`" +msgstr "`getScheme()`" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "`getAuthority()`" +msgstr "`getAuthority()`" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "`getUserInfo()`" +msgstr "`getUserInfo()`" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "`getHost()`" +msgstr "`getHost()`" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "`getPort()`" +msgstr "`getPort()`" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "`getPath()`" +msgstr "`getPath()`" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "`getQuery()`" +msgstr "`getQuery()`" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "`getFragment()`" +msgstr "`getFragment()`" + +#. type: Title ## +#: ../src/guide/runtime/request.md ../src/guide/runtime/response.md +#, no-wrap +msgid "Headers" +msgstr "Headers" + +#. type: Plain text +#: ../src/guide/runtime/request.md +msgid "There are various methods to inspect request headers. To get all headers as an array:" +msgstr "Há vários métodos para inspecionar os headers da requisição. Para obter todos os headers como array:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/request.md +#, no-wrap +msgid "" +"$headers = $request->getHeaders();\n" +"foreach ($headers as $name => $values) {\n" +" // ...\n" +"}\n" +msgstr "" +"$headers = $request->getHeaders();\n" +"foreach ($headers as $name => $values) {\n" +" // ...\n" +"}\n" + +#. type: Plain text +#: ../src/guide/runtime/request.md +msgid "To get a single header:" +msgstr "Para obter um único header:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/request.md +#, no-wrap +msgid "$values = $request->getHeader('Accept-Encoding');\n" +msgstr "$values = $request->getHeader('Accept-Encoding');\n" + +#. type: Plain text +#: ../src/guide/runtime/request.md +msgid "Also, you could get value as a comma-separated string instead of an array. That's especially handy if a header has a single value:" +msgstr "Você também pode obter o valor como uma string separada por vírgulas em vez de um array. Isso é bem prático quando o header tem um único valor:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/request.md +#, no-wrap +msgid "" +"if ($request->getHeaderLine('X-Requested-With') === 'XMLHttpRequest') {\n" +" // This is an AJAX request made with jQuery.\n" +" // Note that header presence and name may vary depending on the library used. \n" +"}\n" +msgstr "" +"if ($request->getHeaderLine('X-Requested-With') === 'XMLHttpRequest') {\n" +" // This is an AJAX request made with jQuery.\n" +" // Note that header presence and name may vary depending on the library used. \n" +"}\n" + +#. type: Plain text +#: ../src/guide/runtime/request.md +msgid "To check if a header is present in the request:" +msgstr "Para verificar se um header está presente na requisição:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/request.md +#, no-wrap +msgid "" +"if ($request->hasHeader('Accept-Encoding')) {\n" +" // ...\n" +"}\n" +msgstr "" +"if ($request->hasHeader('Accept-Encoding')) {\n" +" // ...\n" +"}\n" + +#. type: Title ## +#: ../src/guide/runtime/request.md ../src/guide/runtime/response.md ../src/internals/006-git-commit-messages.md +#, no-wrap +msgid "Body" +msgstr "Corpo" + +#. type: Plain text +#: ../src/guide/runtime/request.md +msgid "There are two methods to get body contents. The first is getting the body as it is without parsing:" +msgstr "Há dois métodos para obter o conteúdo do corpo. O primeiro retorna o corpo como está, sem parsing:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/request.md +#, no-wrap +msgid "$body = $request->getBody();\n" +msgstr "$body = $request->getBody();\n" + +#. type: Plain text +#: ../src/guide/runtime/request.md +msgid "The `$body` would be an instance of `Psr\\Http\\Message\\StreamInterface`." +msgstr "`$body` será uma instância de `Psr\\Http\\Message\\StreamInterface`." + +#. type: Plain text +#: ../src/guide/runtime/request.md +msgid "Also, you could get a parsed body:" +msgstr "Você também pode obter o corpo já interpretado:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/request.md +#, no-wrap +msgid "$bodyParameters = $request->getParsedBody();\n" +msgstr "$bodyParameters = $request->getParsedBody();\n" + +#. type: Plain text +#: ../src/guide/runtime/request.md +msgid "Parsing depends on PSR-7 implementation and may require middleware for custom body formats." +msgstr "O parsing depende da implementação da PSR-7 e pode exigir um middleware para formatos de corpo personalizados." + +#. type: Fenced code block (php) +#: ../src/guide/runtime/request.md +#, no-wrap +msgid "" +"getHeaderLine('Content-Type');\n" +"\n" +" if (strpos($contentType, 'application/json') !== false) {\n" +" $body = $request->getBody();\n" +" $parsedBody = $this->parse($body);\n" +" $request = $request->withParsedBody($parsedBody);\n" +" \n" +" }\n" +"\n" +" return $next->handle($request);\n" +" }\n" +"}\n" +msgstr "" +"getHeaderLine('Content-Type');\n" +"\n" +" if (strpos($contentType, 'application/json') !== false) {\n" +" $body = $request->getBody();\n" +" $parsedBody = $this->parse($body);\n" +" $request = $request->withParsedBody($parsedBody);\n" +" \n" +" }\n" +"\n" +" return $next->handle($request);\n" +" }\n" +"}\n" + +#. type: Title ## +#: ../src/guide/runtime/request.md +#, no-wrap +msgid "File uploads" +msgstr "Upload de arquivos" + +#. type: Plain text +#: ../src/guide/runtime/request.md +msgid "Uploaded files that user submitted from a form with `enctype` attribute equals to `multipart/form-data` are handled via special request method:" +msgstr "Os arquivos enviados pelo usuário em um formulário com o atributo `enctype` igual a `multipart/form-data` são tratados por um método especial da requisição:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/request.md +#, no-wrap +msgid "" +"$files = $request->getUploadedFiles();\n" +"foreach ($files as $file) {\n" +" if ($file->getError() === UPLOAD_ERR_OK) {\n" +" $file->moveTo('path/to/uploads/new_filename.ext');\n" +" }\n" +"}\n" +msgstr "" +"$files = $request->getUploadedFiles();\n" +"foreach ($files as $file) {\n" +" if ($file->getError() === UPLOAD_ERR_OK) {\n" +" $file->moveTo('path/to/uploads/new_filename.ext');\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/runtime/request.md +msgid "Always validate the upload before reading the stream or moving the file. The file may be missing, too large for PHP configuration, only partially uploaded, rejected by a PHP extension, or not match the file type and size your application expects. Yii Validator provides the `Yiisoft\\Validator\\Rule\\File` rule for this. It accepts PSR-7 `UploadedFileInterface` values and validates upload error codes, extension, MIME type, and size. Use `Yiisoft\\Validator\\Rule\\Each` when a field contains several files." +msgstr "Sempre valide o upload antes de ler o stream ou mover o arquivo. O arquivo pode estar ausente, ser grande demais para a configuração do PHP, ter sido enviado só em parte, ter sido rejeitado por uma extensão do PHP ou não corresponder ao tipo e ao tamanho que a sua aplicação espera. O Yii Validator oferece a regra `Yiisoft\\Validator\\Rule\\File` para isso. Ela aceita valores `UploadedFileInterface` da PSR-7 e valida os códigos de erro do upload, a extensão, o tipo MIME e o tamanho. Use `Yiisoft\\Validator\\Rule\\Each` quando um campo tiver vários arquivos." + +#. type: Plain text +#: ../src/guide/runtime/request.md +msgid "The following example handles a single `avatar` upload. It validates the uploaded file with Yii Validator, stores the file outside the public directory, and generates its own file name instead of trusting the client-provided name." +msgstr "O exemplo a seguir trata o upload de um único `avatar`. Ele valida o arquivo enviado com o Yii Validator, guarda o arquivo fora do diretório público e gera o próprio nome do arquivo em vez de confiar no nome informado pelo cliente." + +#. type: Fenced code block (php) +#: ../src/guide/runtime/request.md +#, no-wrap +msgid "" +"\n" +" */\n" +" private const EXTENSIONS = [\n" +" 'image/jpeg' => 'jpg',\n" +" 'image/png' => 'png',\n" +" 'image/webp' => 'webp',\n" +" ];\n" +"\n" +" public function __construct(\n" +" private Aliases $aliases,\n" +" private ResponseFactoryInterface $responseFactory,\n" +" ) {\n" +" }\n" +"\n" +" public function __invoke(ServerRequestInterface $request): ResponseInterface\n" +" {\n" +" $file = $request->getUploadedFiles()['avatar'] ?? null;\n" +"\n" +" $result = (new Validator())->validate(\n" +" ['avatar' => $file],\n" +" [\n" +" 'avatar' => [\n" +" new File(\n" +" extensions: ['jpg', 'jpeg', 'png', 'webp'],\n" +" mimeTypes: array_keys(self::EXTENSIONS),\n" +" maxSize: self::MAX_SIZE,\n" +" ),\n" +" new Image(skipOnError: true),\n" +" ],\n" +" ],\n" +" );\n" +"\n" +" if (!$result->isValid() || !$file instanceof UploadedFileInterface) {\n" +" $messages = $result->getPropertyErrorMessages('avatar');\n" +" return $this->badRequest(\n" +" $messages === [] ? 'Upload a file in the \"avatar\" field.' : implode(' ', $messages),\n" +" );\n" +" }\n" +"\n" +" $uploadDirectory = $this->aliases->get('@runtime/uploads/avatars');\n" +" $this->ensureDirectory($uploadDirectory);\n" +"\n" +" $temporaryPath = $uploadDirectory . DIRECTORY_SEPARATOR . bin2hex(random_bytes(16)) . '.upload';\n" +" $file->moveTo($temporaryPath);\n" +"\n" +" $mediaType = (new finfo(FILEINFO_MIME_TYPE))->file($temporaryPath);\n" +"\n" +" if (!is_string($mediaType) || !isset(self::EXTENSIONS[$mediaType])) {\n" +" unlink($temporaryPath);\n" +" return $this->badRequest('Only JPEG, PNG, and WebP images are allowed.');\n" +" }\n" +"\n" +" $fileName = bin2hex(random_bytes(16)) . '.' . self::EXTENSIONS[$mediaType];\n" +" $targetPath = $uploadDirectory . DIRECTORY_SEPARATOR . $fileName;\n" +"\n" +" if (!rename($temporaryPath, $targetPath)) {\n" +" unlink($temporaryPath);\n" +" throw new RuntimeException('Unable to store uploaded file.');\n" +" }\n" +"\n" +" $response = $this->responseFactory->createResponse(Status::CREATED);\n" +" $response->getBody()->write('Stored as ' . $fileName);\n" +"\n" +" return $response;\n" +" }\n" +"\n" +" private function badRequest(string $message): ResponseInterface\n" +" {\n" +" $response = $this->responseFactory->createResponse(Status::BAD_REQUEST);\n" +" $response->getBody()->write($message);\n" +"\n" +" return $response;\n" +" }\n" +"\n" +" private function ensureDirectory(string $directory): void\n" +" {\n" +" if (!is_dir($directory) && !mkdir($directory, 0775, true) && !is_dir($directory)) {\n" +" throw new RuntimeException(sprintf('Directory \"%s\" was not created.', $directory));\n" +" }\n" +" }\n" +"}\n" +msgstr "" +"\n" +" */\n" +" private const EXTENSIONS = [\n" +" 'image/jpeg' => 'jpg',\n" +" 'image/png' => 'png',\n" +" 'image/webp' => 'webp',\n" +" ];\n" +"\n" +" public function __construct(\n" +" private Aliases $aliases,\n" +" private ResponseFactoryInterface $responseFactory,\n" +" ) {\n" +" }\n" +"\n" +" public function __invoke(ServerRequestInterface $request): ResponseInterface\n" +" {\n" +" $file = $request->getUploadedFiles()['avatar'] ?? null;\n" +"\n" +" $result = (new Validator())->validate(\n" +" ['avatar' => $file],\n" +" [\n" +" 'avatar' => [\n" +" new File(\n" +" extensions: ['jpg', 'jpeg', 'png', 'webp'],\n" +" mimeTypes: array_keys(self::EXTENSIONS),\n" +" maxSize: self::MAX_SIZE,\n" +" ),\n" +" new Image(skipOnError: true),\n" +" ],\n" +" ],\n" +" );\n" +"\n" +" if (!$result->isValid() || !$file instanceof UploadedFileInterface) {\n" +" $messages = $result->getPropertyErrorMessages('avatar');\n" +" return $this->badRequest(\n" +" $messages === [] ? 'Upload a file in the \"avatar\" field.' : implode(' ', $messages),\n" +" );\n" +" }\n" +"\n" +" $uploadDirectory = $this->aliases->get('@runtime/uploads/avatars');\n" +" $this->ensureDirectory($uploadDirectory);\n" +"\n" +" $temporaryPath = $uploadDirectory . DIRECTORY_SEPARATOR . bin2hex(random_bytes(16)) . '.upload';\n" +" $file->moveTo($temporaryPath);\n" +"\n" +" $mediaType = (new finfo(FILEINFO_MIME_TYPE))->file($temporaryPath);\n" +"\n" +" if (!is_string($mediaType) || !isset(self::EXTENSIONS[$mediaType])) {\n" +" unlink($temporaryPath);\n" +" return $this->badRequest('Only JPEG, PNG, and WebP images are allowed.');\n" +" }\n" +"\n" +" $fileName = bin2hex(random_bytes(16)) . '.' . self::EXTENSIONS[$mediaType];\n" +" $targetPath = $uploadDirectory . DIRECTORY_SEPARATOR . $fileName;\n" +"\n" +" if (!rename($temporaryPath, $targetPath)) {\n" +" unlink($temporaryPath);\n" +" throw new RuntimeException('Unable to store uploaded file.');\n" +" }\n" +"\n" +" $response = $this->responseFactory->createResponse(Status::CREATED);\n" +" $response->getBody()->write('Stored as ' . $fileName);\n" +"\n" +" return $response;\n" +" }\n" +"\n" +" private function badRequest(string $message): ResponseInterface\n" +" {\n" +" $response = $this->responseFactory->createResponse(Status::BAD_REQUEST);\n" +" $response->getBody()->write($message);\n" +"\n" +" return $response;\n" +" }\n" +"\n" +" private function ensureDirectory(string $directory): void\n" +" {\n" +" if (!is_dir($directory) && !mkdir($directory, 0775, true) && !is_dir($directory)) {\n" +" throw new RuntimeException(sprintf('Directory \"%s\" was not created.', $directory));\n" +" }\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/runtime/request.md +msgid "Notes:" +msgstr "Observações:" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "Store uploads under `@runtime` or another non-public directory unless the files are intentionally public." +msgstr "Guarde os uploads em `@runtime` ou em outro diretório não público, a menos que os arquivos sejam públicos de propósito." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "Do not use `getClientFilename()` as a storage path. A browser controls it, so it may contain unsafe characters, path-like values, or duplicate names." +msgstr "Não use `getClientFilename()` como caminho de armazenamento. Quem controla esse valor é o navegador, então ele pode ter caracteres inseguros, valores que parecem caminhos ou nomes duplicados." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "Do not rely on `getClientMediaType()` alone. It comes from the client. Use `File` MIME type validation, `Image` for image validation and dimension checks, or another server-side parser appropriate for the file format." +msgstr "Não confie apenas em `getClientMediaType()`. Esse valor vem do cliente. Use a validação de tipo MIME da regra `File`, a regra `Image` para validar imagens e dimensões, ou outro parser no servidor adequado ao formato do arquivo." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "Check PHP limits such as `upload_max_filesize`, `post_max_size`, and `max_file_uploads` when expected files are rejected before the action runs." +msgstr "Verifique limites do PHP como `upload_max_filesize`, `post_max_size` e `max_file_uploads` quando arquivos esperados forem rejeitados antes de a action rodar." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "When a form uploads several files, the array returned by `getUploadedFiles()` has the same shape as the file input names. Validate them with `Each(new File(...))` and move each `UploadedFileInterface` separately." +msgstr "Quando um formulário envia vários arquivos, o array retornado por `getUploadedFiles()` tem o mesmo formato dos nomes dos inputs de arquivo. Valide-os com `Each(new File(...))` e mova cada `UploadedFileInterface` separadamente." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/request.md +msgid "`File` can also validate string file paths and `SplFileInfo` instances. Do not pass user-submitted paths directly: use PSR-7 uploaded file objects from the request, or perform upload provenance checks before validating filesystem paths." +msgstr "A regra `File` também valida caminhos de arquivo em string e instâncias de `SplFileInfo`. Não passe caminhos enviados pelo usuário diretamente: use os objetos de arquivo enviado da PSR-7 vindos da requisição, ou verifique a origem do upload antes de validar caminhos do sistema de arquivos." + +#. type: Title ## +#: ../src/guide/runtime/request.md +#, no-wrap +msgid "Attributes" +msgstr "Atributos" + +#. type: Plain text +#: ../src/guide/runtime/request.md +msgid "Application middleware may set custom request attributes using `withAttribute()` method. You can get these attributes with `getAttribute()`." +msgstr "Os middlewares da aplicação podem definir atributos personalizados na requisição com o método `withAttribute()`. Você pode ler esses atributos com `getAttribute()`." + +#. type: Plain text +#: ../src/guide/runtime/request.md +msgid "Route arguments, such as `id` from a `/posts/{id}` route pattern, aren't request attributes. Use `#[RouteArgument]` in an action parameter or inject `Yiisoft\\Router\\CurrentRoute` when you need route arguments or route metadata." +msgstr "Argumentos de rota, como o `id` de um padrão de rota `/posts/{id}`, não são atributos da requisição. Use `#[RouteArgument]` em um parâmetro da action ou injete `Yiisoft\\Router\\CurrentRoute` quando precisar de argumentos ou metadados da rota." diff --git a/_translations/po/pt-BR/guide_runtime_response.md.po b/_translations/po/pt-BR/guide_runtime_response.md.po new file mode 100644 index 00000000..1adbd321 --- /dev/null +++ b/_translations/po/pt-BR/guide_runtime_response.md.po @@ -0,0 +1,292 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-05-09 20:32+0000\n" +"PO-Revision-Date: 2026-05-09 20:32+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/guide/runtime/request.md ../src/guide/runtime/response.md +#, no-wrap +msgid "Headers" +msgstr "Headers" + +#. type: Title ## +#: ../src/guide/runtime/request.md ../src/guide/runtime/response.md ../src/internals/006-git-commit-messages.md +#, no-wrap +msgid "Body" +msgstr "Corpo" + +#. type: Title # +#: ../src/guide/runtime/response.md +#, no-wrap +msgid "Response" +msgstr "Resposta" + +#. type: Plain text +#: ../src/guide/runtime/response.md +msgid "HTTP response has status code and message, a set of headers and a body:" +msgstr "Uma resposta HTTP tem um código e uma mensagem de status, um conjunto de headers e um corpo:" + +#. type: Fenced code block +#: ../src/guide/runtime/response.md +#, no-wrap +msgid "" +"HTTP/1.1 200 OK\n" +"Date: Mon, 27 Jul 2009 12:28:53 GMT\n" +"Server: Apache/2.2.14 (Win32)\n" +"Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT\n" +"Content-Length: 6 \n" +"Content-Type: text/html\n" +"Connection: Closed\n" +"\n" +"Hello!\n" +msgstr "" +"HTTP/1.1 200 OK\n" +"Date: Mon, 27 Jul 2009 12:28:53 GMT\n" +"Server: Apache/2.2.14 (Win32)\n" +"Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT\n" +"Content-Length: 6 \n" +"Content-Type: text/html\n" +"Connection: Closed\n" +"\n" +"Hello!\n" + +#. type: Plain text +#: ../src/guide/runtime/response.md +msgid "Yii uses [PSR-7 `Response`](https://www.php-fig.org/psr/psr-7/) in the web application to represent response." +msgstr "O Yii usa o [`Response` da PSR-7](https://www.php-fig.org/psr/psr-7/) na aplicação web para representar a resposta." + +#. type: Plain text +#: ../src/guide/runtime/response.md +msgid "The object should be constructed and returned as a result of the execution of controller actions or other middleware. Usually, the middleware has a response factory injected into its constructor." +msgstr "O objeto deve ser criado e retornado como resultado da execução das actions de controllers ou de outros middlewares. Normalmente, o middleware recebe uma response factory injetada no construtor." + +#. type: Fenced code block (php) +#: ../src/guide/runtime/response.md +#, no-wrap +msgid "" +"use Psr\\Http\\Message\\ResponseFactoryInterface;\n" +"use Psr\\Http\\Message\\ResponseInterface;\n" +"use Psr\\Http\\Message\\ServerRequestInterface;\n" +"\n" +"final readonly class PostAction\n" +"{\n" +" public function __construct(\n" +" private ResponseFactoryInterface $responseFactory\n" +" )\n" +" {\n" +" }\n" +"\n" +" public function view(ServerRequestInterface $request): ResponseInterface\n" +" {\n" +" $response = $this->responseFactory->createResponse();\n" +" $response->getBody()->write('Hello!');\n" +" return $response;\n" +" }\n" +"}\n" +msgstr "" +"use Psr\\Http\\Message\\ResponseFactoryInterface;\n" +"use Psr\\Http\\Message\\ResponseInterface;\n" +"use Psr\\Http\\Message\\ServerRequestInterface;\n" +"\n" +"final readonly class PostAction\n" +"{\n" +" public function __construct(\n" +" private ResponseFactoryInterface $responseFactory\n" +" )\n" +" {\n" +" }\n" +"\n" +" public function view(ServerRequestInterface $request): ResponseInterface\n" +" {\n" +" $response = $this->responseFactory->createResponse();\n" +" $response->getBody()->write('Hello!');\n" +" return $response;\n" +" }\n" +"}\n" + +#. type: Title ## +#: ../src/guide/runtime/response.md +#, no-wrap +msgid "Status code" +msgstr "Código de status" + +#. type: Plain text +#: ../src/guide/runtime/response.md +msgid "You can set a status code like the following:" +msgstr "Você pode definir o código de status assim:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/response.md +#, no-wrap +msgid "" +"use Yiisoft\\Http\\Status;\n" +"\n" +"$response = $response->withStatus(Status::NOT_FOUND);\n" +msgstr "" +"use Yiisoft\\Http\\Status;\n" +"\n" +"$response = $response->withStatus(Status::NOT_FOUND);\n" + +#. type: Plain text +#: ../src/guide/runtime/response.md +msgid "Majority of status codes are available from `Status` class for convenience and readability." +msgstr "A maioria dos códigos de status está disponível na classe `Status`, por conveniência e legibilidade." + +#. type: Plain text +#: ../src/guide/runtime/response.md +msgid "Router may return a response before an action runs. For example, an `OPTIONS` request to a known route path gets an automatic `204 No Content` response with an `Allow` header that lists supported methods. See [Automatic OPTIONS responses](routing.md#automatic-options-responses) for routing details." +msgstr "O router pode retornar uma resposta antes de a action rodar. Por exemplo, uma requisição `OPTIONS` para o caminho de uma rota conhecida recebe automaticamente uma resposta `204 No Content` com um header `Allow` listando os métodos suportados. Veja [Respostas OPTIONS automáticas](routing.md#respostas-options-automaticas) para os detalhes de roteamento." + +#. type: Plain text +#: ../src/guide/runtime/response.md +msgid "You can set headers like this:" +msgstr "Você pode definir headers assim:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/response.md +#, no-wrap +msgid "$response = $response->withHeader('Content-type', 'application/json');\n" +msgstr "$response = $response->withHeader('Content-type', 'application/json');\n" + +#. type: Plain text +#: ../src/guide/runtime/response.md +msgid "If there is a need to append a header value to the existing header:" +msgstr "Se for preciso acrescentar um valor a um header existente:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/response.md +#, no-wrap +msgid "$response = $response->withAddedHeader('Set-Cookie', 'qwerty=219ffwef9w0f; Domain=somecompany.co.uk; Path=/; Expires=Wed, 30 Aug 2019 00:00:00 GMT');\n" +msgstr "$response = $response->withAddedHeader('Set-Cookie', 'qwerty=219ffwef9w0f; Domain=somecompany.co.uk; Path=/; Expires=Wed, 30 Aug 2019 00:00:00 GMT');\n" + +#. type: Plain text +#: ../src/guide/runtime/response.md +msgid "And, if needed, headers could be removed:" +msgstr "E, se necessário, os headers podem ser removidos:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/response.md +#, no-wrap +msgid "$response = $response->withoutHeader('Set-Cookie');\n" +msgstr "$response = $response->withoutHeader('Set-Cookie');\n" + +#. type: Plain text +#: ../src/guide/runtime/response.md +msgid "Response body is an object implementing `Psr\\Http\\Message\\StreamInterface`." +msgstr "O corpo da resposta é um objeto que implementa `Psr\\Http\\Message\\StreamInterface`." + +#. type: Plain text +#: ../src/guide/runtime/response.md +msgid "You can write to it via the interface itself:" +msgstr "Você pode escrever nele pela própria interface:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/response.md +#, no-wrap +msgid "" +"$body = $response->getBody();\n" +"$body->write('Hello');\n" +msgstr "" +"$body = $response->getBody();\n" +"$body->write('Hello');\n" + +#. type: Title ## +#: ../src/guide/runtime/response.md +#, no-wrap +msgid "Examples" +msgstr "Exemplos" + +#. type: Title ### +#: ../src/guide/runtime/response.md +#, no-wrap +msgid "Redirecting" +msgstr "Redirecionando" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/response.md +#, no-wrap +msgid "" +"use Yiisoft\\Http\\Status;\n" +"\n" +"return $response\n" +" ->withStatus(Status::PERMANENT_REDIRECT)\n" +" ->withHeader('Location', 'https://www.example.com'); \n" +msgstr "" +"use Yiisoft\\Http\\Status;\n" +"\n" +"return $response\n" +" ->withStatus(Status::PERMANENT_REDIRECT)\n" +" ->withHeader('Location', 'https://www.example.com'); \n" + +#. type: Plain text +#: ../src/guide/runtime/response.md +msgid "Note that there are different statuses used for redirection:" +msgstr "Existem status diferentes usados para redirecionamento:" + +#. type: Plain text +#: ../src/guide/runtime/response.md +#, no-wrap +msgid "" +"| Code | Usage | What is it for |\n" +"|------|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n" +"| 301 | `Status::MOVED_PERMANENTLY` | Permanently changed a URL structure. Search engines update their indexes, and browsers cache it. |\n" +"| 308 | `Status::PERMANENT_REDIRECT` | Like 301, but guarantees the HTTP method won't change. |\n" +"| 302 | `Status::FOUND` | Temporary changes like maintenance pages. Original URL should still be used for future requests. Search engines typically don't update their indexes. |\n" +"| 307 | `Status::TEMPORARY_REDIRECT` | Like 302, but guarantees the HTTP method won't change. |\n" +"| 303 | `Status::SEE_OTHER` | After form submissions to prevent duplicate submissions if the user refreshes. Explicitly tells to use `GET` for the redirect, even if the original request was `POST`. |\n" +msgstr "" +"| Código | Constante | Para que serve |\n" +"|--------|------------------------------|----------------|\n" +"| 301 | `Status::MOVED_PERMANENTLY` | Mudança permanente na estrutura de URLs. Os mecanismos de busca atualizam os índices e os navegadores guardam em cache. |\n" +"| 308 | `Status::PERMANENT_REDIRECT` | Como o 301, mas garante que o método HTTP não muda. |\n" +"| 302 | `Status::FOUND` | Mudanças temporárias, como páginas de manutenção. A URL original ainda deve ser usada nas próximas requisições. Os mecanismos de busca normalmente não atualizam os índices. |\n" +"| 307 | `Status::TEMPORARY_REDIRECT` | Como o 302, mas garante que o método HTTP não muda. |\n" +"| 303 | `Status::SEE_OTHER` | Depois do envio de formulários, para evitar envios duplicados se o usuário recarregar a página. Indica explicitamente que o redirecionamento deve usar `GET`, mesmo que a requisição original tenha sido `POST`. |\n" + +#. type: Title ### +#: ../src/guide/runtime/response.md +#, no-wrap +msgid "Responding with JSON" +msgstr "Respondendo com JSON" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/response.md +#, no-wrap +msgid "" +"use Yiisoft\\Http\\Status;\n" +"use Yiisoft\\Json\\Json;\n" +"\n" +"$data = [\n" +" 'account' => 'samdark',\n" +" 'value' => 42\n" +"];\n" +"\n" +"$response->getBody()->write(Json::encode($data));\n" +"return $response\n" +" ->withStatus(Status::OK)\n" +" ->withHeader('Content-Type', 'application/json');\n" +msgstr "" +"use Yiisoft\\Http\\Status;\n" +"use Yiisoft\\Json\\Json;\n" +"\n" +"$data = [\n" +" 'account' => 'samdark',\n" +" 'value' => 42\n" +"];\n" +"\n" +"$response->getBody()->write(Json::encode($data));\n" +"return $response\n" +" ->withStatus(Status::OK)\n" +" ->withHeader('Content-Type', 'application/json');\n" diff --git a/_translations/po/pt-BR/guide_runtime_routing.md.po b/_translations/po/pt-BR/guide_runtime_routing.md.po new file mode 100644 index 00000000..a0bee429 --- /dev/null +++ b/_translations/po/pt-BR/guide_runtime_routing.md.po @@ -0,0 +1,1145 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-06-05 20:33+0000\n" +"PO-Revision-Date: 2026-06-05 20:33+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "Routing and URL generation" +msgstr "Roteamento e geração de URLs" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "Usually, a Yii application processes certain requests with certain handlers. It selects a handler based on the request URL. The part of the application that does the job is a router, and the process of selecting a handler, instantiating it and running a handler method is *routing*." +msgstr "Normalmente, uma aplicação Yii processa certas requisições com certos handlers. Ela escolhe o handler com base na URL da requisição. A parte da aplicação que faz esse trabalho é o router, e o processo de escolher um handler, instanciá-lo e executar um método dele é o *roteamento*." + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "The reverse process of routing is *URL generation*, which creates a URL from a given named route, route arguments, and query parameters. When you later request the created URL, the routing process can resolve it back into the original route arguments and query parameters." +msgstr "O processo inverso do roteamento é a *geração de URLs*, que cria uma URL a partir de uma rota nomeada, de argumentos de rota e de parâmetros de query. Quando você requisita depois a URL criada, o roteamento consegue convertê-la de volta nos argumentos de rota e parâmetros de query originais." + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "Routing and URL generation are separate services, but they use a common set of routes for both URL matching and URL generation." +msgstr "Roteamento e geração de URLs são serviços separados, mas usam o mesmo conjunto de rotas tanto para casar URLs quanto para gerá-las." + +#. type: Title ## +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "Configuring routes" +msgstr "Configurando rotas" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "By configuring routes, you can let your application recognize arbitrary URL formats without modifying your existing application code. You can configure routes in `/config/routes.php`. The structure of the file is the following:" +msgstr "Configurando rotas, você faz a aplicação reconhecer formatos arbitrários de URL sem modificar o código existente. Você pode configurar as rotas em `/config/routes.php`. A estrutura do arquivo é a seguinte:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "" +"action([SiteController::class, 'index'])\n" +" ->name('site/index')\n" +"];\n" +msgstr "" +"action([SiteController::class, 'index'])\n" +" ->name('site/index')\n" +"];\n" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "The file returns an array of routes. When defining a route, you start with a method corresponding to a certain HTTP request type:" +msgstr "O arquivo retorna um array de rotas. Ao definir uma rota, você começa com um método que corresponde a um tipo de requisição HTTP:" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/routing.md +msgid "get" +msgstr "get" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/routing.md +msgid "post" +msgstr "post" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/routing.md +msgid "put" +msgstr "put" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/routing.md +msgid "delete" +msgstr "delete" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/routing.md +msgid "patch" +msgstr "patch" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/routing.md +msgid "head" +msgstr "head" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/routing.md +msgid "options" +msgstr "options" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "If you need many methods, you can use `methods()`:" +msgstr "Se você precisar de vários métodos, pode usar `methods()`:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "" +"action([SiteController::class, 'user'])\n" +" ->name('site/user')\n" +"];\n" +msgstr "" +"action([SiteController::class, 'user'])\n" +" ->name('site/user')\n" +"];\n" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "All these methods accept a route pattern. The route pattern defines how the router matches the URL when routing and how it generates URL based on route name and parameters. You will learn about the actual syntax later in this guide. Specify a handler with `action()` as:" +msgstr "Todos esses métodos aceitam um padrão de rota. O padrão de rota define como o router casa a URL durante o roteamento e como gera a URL a partir do nome da rota e dos parâmetros. Você vai conhecer a sintaxe mais adiante neste guia. Defina o handler com `action()` como:" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/routing.md +msgid "[Middleware](../structure/middleware.md) class name." +msgstr "Nome de uma classe de [middleware](../structure/middleware.md)." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/routing.md +msgid "Handler action (an array of [HandlerClass, handlerMethod])." +msgstr "Uma action de handler (um array no formato [HandlerClass, handlerMethod])." + +#. type: Bullet: '- ' +#: ../src/guide/runtime/routing.md +msgid "A callable." +msgstr "Um callable." + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "In case of a handler action, a class of type `HandlerClass` is instantiated and its `handlerMethod` is called:" +msgstr "No caso de uma action de handler, uma classe do tipo `HandlerClass` é instanciada e o seu método `handlerMethod` é chamado:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "" +"use Psr\\Http\\Message\\ServerRequestInterface;\n" +"use Psr\\Http\\Message\\ResponseInterface;\n" +"\n" +"final readonly class HandlerClass\n" +"{\n" +" public function handle(ServerRequestInterface $request): ResponseInterface\n" +" {\n" +" // ...\n" +" }\n" +"}\n" +msgstr "" +"use Psr\\Http\\Message\\ServerRequestInterface;\n" +"use Psr\\Http\\Message\\ResponseInterface;\n" +"\n" +"final readonly class HandlerClass\n" +"{\n" +" public function handle(ServerRequestInterface $request): ResponseInterface\n" +" {\n" +" // ...\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "The callable is called as is:" +msgstr "O callable é chamado como está:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "" +"static function (ServerRequestInterface $request, RequestHandlerInterface $next) use ($responseFactory) {\n" +" $response = $responseFactory->createResponse();\n" +" $response->getBody()->write('You are at homepage.');\n" +" return $response;\n" +"}\n" +msgstr "" +"static function (ServerRequestInterface $request, RequestHandlerInterface $next) use ($responseFactory) {\n" +" $response = $responseFactory->createResponse();\n" +" $response->getBody()->write('You are at homepage.');\n" +" return $response;\n" +"}\n" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "For handler action and callable typed parameters are automatically injected using the dependency injection container passed to the route." +msgstr "Para actions de handler e callables, os parâmetros tipados são injetados automaticamente pelo container de injeção de dependência passado para a rota." + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "Get current request and handler by type-hinting for `ServerRequestInterface` and `RequestHandlerInterface`." +msgstr "Obtenha a requisição e o handler atuais usando os type hints `ServerRequestInterface` e `RequestHandlerInterface`." + +#. type: Title ### +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "Route arguments in actions" +msgstr "Argumentos de rota nas actions" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "Named route parameters are stored in `CurrentRoute`. To pass a route parameter to an action method parameter, use the `RouteArgument` attribute:" +msgstr "Os parâmetros nomeados da rota ficam guardados em `CurrentRoute`. Para passar um parâmetro de rota para um parâmetro do método da action, use o atributo `RouteArgument`:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "" +"action([PostController::class, 'view'])\n" +" ->name('post/view')\n" +"];\n" +"\n" +"final readonly class PostController\n" +"{\n" +" public function view(#[RouteArgument('id')] int $id): ResponseInterface\n" +" {\n" +" // $id contains the value from the {id} route parameter.\n" +" }\n" +"}\n" +msgstr "" +"action([PostController::class, 'view'])\n" +" ->name('post/view')\n" +"];\n" +"\n" +"final readonly class PostController\n" +"{\n" +" public function view(#[RouteArgument('id')] int $id): ResponseInterface\n" +" {\n" +" // $id contains the value from the {id} route parameter.\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "If a parameter has the same name as the action parameter, you can omit the attribute name:" +msgstr "Se o parâmetro tiver o mesmo nome do parâmetro da action, você pode omitir o nome no atributo:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "" +"public function view(#[RouteArgument] int $id): ResponseInterface\n" +"{\n" +" // ...\n" +"}\n" +msgstr "" +"public function view(#[RouteArgument] int $id): ResponseInterface\n" +"{\n" +" // ...\n" +"}\n" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "You can also inject `CurrentRoute` into an action or a service when you need several arguments or route metadata:" +msgstr "Você também pode injetar `CurrentRoute` em uma action ou em um serviço quando precisar de vários argumentos ou de metadados da rota:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "" +"getArgument('id');\n" +" $routeName = $currentRoute->getName();\n" +"\n" +" // ...\n" +" }\n" +"}\n" +msgstr "" +"getArgument('id');\n" +" $routeName = $currentRoute->getName();\n" +"\n" +" // ...\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "Route arguments aren't request attributes. Read them from `CurrentRoute` or action parameters marked with `RouteArgument`." +msgstr "Argumentos de rota não são atributos da requisição. Leia-os de `CurrentRoute` ou de parâmetros da action marcados com `RouteArgument`." + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "For optional route parameters, provide a default value either in the route with `defaults()` or in the action method signature." +msgstr "Para parâmetros de rota opcionais, informe um valor padrão na rota com `defaults()` ou na assinatura do método da action." + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "You could add extra handlers to wrap primary one with `middleware()` method:" +msgstr "Você pode adicionar handlers extras em volta do principal com o método `middleware()`:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "" +"action([DownloadController::class, 'download'])\n" +" ->name('download/id')\n" +" ->middleware(LimitDownloadRate::class)\n" +"];\n" +msgstr "" +"action([DownloadController::class, 'download'])\n" +" ->name('download/id')\n" +" ->middleware(LimitDownloadRate::class)\n" +"];\n" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "Check [\"the middleware\"](../structure/middleware.md) guide to learn more about how to implement middleware." +msgstr "Veja o guia sobre [\"middleware\"](../structure/middleware.md) para saber mais sobre como implementar middlewares." + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "This is especially useful when grouping routes:" +msgstr "Isso é especialmente útil ao agrupar rotas:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "" +"middleware(ApiDataWrapper::class)\n" +" ->routes(\n" +" Route::get('/info/v2')\n" +" ->action(ApiInfo::class)\n" +" ->name('api/info/v2')\n" +" ->middleware(JsonDataResponseMiddleware::class),\n" +" Route::get('/user')\n" +" ->action([ApiUserController::class, 'index'])\n" +" ->name('api/user/index'),\n" +" Route::get('/user/{login}')\n" +" ->action([ApiUserController::class, 'profile'])\n" +" ->middleware(JsonDataResponseMiddleware::class)\n" +" ->name('api/user/profile'),\n" +" )\n" +"];\n" +msgstr "" +"middleware(ApiDataWrapper::class)\n" +" ->routes(\n" +" Route::get('/info/v2')\n" +" ->action(ApiInfo::class)\n" +" ->name('api/info/v2')\n" +" ->middleware(JsonDataResponseMiddleware::class),\n" +" Route::get('/user')\n" +" ->action([ApiUserController::class, 'index'])\n" +" ->name('api/user/index'),\n" +" Route::get('/user/{login}')\n" +" ->action([ApiUserController::class, 'profile'])\n" +" ->middleware(JsonDataResponseMiddleware::class)\n" +" ->name('api/user/profile'),\n" +" )\n" +"];\n" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "Router executes `ApiDataWrapper` before handling any URL starting with `/api`." +msgstr "O router executa `ApiDataWrapper` antes de tratar qualquer URL que comece com `/api`." + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "You could name a route with a `name()` method. It's a good idea to choose a route name based on the handler's name." +msgstr "Você pode dar um nome a uma rota com o método `name()`. É uma boa ideia escolher o nome da rota com base no nome do handler." + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "You can set a default value for a route parameter. For example:" +msgstr "Você pode definir um valor padrão para um parâmetro de rota. Por exemplo:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "" +"action([SiteController::class, 'user'])\n" +" ->name('site/user')\n" +" ->defaults(['id' => '42'])\n" +"];\n" +msgstr "" +"action([SiteController::class, 'user'])\n" +" ->name('site/user')\n" +" ->defaults(['id' => '42'])\n" +"];\n" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "This configuration would result in a match with both `/user` and `/user/123`. In both cases `CurrentRoute` service will contain `id` argument filled. In the first case it will be default `42` and in the second case it will be `123`." +msgstr "Essa configuração casa tanto com `/user` quanto com `/user/123`. Nos dois casos, o serviço `CurrentRoute` vai ter o argumento `id` preenchido. No primeiro caso, ele será o padrão `42` e, no segundo, `123`." + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "In cause URL should be valid for a single host, you can specify it with `host()`." +msgstr "Se a URL só deve valer para um host, você pode defini-lo com `host()`." + +#. type: Title ### +#: ../src/guide/runtime/routing.md ../src/guide/start/databases.md +#, no-wrap +msgid "Routing" +msgstr "Roteamento" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "Yii routing is flexible, and internally it may use different routing implementations. The actual matching algorithm may vary, but the basic idea stays the same." +msgstr "O roteamento do Yii é flexível e, internamente, pode usar diferentes implementações. O algoritmo de casamento pode variar, mas a ideia básica é a mesma." + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "Router matches routes defined in config from top to bottom. If there is a match, further matching isn't performed and the router executes the route handler to get the response. If there is no match at all, router passes handling to the next middleware in the [application middleware set](../structure/middleware.md)." +msgstr "O router casa as rotas definidas na configuração de cima para baixo. Se houver um casamento, ele para de procurar e executa o handler da rota para obter a resposta. Se nenhuma rota casar, o router passa o tratamento para o próximo middleware do [conjunto de middlewares da aplicação](../structure/middleware.md)." + +#. type: Title ### +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "Automatic OPTIONS responses" +msgstr "Respostas OPTIONS automáticas" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "When the request path matches a route but the HTTP method doesn't, router returns a `405 Method Not Allowed` response with an `Allow` header:" +msgstr "Quando o caminho da requisição casa com uma rota, mas o método HTTP não, o router retorna uma resposta `405 Method Not Allowed` com o header `Allow`:" + +#. type: Fenced code block (http) +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "" +"HTTP/1.1 405 Method Not Allowed\n" +"Allow: GET\n" +msgstr "" +"HTTP/1.1 405 Method Not Allowed\n" +"Allow: GET\n" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "For an `OPTIONS` request to the same path, router returns an empty `204 No Content` response with the same `Allow` header:" +msgstr "Para uma requisição `OPTIONS` no mesmo caminho, o router retorna uma resposta vazia `204 No Content` com o mesmo header `Allow`:" + +#. type: Fenced code block (http) +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "" +"HTTP/1.1 204 No Content\n" +"Allow: GET\n" +msgstr "" +"HTTP/1.1 204 No Content\n" +"Allow: GET\n" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "This response is generated from the configured routes before the route action runs. If an API endpoint needs CORS headers, attach CORS middleware to a route group:" +msgstr "Essa resposta é gerada a partir das rotas configuradas, antes de a action da rota ser executada. Se um endpoint de API precisar de headers CORS, adicione um middleware de CORS a um grupo de rotas:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "" +"withCors(CorsMiddleware::class)\n" +" ->routes(\n" +" Route::methods([Method::GET, Method::POST], '/posts')\n" +" ->action([PostController::class, 'index'])\n" +" ->name('api/posts')\n" +" )\n" +"];\n" +msgstr "" +"withCors(CorsMiddleware::class)\n" +" ->routes(\n" +" Route::methods([Method::GET, Method::POST], '/posts')\n" +" ->action([PostController::class, 'index'])\n" +" ->name('api/posts')\n" +" )\n" +"];\n" + +#. type: Title ## +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "Generating URLs" +msgstr "Gerando URLs" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "To generate URL based on a route, a route should have a name:" +msgstr "Para gerar uma URL a partir de uma rota, a rota precisa ter um nome:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "" +"action([TestController::class, 'index'])\n" +" ->name('test/index'),\n" +" Route::post('/test/submit/{id}')\n" +" ->action([TestController::class, 'submit'])\n" +" ->name('test/submit')\n" +"];\n" +msgstr "" +"action([TestController::class, 'index'])\n" +" ->name('test/index'),\n" +" Route::post('/test/submit/{id}')\n" +" ->action([TestController::class, 'submit'])\n" +" ->name('test/submit')\n" +"];\n" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "The generation looks like the following:" +msgstr "A geração fica assim:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "" +"generate('test/submit', ['id' => '42']);\n" +" // ...\n" +" }\n" +"}\n" +msgstr "" +"generate('test/submit', ['id' => '42']);\n" +" // ...\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "In the above code, we get a generator instance with the help of [automatic dependency injection](../concept/di-container.md) that works with action handlers. In another service, you can get the instance with similar constructor injection. In views URL generator is available as `$url`." +msgstr "No código acima, obtemos uma instância do gerador com a ajuda da [injeção de dependência automática](../concept/di-container.md), que funciona com handlers de action. Em outro serviço, você pode obter a instância com uma injeção no construtor parecida. Nas views, o gerador de URLs está disponível como `$url`." + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "Then we use `generate()` method to get the actual URL. It accepts a route name, route arguments, query parameters, and a hash fragment. The code will return `/test/submit/42`." +msgstr "Depois usamos o método `generate()` para obter a URL. Ele aceita o nome da rota, argumentos de rota, parâmetros de query e um fragmento (hash). O código retorna `/test/submit/42`." + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "Route arguments are used to fill placeholders in the route pattern. Arguments that aren't used in the pattern are added to the query string when the query parameters array doesn't already contain the same name:" +msgstr "Os argumentos de rota preenchem os placeholders do padrão da rota. Os argumentos que não aparecem no padrão são adicionados à query string, desde que o array de parâmetros de query ainda não tenha o mesmo nome:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "" +"$url = $urlGenerator->generate(\n" +" 'test/submit',\n" +" ['id' => '42', 'utm' => 'newsletter'],\n" +" ['page' => '1']\n" +");\n" +"// $url is \"/test/submit/42?page=1&utm=newsletter\".\n" +msgstr "" +"$url = $urlGenerator->generate(\n" +" 'test/submit',\n" +" ['id' => '42', 'utm' => 'newsletter'],\n" +" ['page' => '1']\n" +");\n" +"// $url is \"/test/submit/42?page=1&utm=newsletter\".\n" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "If you need absolute URL, use `generateAbsolute()` instead." +msgstr "Se você precisar de uma URL absoluta, use `generateAbsolute()`." + +#. type: Title ### +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "Generating URL from the current route" +msgstr "Gerando a URL a partir da rota atual" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "Use `generateFromCurrent()` when a link should keep the current route and most of its arguments. For example, a detail page can link to another page number while keeping the current route name and `id` argument:" +msgstr "Use `generateFromCurrent()` quando um link deve manter a rota atual e a maior parte dos seus argumentos. Por exemplo, uma página de detalhes pode apontar para outro número de página mantendo o nome da rota atual e o argumento `id`:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "$url = $urlGenerator->generateFromCurrent(['page' => '2']);\n" +msgstr "$url = $urlGenerator->generateFromCurrent(['page' => '2']);\n" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "The method also keeps query parameters from the current request. Pass explicit query parameters when a link should replace or add query string values." +msgstr "O método também mantém os parâmetros de query da requisição atual. Passe parâmetros de query explícitos quando o link precisar substituir ou adicionar valores na query string." + +#. type: Title ### +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "Locale-based URLs" +msgstr "URLs com locale" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "When the locale is part of the URL path, define it as a route argument. For a Yii application with routes in `config/common/routes.php`, wrap localized routes in a group with a locale parameter:" +msgstr "Quando o locale faz parte do caminho da URL, defina-o como um argumento de rota. Em uma aplicação Yii com as rotas em `config/common/routes.php`, coloque as rotas localizadas em um grupo com um parâmetro de locale:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "" +"routes(\n" +" Route::get('/')\n" +" ->action(HomePageAction::class)\n" +" ->name('home'),\n" +" Route::get('/posts/{slug}')\n" +" ->action(PostViewAction::class)\n" +" ->name('post/view')\n" +" )\n" +"];\n" +msgstr "" +"routes(\n" +" Route::get('/')\n" +" ->action(HomePageAction::class)\n" +" ->name('home'),\n" +" Route::get('/posts/{slug}')\n" +" ->action(PostViewAction::class)\n" +" ->name('post/view')\n" +" )\n" +"];\n" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "The route `/de/posts/welcome` matches the `post/view` route and stores `_locale` as a route argument with the `de` value." +msgstr "A rota `/de/posts/welcome` casa com a rota `post/view` e guarda `_locale` como argumento de rota com o valor `de`." + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "In middleware that chooses the request locale, read this argument from `CurrentRoute`:" +msgstr "No middleware que escolhe o locale da requisição, leia esse argumento de `CurrentRoute`:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "" +"currentRoute->getArgument('_locale', self::DEFAULT_LOCALE);\n" +"\n" +" $this->translator->setLocale($locale);\n" +" $this->view->setLocale($locale);\n" +" $this->urlGenerator->setDefaultArgument('_locale', $locale);\n" +"\n" +" return $handler->handle($request);\n" +" }\n" +"}\n" +msgstr "" +"currentRoute->getArgument('_locale', self::DEFAULT_LOCALE);\n" +"\n" +" $this->translator->setLocale($locale);\n" +" $this->view->setLocale($locale);\n" +" $this->urlGenerator->setDefaultArgument('_locale', $locale);\n" +"\n" +" return $handler->handle($request);\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "Register this middleware in the localized route group before the route action:" +msgstr "Registre esse middleware no grupo de rotas localizadas, antes da action da rota:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "" +"use App\\Web\\HomePage\\Action as HomePageAction;\n" +"use App\\Web\\Middleware\\LocaleMiddleware;\n" +"use Yiisoft\\Router\\Group;\n" +"use Yiisoft\\Router\\Route;\n" +"\n" +"return [\n" +" Group::create('/{_locale:en-US|de}')\n" +" ->middleware(LocaleMiddleware::class)\n" +" ->routes(\n" +" Route::get('/')\n" +" ->action(HomePageAction::class)\n" +" ->name('home')\n" +" )\n" +"];\n" +msgstr "" +"use App\\Web\\HomePage\\Action as HomePageAction;\n" +"use App\\Web\\Middleware\\LocaleMiddleware;\n" +"use Yiisoft\\Router\\Group;\n" +"use Yiisoft\\Router\\Route;\n" +"\n" +"return [\n" +" Group::create('/{_locale:en-US|de}')\n" +" ->middleware(LocaleMiddleware::class)\n" +" ->routes(\n" +" Route::get('/')\n" +" ->action(HomePageAction::class)\n" +" ->name('home')\n" +" )\n" +"];\n" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "After the middleware sets the default `_locale` argument, URL generation can omit it:" +msgstr "Depois que o middleware define o argumento padrão `_locale`, a geração de URLs pode omiti-lo:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "" +"$url = $urlGenerator->generate('post/view', ['slug' => 'welcome']);\n" +"// On a German page, $url is \"/de/posts/welcome\".\n" +msgstr "" +"$url = $urlGenerator->generate('post/view', ['slug' => 'welcome']);\n" +"// On a German page, $url is \"/de/posts/welcome\".\n" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "For a language switcher, use `generateFromCurrent()` and replace only the locale argument:" +msgstr "Para um seletor de idioma, use `generateFromCurrent()` e substitua apenas o argumento de locale:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "" +"$url = $urlGenerator->generateFromCurrent(\n" +" ['_locale' => 'en-US'],\n" +" fallbackRouteName: 'home'\n" +");\n" +msgstr "" +"$url = $urlGenerator->generateFromCurrent(\n" +" ['_locale' => 'en-US'],\n" +" fallbackRouteName: 'home'\n" +");\n" + +#. type: Title ## +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "Route patterns" +msgstr "Padrões de rota" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "Route patterns used depend on the underlying implementation used. The default implementation is [nikic/FastRoute](https://github.com/nikic/FastRoute)." +msgstr "Os padrões de rota dependem da implementação usada por baixo. A implementação padrão é o [nikic/FastRoute](https://github.com/nikic/FastRoute)." + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "Basic patterns are static like `/test`. That means they must match exactly in order for a route match." +msgstr "Os padrões básicos são estáticos, como `/test`. Isso significa que eles precisam casar exatamente para a rota ser escolhida." + +#. type: Title ### +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "Named Parameters" +msgstr "Parâmetros nomeados" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "A pattern can include one or more named parameters which are specified in the pattern in the format of `{ParamName:RegExp}`, where `ParamName` specifies the parameter name and `RegExp` is an optional regular expression used to match parameter values. If `RegExp` isn't specified, it means the parameter value should be a string without any slash." +msgstr "Um padrão pode ter um ou mais parâmetros nomeados, escritos no formato `{ParamName:RegExp}`, onde `ParamName` é o nome do parâmetro e `RegExp` é uma expressão regular opcional usada para casar o valor. Se `RegExp` não for informada, o valor do parâmetro deve ser uma string sem barras." + +#. type: Plain text +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "" +"> [!NOTE]\n" +"> You can only use regular expressions inside parameters. The rest of the pattern is considered plain text.\n" +msgstr "" +"> [!NOTE]\n" +"> Você só pode usar expressões regulares dentro dos parâmetros. O resto do padrão é tratado como texto puro.\n" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "You can't use capturing groups. For example `{lang:(en|de)}` isn't a valid placeholder, because `()` is a capturing group. Instead, you can use either `{lang:en|de}` or `{lang:(?:en|de)}`." +msgstr "Você não pode usar grupos de captura. Por exemplo, `{lang:(en|de)}` não é um placeholder válido, porque `()` é um grupo de captura. Em vez disso, use `{lang:en|de}` ou `{lang:(?:en|de)}`." + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "On a route match router fills `CurrentRoute` arguments with values matching the corresponding parts of the URL. When you use the rule to create a URL, it will take the values of the provided parameters and insert them at the places where the parameters are declared." +msgstr "Quando uma rota casa, o router preenche os argumentos de `CurrentRoute` com os valores das partes correspondentes da URL. Quando você usa a regra para criar uma URL, ela pega os valores dos parâmetros informados e os insere nas posições onde os parâmetros foram declarados." + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "Let's use some examples to illustrate how named parameters work. Assume you've declared the following three patterns:" +msgstr "Vamos usar alguns exemplos para mostrar como os parâmetros nomeados funcionam. Suponha que você declarou os três padrões a seguir:" + +#. type: Bullet: '1. ' +#: ../src/guide/runtime/routing.md +msgid "`'posts/{year:\\d{4}}/{category}`" +msgstr "`'posts/{year:\\d{4}}/{category}`" + +#. type: Bullet: '2. ' +#: ../src/guide/runtime/routing.md +msgid "`'posts'`" +msgstr "`'posts'`" + +#. type: Bullet: '3. ' +#: ../src/guide/runtime/routing.md +msgid "`'post/{id:\\d+}'`" +msgstr "`'post/{id:\\d+}'`" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/routing.md +msgid "`/posts` match the second pattern;" +msgstr "`/posts` casa com o segundo padrão;" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/routing.md +msgid "`/posts/2014/php` match a first pattern. Parameters are the `year` whose value is 2014 and the `category` whose value is `php`;" +msgstr "`/posts/2014/php` casa com o primeiro padrão. Os parâmetros são `year`, com valor 2014, e `category`, com valor `php`;" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/routing.md +msgid "`/post/100` match a third pattern. The `id` parameter value is 100;" +msgstr "`/post/100` casa com o terceiro padrão. O valor do parâmetro `id` é 100;" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/routing.md +msgid "`/posts/php` doesn't match." +msgstr "`/posts/php` não casa." + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "When generating URLs, you should use the following parameters:" +msgstr "Ao gerar URLs, você deve usar os seguintes parâmetros:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "" +"echo $url->generate('first', ['year' => '2020', 'category' => 'Virology']);\n" +"echo $url->generate('second');\n" +"echo $url->generate('third', ['id' => '42']);\n" +msgstr "" +"echo $url->generate('first', ['year' => '2020', 'category' => 'Virology']);\n" +"echo $url->generate('second');\n" +"echo $url->generate('third', ['id' => '42']);\n" + +#. type: Title ### +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "Optional parts" +msgstr "Partes opcionais" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "You should wrap optional pattern parts with `[` and `]`. For example, `/posts[/{id}]` pattern would match both `http://example.com/posts` and `http://example.com/posts/42`. Router would fill `id` argument of `CurrentRoute` service in the second case only. In this case, you could specify the default value:" +msgstr "Coloque as partes opcionais do padrão entre `[` e `]`. Por exemplo, o padrão `/posts[/{id}]` casa tanto com `http://example.com/posts` quanto com `http://example.com/posts/42`. O router só preenche o argumento `id` do serviço `CurrentRoute` no segundo caso. Nesse caso, você pode definir o valor padrão:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/routing.md +#, no-wrap +msgid "" +"use \\Yiisoft\\Router\\Route;\n" +"\n" +"Route::get('/posts[/{id}]')->defaults(['id' => '1']);\n" +msgstr "" +"use \\Yiisoft\\Router\\Route;\n" +"\n" +"Route::get('/posts[/{id}]')->defaults(['id' => '1']);\n" + +#. type: Plain text +#: ../src/guide/runtime/routing.md +msgid "Optional parts are only supported in a trailing position, not in the middle of a route." +msgstr "Partes opcionais só são suportadas no final da rota, não no meio dela." diff --git a/_translations/po/pt-BR/guide_runtime_sessions.md.po b/_translations/po/pt-BR/guide_runtime_sessions.md.po new file mode 100644 index 00000000..6cea8a7a --- /dev/null +++ b/_translations/po/pt-BR/guide_runtime_sessions.md.po @@ -0,0 +1,339 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-09-29 22:50+0000\n" +"PO-Revision-Date: 2026-09-29 22:50+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/guide/runtime/sessions.md ../src/guide/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "Sessions" +msgstr "Sessões" + +#. type: Plain text +#: ../src/guide/runtime/sessions.md +msgid "Sessions persist data between requests without passing them to the client and back. Yii has [a session package](https://github.com/yiisoft/session) to work with session data." +msgstr "As sessões mantêm dados entre requisições sem precisar enviá-los ao cliente e de volta. O Yii tem [um pacote de sessão](https://github.com/yiisoft/session) para trabalhar com os dados da sessão." + +#. type: Plain text +#: ../src/guide/runtime/sessions.md +msgid "To add it to your application, use composer:" +msgstr "Para adicioná-lo à sua aplicação, use o composer:" + +#. type: Fenced code block (shell) +#: ../src/guide/runtime/sessions.md +#, no-wrap +msgid "composer require yiisoft/session\n" +msgstr "composer require yiisoft/session\n" + +#. type: Title ## +#: ../src/guide/runtime/sessions.md +#, no-wrap +msgid "Configuring middleware" +msgstr "Configurando o middleware" + +#. type: Plain text +#: ../src/guide/runtime/sessions.md +msgid "To keep a session between requests, you need to add `SessionMiddleware` to your route group or application middlewares. You should prefer a route group when you have both API with token-based authentication and regular web routes in the same application. Having it this way avoids starting the session for API endpoints." +msgstr "Para manter a sessão entre requisições, você precisa adicionar o `SessionMiddleware` ao seu grupo de rotas ou aos middlewares da aplicação. Prefira um grupo de rotas quando a mesma aplicação tiver uma API com autenticação por token e rotas web comuns. Assim, a sessão não é iniciada nos endpoints da API." + +#. type: Plain text +#: ../src/guide/runtime/sessions.md +msgid "To add a session for a certain group of routes, edit `config/routes.php` like the following:" +msgstr "Para adicionar a sessão a um grupo específico de rotas, edite `config/routes.php` assim:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/sessions.md +#, no-wrap +msgid "" +"middleware(SessionMiddleware::class)\n" +" ->routes(\n" +" // ...\n" +" )\n" +"];\n" +msgstr "" +"middleware(SessionMiddleware::class)\n" +" ->routes(\n" +" // ...\n" +" )\n" +"];\n" + +#. type: Plain text +#: ../src/guide/runtime/sessions.md +msgid "To add a session to the whole application, edit `config/application.php` like the following:" +msgstr "Para adicionar a sessão à aplicação inteira, edite `config/application.php` assim:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/sessions.md +#, no-wrap +msgid "" +"return [\n" +" Yiisoft\\Yii\\Web\\Application::class => [\n" +" '__construct()' => [\n" +" 'dispatcher' => DynamicReference::to(static function (Injector $injector) {\n" +" return ($injector->make(MiddlewareDispatcher::class))\n" +" ->withMiddlewares(\n" +" [\n" +" Router::class,\n" +" CsrfTokenMiddleware::class,\n" +" SessionMiddleware::class, // <-- add this\n" +" ErrorCatcher::class,\n" +" ]\n" +" );\n" +" }),\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +"return [\n" +" Yiisoft\\Yii\\Web\\Application::class => [\n" +" '__construct()' => [\n" +" 'dispatcher' => DynamicReference::to(static function (Injector $injector) {\n" +" return ($injector->make(MiddlewareDispatcher::class))\n" +" ->withMiddlewares(\n" +" [\n" +" Router::class,\n" +" CsrfTokenMiddleware::class,\n" +" SessionMiddleware::class, // <-- add this\n" +" ErrorCatcher::class,\n" +" ]\n" +" );\n" +" }),\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Title ## +#: ../src/guide/runtime/sessions.md +#, no-wrap +msgid "Opening and closing session" +msgstr "Abrindo e fechando a sessão" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/sessions.md +#, no-wrap +msgid "" +"public function actionProfile(\\Yiisoft\\Session\\SessionInterface $session)\n" +"{\n" +" // start a session if it's not yet started\n" +" $session->open();\n" +"\n" +" // work with session\n" +"\n" +" // write session values and then close it\n" +" $session->close();\n" +"}\n" +msgstr "" +"public function actionProfile(\\Yiisoft\\Session\\SessionInterface $session)\n" +"{\n" +" // start a session if it's not yet started\n" +" $session->open();\n" +"\n" +" // work with session\n" +"\n" +" // write session values and then close it\n" +" $session->close();\n" +"}\n" + +#. type: Plain text +#: ../src/guide/runtime/sessions.md +#, no-wrap +msgid "" +"> [!NOTE]\n" +"> Closing session as early as possible is a good practice since many session implementations are blocking other\n" +"> requests while the session is open.\n" +msgstr "" +"> [!NOTE]\n" +"> Fechar a sessão o quanto antes é uma boa prática, já que muitas implementações de sessão bloqueiam outras\n" +"> requisições enquanto a sessão está aberta.\n" + +#. type: Plain text +#: ../src/guide/runtime/sessions.md +msgid "There are two more ways to close a session:" +msgstr "Há mais duas formas de fechar uma sessão:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/sessions.md +#, no-wrap +msgid "" +"public function actionProfile(\\Yiisoft\\Session\\SessionInterface $session)\n" +"{\n" +" // discard changes and close the session\n" +" $session->discard();\n" +"\n" +" // destroy the session completely\n" +" $session->destroy(); \n" +"}\n" +msgstr "" +"public function actionProfile(\\Yiisoft\\Session\\SessionInterface $session)\n" +"{\n" +" // discard changes and close the session\n" +" $session->discard();\n" +"\n" +" // destroy the session completely\n" +" $session->destroy(); \n" +"}\n" + +#. type: Title ## +#: ../src/guide/runtime/sessions.md +#, no-wrap +msgid "Working with session data" +msgstr "Trabalhando com os dados da sessão" + +#. type: Plain text +#: ../src/guide/runtime/sessions.md +msgid "Usually you will use the following methods to work with session data:" +msgstr "Normalmente você vai usar os seguintes métodos para trabalhar com os dados da sessão:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/sessions.md +#, no-wrap +msgid "" +"public function actionProfile(\\Yiisoft\\Session\\SessionInterface $session)\n" +"{\n" +" // get a value\n" +" $lastAccessTime = $session->get('lastAccessTime');\n" +"\n" +" // get all values\n" +" $sessionData = $session->all();\n" +" \n" +" // set a value\n" +" $session->set('lastAccessTime', time());\n" +"\n" +" // check if the value exists\n" +" if ($session->has('lastAccessTime')) {\n" +" // ... \n" +" }\n" +" \n" +" // remove value\n" +" $session->remove('lastAccessTime');\n" +"\n" +" // get value and then remove it\n" +" $sessionData = $session->pull('lastAccessTime');\n" +"\n" +" // clear session data from runtime\n" +" $session->clear();\n" +"}\n" +msgstr "" +"public function actionProfile(\\Yiisoft\\Session\\SessionInterface $session)\n" +"{\n" +" // get a value\n" +" $lastAccessTime = $session->get('lastAccessTime');\n" +"\n" +" // get all values\n" +" $sessionData = $session->all();\n" +" \n" +" // set a value\n" +" $session->set('lastAccessTime', time());\n" +"\n" +" // check if the value exists\n" +" if ($session->has('lastAccessTime')) {\n" +" // ... \n" +" }\n" +" \n" +" // remove value\n" +" $session->remove('lastAccessTime');\n" +"\n" +" // get value and then remove it\n" +" $sessionData = $session->pull('lastAccessTime');\n" +"\n" +" // clear session data from runtime\n" +" $session->clear();\n" +"}\n" + +#. type: Title ## +#: ../src/guide/runtime/sessions.md +#, no-wrap +msgid "Flash messages" +msgstr "Mensagens flash" + +#. type: Plain text +#: ../src/guide/runtime/sessions.md +msgid "In case you need some data to remain in session until read, such as in case of displaying a message on the next page, \"flash\" messages are what you need. A flash message is a special type of data that's available only in the current request and the next request. After that, it will be deleted automatically." +msgstr "Quando você precisa que um dado fique na sessão até ser lido, como ao exibir uma mensagem na próxima página, o que você precisa são as mensagens \"flash\". Uma mensagem flash é um tipo especial de dado que só fica disponível na requisição atual e na próxima. Depois disso, ela é apagada automaticamente." + +#. type: Plain text +#: ../src/guide/runtime/sessions.md +msgid "`FlashInteface` usage is the following:" +msgstr "O uso de `FlashInteface` é o seguinte:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/sessions.md +#, no-wrap +msgid "" +"/** @var Yiisoft\\Session\\Flash\\FlashInterface $flash */\n" +"\n" +"// request 1\n" +"$flash->set('warning', 'Oh no, not again.');\n" +"\n" +"// request 2\n" +"$warning = $flash->get('warning');\n" +"if ($warning !== null) {\n" +" // do something with it\n" +"}\n" +msgstr "" +"/** @var Yiisoft\\Session\\Flash\\FlashInterface $flash */\n" +"\n" +"// request 1\n" +"$flash->set('warning', 'Oh no, not again.');\n" +"\n" +"// request 2\n" +"$warning = $flash->get('warning');\n" +"if ($warning !== null) {\n" +" // do something with it\n" +"}\n" + +#. type: Title ## +#: ../src/guide/runtime/sessions.md +#, no-wrap +msgid "Custom session storage" +msgstr "Armazenamento de sessão personalizado" + +#. type: Plain text +#: ../src/guide/runtime/sessions.md +msgid "When using `Yiisoft\\Session\\Session`, you can use your own storage implementation:" +msgstr "Ao usar `Yiisoft\\Session\\Session`, você pode usar a sua própria implementação de armazenamento:" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/sessions.md +#, no-wrap +msgid "" +"$handler = new MySessionHandler();\n" +"$session = new \\Yiisoft\\Session\\Session([], $handler);\n" +msgstr "" +"$handler = new MySessionHandler();\n" +"$session = new \\Yiisoft\\Session\\Session([], $handler);\n" + +#. type: Plain text +#: ../src/guide/runtime/sessions.md +msgid "Custom storage must implement `\\SessionHandlerInterface`." +msgstr "O armazenamento personalizado precisa implementar `\\SessionHandlerInterface`." diff --git a/_translations/po/pt-BR/guide_security_authentication.md.po b/_translations/po/pt-BR/guide_security_authentication.md.po new file mode 100644 index 00000000..b4d7ddb6 --- /dev/null +++ b/_translations/po/pt-BR/guide_security_authentication.md.po @@ -0,0 +1,518 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-06-05 20:33+0000\n" +"PO-Revision-Date: 2026-06-05 20:33+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/security/authentication.md +#, no-wrap +msgid "Authentication" +msgstr "Autenticação" + +#. type: Plain text +#: ../src/guide/security/authentication.md +msgid "Authentication is the process of verifying the identity of a user. It usually uses an identifier (for example, a username or an email address) and a secret token (such as a password or an access token) to judge if the user is the one whom he claims as. Authentication is the basis of the login feature." +msgstr "Autenticação é o processo de verificar a identidade de um usuário. Normalmente ela usa um identificador (por exemplo, um nome de usuário ou um endereço de e-mail) e um token secreto (como uma senha ou um token de acesso) para decidir se o usuário é quem diz ser. A autenticação é a base do recurso de login." + +#. type: Plain text +#: ../src/guide/security/authentication.md +msgid "Yii provides an authentication framework which wires up various components to support login. To use this framework, you mainly need to do the following work:" +msgstr "O Yii fornece um framework de autenticação que conecta vários componentes para dar suporte ao login. Para usar esse framework, você precisa basicamente fazer o seguinte:" + +#. type: Bullet: '* ' +#: ../src/guide/security/authentication.md +msgid "Configure the `Yiisoft\\User\\CurrentUser` service;" +msgstr "Configurar o serviço `Yiisoft\\User\\CurrentUser`;" + +#. type: Bullet: '* ' +#: ../src/guide/security/authentication.md +msgid "Create a class implementing the `\\Yiisoft\\Auth\\IdentityInterface` interface;" +msgstr "Criar uma classe que implementa a interface `\\Yiisoft\\Auth\\IdentityInterface`;" + +#. type: Bullet: '* ' +#: ../src/guide/security/authentication.md +msgid "Create a class implementing the `\\Yiisoft\\Auth\\IdentityRepositoryInterface` interface;" +msgstr "Criar uma classe que implementa a interface `\\Yiisoft\\Auth\\IdentityRepositoryInterface`;" + +#. type: Plain text +#: ../src/guide/security/authentication.md +msgid "To use the `Yiisoft\\User\\CurrentUser` service, install [yiisoft/user](https://github.com/yiisoft/user) package:" +msgstr "Para usar o serviço `Yiisoft\\User\\CurrentUser`, instale o pacote [yiisoft/user](https://github.com/yiisoft/user):" + +#. type: Fenced code block (shell) +#: ../src/guide/security/authentication.md +#, no-wrap +msgid "composer require yiisoft/user\n" +msgstr "composer require yiisoft/user\n" + +#. type: Title ## +#: ../src/guide/security/authentication.md +#, no-wrap +msgid "Configuring `Yiisoft\\User\\CurrentUser`" +msgstr "Configurando `Yiisoft\\User\\CurrentUser`" + +#. type: Plain text +#: ../src/guide/security/authentication.md +msgid "The `Yiisoft\\User\\CurrentUser` application service manages the user authentication status. It depends on `Yiisoft\\Auth\\IdentityRepositoryInterface` that should return an instance of `\\Yiisoft\\Auth\\IdentityInterface` which has the actual authentication logic." +msgstr "O serviço de aplicação `Yiisoft\\User\\CurrentUser` gerencia o estado de autenticação do usuário. Ele depende de `Yiisoft\\Auth\\IdentityRepositoryInterface`, que deve retornar uma instância de `\\Yiisoft\\Auth\\IdentityInterface` contendo a lógica de autenticação de fato." + +#. type: Fenced code block (php) +#: ../src/guide/security/authentication.md +#, no-wrap +msgid "" +"use Yiisoft\\Session\\Session;\n" +"use Yiisoft\\Session\\SessionInterface;\n" +"use Yiisoft\\Auth\\IdentityRepositoryInterface;\n" +"use Yiisoft\\Definitions\\Reference;\n" +"\n" +"return [\n" +" // ...\n" +"\n" +" SessionInterface::class => [\n" +" 'class' => Session::class,\n" +" '__construct()' => [\n" +" $params['session']['options'] ?? [],\n" +" $params['session']['handler'] ?? null,\n" +" ],\n" +" ],\n" +" IdentityRepositoryInterface::class => IdentityRepository::class,\n" +" CurrentUser::class => [\n" +" 'withSession()' => [Reference::to(SessionInterface::class)]\n" +" ],\n" +"];\n" +msgstr "" +"use Yiisoft\\Session\\Session;\n" +"use Yiisoft\\Session\\SessionInterface;\n" +"use Yiisoft\\Auth\\IdentityRepositoryInterface;\n" +"use Yiisoft\\Definitions\\Reference;\n" +"\n" +"return [\n" +" // ...\n" +"\n" +" SessionInterface::class => [\n" +" 'class' => Session::class,\n" +" '__construct()' => [\n" +" $params['session']['options'] ?? [],\n" +" $params['session']['handler'] ?? null,\n" +" ],\n" +" ],\n" +" IdentityRepositoryInterface::class => IdentityRepository::class,\n" +" CurrentUser::class => [\n" +" 'withSession()' => [Reference::to(SessionInterface::class)]\n" +" ],\n" +"];\n" + +#. type: Title ## +#: ../src/guide/security/authentication.md +#, no-wrap +msgid "Implementing`\\Yiisoft\\Auth\\IdentityInterface`" +msgstr "Implementando`\\Yiisoft\\Auth\\IdentityInterface`" + +#. type: Plain text +#: ../src/guide/security/authentication.md +msgid "The identity class must implement the `\\Yiisoft\\Auth\\IdentityInterface` which has a single method:" +msgstr "A classe de identidade deve implementar a `\\Yiisoft\\Auth\\IdentityInterface`, que tem um único método:" + +#. type: Bullet: '* ' +#: ../src/guide/security/authentication.md +msgid "[[yii\\web\\IdentityInterface::getId()|getId()]]: it returns the ID of the user represented by this identity instance." +msgstr "[[yii\\web\\IdentityInterface::getId()|getId()]]: retorna o ID do usuário representado por esta instância de identidade." + +#. type: Plain text +#: ../src/guide/security/authentication.md +msgid "In the following example, an identity class is implemented as a pure PHP object." +msgstr "No exemplo a seguir, a classe de identidade é implementada como um objeto PHP puro." + +#. type: Fenced code block (php) +#: ../src/guide/security/authentication.md +#, no-wrap +msgid "" +"id;\n" +" }\n" +"}\n" +msgstr "" +"id;\n" +" }\n" +"}\n" + +#. type: Title ## +#: ../src/guide/security/authentication.md +#, no-wrap +msgid "Implementing`\\Yiisoft\\Auth\\IdentityRepositoryInterface`" +msgstr "Implementando`\\Yiisoft\\Auth\\IdentityRepositoryInterface`" + +#. type: Plain text +#: ../src/guide/security/authentication.md +msgid "The identity repository class must implement the `\\Yiisoft\\Auth\\IdentityRepositoryInterface` which has the following methods:" +msgstr "A classe de repositório de identidades deve implementar a `\\Yiisoft\\Auth\\IdentityRepositoryInterface`, que tem os seguintes métodos:" + +#. type: Bullet: '* ' +#: ../src/guide/security/authentication.md +msgid "`findIdentity(string $id): ?IdentityInterface`: it looks for an instance of the identity class using the specified ID. This method is used when you need to keep the login status via session." +msgstr "`findIdentity(string $id): ?IdentityInterface`: procura uma instância da classe de identidade usando o ID informado. Esse método é usado quando você precisa manter o estado de login via sessão." + +#. type: Bullet: '* ' +#: ../src/guide/security/authentication.md +msgid "`findIdentityByToken(string $token, string $type): ?IdentityInterface`: it looks for an instance of the identity class using the specified access token. This method is used when you need to authenticate a user by a single secret token (for example, in a stateless REST API)." +msgstr "`findIdentityByToken(string $token, string $type): ?IdentityInterface`: procura uma instância da classe de identidade usando o token de acesso informado. Esse método é usado quando você precisa autenticar um usuário por um único token secreto (por exemplo, numa API REST sem estado)." + +#. type: Plain text +#: ../src/guide/security/authentication.md +msgid "A dummy implementation may look like the following:" +msgstr "Uma implementação fictícia pode ficar assim:" + +#. type: Fenced code block (php) +#: ../src/guide/security/authentication.md +#, no-wrap +msgid "" +"namespace App\\User;\n" +"\n" +"use App\\User\\Identity;\n" +"use \\Yiisoft\\Auth\\IdentityInterface;\n" +"use \\Yiisoft\\Auth\\IdentityRepositoryInterface;\n" +"\n" +"final readonly class IdentityRepository implements IdentityRepositoryInterface\n" +"{\n" +" private const USERS = [\n" +" [\n" +" 'id' => 1,\n" +" 'token' => '12345' \n" +" ],\n" +" [\n" +" 'id' => 42,\n" +" 'token' => '54321'\n" +" ], \n" +" ];\n" +"\n" +" public function findIdentity(string $id) : ?IdentityInterface\n" +" {\n" +" foreach (self::USERS as $user) {\n" +" if ((string)$user['id'] === $id) {\n" +" return new Identity($id); \n" +" }\n" +" }\n" +" \n" +" return null;\n" +" }\n" +"\n" +" public function findIdentityByToken(string $token, string $type) : ?IdentityInterface\n" +" {\n" +" foreach (self::USERS as $user) {\n" +" if ($user['token'] === $token) {\n" +" return new Identity((string)$user['id']); \n" +" }\n" +" }\n" +" \n" +" return null;\n" +" }\n" +"}\n" +msgstr "" +"namespace App\\User;\n" +"\n" +"use App\\User\\Identity;\n" +"use \\Yiisoft\\Auth\\IdentityInterface;\n" +"use \\Yiisoft\\Auth\\IdentityRepositoryInterface;\n" +"\n" +"final readonly class IdentityRepository implements IdentityRepositoryInterface\n" +"{\n" +" private const USERS = [\n" +" [\n" +" 'id' => 1,\n" +" 'token' => '12345' \n" +" ],\n" +" [\n" +" 'id' => 42,\n" +" 'token' => '54321'\n" +" ], \n" +" ];\n" +"\n" +" public function findIdentity(string $id) : ?IdentityInterface\n" +" {\n" +" foreach (self::USERS as $user) {\n" +" if ((string)$user['id'] === $id) {\n" +" return new Identity($id); \n" +" }\n" +" }\n" +" \n" +" return null;\n" +" }\n" +"\n" +" public function findIdentityByToken(string $token, string $type) : ?IdentityInterface\n" +" {\n" +" foreach (self::USERS as $user) {\n" +" if ($user['token'] === $token) {\n" +" return new Identity((string)$user['id']); \n" +" }\n" +" }\n" +" \n" +" return null;\n" +" }\n" +"}\n" + +#. type: Title ## +#: ../src/guide/security/authentication.md +#, no-wrap +msgid "Using `Yiisoft\\User\\CurrentUser`" +msgstr "Usando `Yiisoft\\User\\CurrentUser`" + +#. type: Plain text +#: ../src/guide/security/authentication.md +msgid "You can use `Yiisoft\\User\\CurrentUser` service to get current user identity. As any service, it could be auto-wired in either action handler constructor or method:" +msgstr "Você pode usar o serviço `Yiisoft\\User\\CurrentUser` para obter a identidade do usuário atual. Como qualquer serviço, ele pode ser injetado automaticamente (autowiring) no construtor ou no método do handler da action:" + +#. type: Fenced code block (php) +#: ../src/guide/security/authentication.md +#, no-wrap +msgid "" +"use Psr\\Http\\Message\\ServerRequestInterface;\n" +"use Yiisoft\\User\\CurrentUser;\n" +"\n" +"final readonly class SiteController\n" +"{\n" +" public function __construct(private CurrentUser $user) {}\n" +"\n" +" public function index(ServerRequestInterface $request): ResponseInterface\n" +" {\n" +" if ($this->user->isGuest()) {\n" +" // user is guest\n" +" } else {\n" +" $identity = $this->user->getIdentity();\n" +" // do something based on identity\n" +" }\n" +" }\n" +"}\n" +msgstr "" +"use Psr\\Http\\Message\\ServerRequestInterface;\n" +"use Yiisoft\\User\\CurrentUser;\n" +"\n" +"final readonly class SiteController\n" +"{\n" +" public function __construct(private CurrentUser $user) {}\n" +"\n" +" public function index(ServerRequestInterface $request): ResponseInterface\n" +" {\n" +" if ($this->user->isGuest()) {\n" +" // o usuário é visitante\n" +" } else {\n" +" $identity = $this->user->getIdentity();\n" +" // faça algo com base na identidade\n" +" }\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/security/authentication.md +msgid "`isGuest()` determines if user is logged in or not. `getIdentity()` returns an instance of identity." +msgstr "`isGuest()` determina se o usuário está logado ou não. `getIdentity()` retorna uma instância da identidade." + +#. type: Plain text +#: ../src/guide/security/authentication.md +msgid "To log in a user, you may use the following code:" +msgstr "Para fazer o login de um usuário, você pode usar o seguinte código:" + +#. type: Fenced code block (php) +#: ../src/guide/security/authentication.md +#, no-wrap +msgid "" +"$identity = $identityRepository->findByEmail($email);\n" +"\n" +"/* @var $user \\Yiisoft\\User\\CurrentUser */\n" +"$user->login($identity);\n" +msgstr "" +"$identity = $identityRepository->findByEmail($email);\n" +"\n" +"/* @var $user \\Yiisoft\\User\\CurrentUser */\n" +"$user->login($identity);\n" + +#. type: Plain text +#: ../src/guide/security/authentication.md +msgid "The `login()` method sets the identity to the User service. It stores identity into session so user authentication status is maintained." +msgstr "O método `login()` define a identidade no serviço de usuário. Ele armazena a identidade na sessão, para que o estado de autenticação do usuário seja mantido." + +#. type: Plain text +#: ../src/guide/security/authentication.md +msgid "To log out a user, call" +msgstr "Para fazer o logout de um usuário, chame" + +#. type: Fenced code block (php) +#: ../src/guide/security/authentication.md +#, no-wrap +msgid "" +"/* @var $user \\Yiisoft\\User\\CurrentUser */\n" +"$user->logout();\n" +msgstr "" +"/* @var $user \\Yiisoft\\User\\CurrentUser */\n" +"$user->logout();\n" + +#. type: Title ## +#: ../src/guide/security/authentication.md +#, no-wrap +msgid "Protecting Routes" +msgstr "Protegendo rotas" + +#. type: Plain text +#: ../src/guide/security/authentication.md +msgid "The `Yiisoft\\Auth\\Middleware\\Authentication` middleware can be used to restrict access to a given route to authenticated users only." +msgstr "O middleware `Yiisoft\\Auth\\Middleware\\Authentication` pode ser usado para restringir o acesso a uma rota apenas a usuários autenticados." + +#. type: Plain text +#: ../src/guide/security/authentication.md +msgid "First, configure the `Yiisoft\\Auth\\AuthenticationMethodInterface`:" +msgstr "Primeiro, configure a `Yiisoft\\Auth\\AuthenticationMethodInterface`:" + +#. type: Fenced code block (php) +#: ../src/guide/security/authentication.md +#, no-wrap +msgid "" +"use Yiisoft\\Auth\\AuthenticationMethodInterface;\n" +"use Yiisoft\\User\\Method\\WebAuth;\n" +"\n" +"return [\n" +" // ...\n" +" AuthenticationMethodInterface::class => WebAuth::class,\n" +"];\n" +msgstr "" +"use Yiisoft\\Auth\\AuthenticationMethodInterface;\n" +"use Yiisoft\\User\\Method\\WebAuth;\n" +"\n" +"return [\n" +" // ...\n" +" AuthenticationMethodInterface::class => WebAuth::class,\n" +"];\n" + +#. type: Plain text +#: ../src/guide/security/authentication.md +msgid "Then, apply the `Yiisoft\\Auth\\Middleware\\Authentication` middleware to a route:" +msgstr "Depois, aplique o middleware `Yiisoft\\Auth\\Middleware\\Authentication` a uma rota:" + +#. type: Fenced code block (php) +#: ../src/guide/security/authentication.md +#, no-wrap +msgid "" +"use Yiisoft\\Auth\\Middleware\\Authentication;\n" +" \n" +"Route::post('/create')\n" +" ->middleware(Authentication::class)\n" +" ->action([SiteController::class, 'create'])\n" +" ->name('site/create')\n" +msgstr "" +"use Yiisoft\\Auth\\Middleware\\Authentication;\n" +" \n" +"Route::post('/create')\n" +" ->middleware(Authentication::class)\n" +" ->action([SiteController::class, 'create'])\n" +" ->name('site/create')\n" + +#. type: Plain text +#: ../src/guide/security/authentication.md +#, no-wrap +msgid " Or to a group of routes:\n" +msgstr " Ou a um grupo de rotas:\n" + +#. type: Fenced code block (php) +#: ../src/guide/security/authentication.md +#, no-wrap +msgid "" +"use Yiisoft\\Auth\\Middleware\\Authentication;\n" +"\n" +"Group::create()\n" +" ->middleware(Authentication::class)\n" +" ->routes(\n" +" Route::post('/create')\n" +" ->action([SiteController::class, 'create'])\n" +" ->name('site/create'),\n" +" Route::put('/update/{id}')\n" +" ->action([SiteController::class, 'update'])\n" +" ->name('site/update')\n" +" )\n" +msgstr "" +"use Yiisoft\\Auth\\Middleware\\Authentication;\n" +"\n" +"Group::create()\n" +" ->middleware(Authentication::class)\n" +" ->routes(\n" +" Route::post('/create')\n" +" ->action([SiteController::class, 'create'])\n" +" ->name('site/create'),\n" +" Route::put('/update/{id}')\n" +" ->action([SiteController::class, 'update'])\n" +" ->name('site/update')\n" +" )\n" + +#. type: Title ## +#: ../src/guide/security/authentication.md +#, no-wrap +msgid "Authentication Events" +msgstr "Eventos de autenticação" + +#. type: Plain text +#: ../src/guide/security/authentication.md +msgid "The user service raises a few events during the login and logout processes." +msgstr "O serviço de usuário dispara alguns eventos durante os processos de login e logout." + +#. type: Bullet: '* ' +#: ../src/guide/security/authentication.md +msgid "`\\Yiisoft\\User\\Event\\BeforeLogin`: raised at the beginning of `login()`. If the event handler calls `invalidate()` on an event object, the login process will be cancelled." +msgstr "`\\Yiisoft\\User\\Event\\BeforeLogin`: disparado no início de `login()`. Se o handler do evento chamar `invalidate()` no objeto do evento, o processo de login será cancelado." + +#. type: Bullet: '* ' +#: ../src/guide/security/authentication.md +msgid "`\\Yiisoft\\User\\Event\\AfterLogin`: raised after a successful login." +msgstr "`\\Yiisoft\\User\\Event\\AfterLogin`: disparado após um login bem-sucedido." + +#. type: Bullet: '* ' +#: ../src/guide/security/authentication.md +msgid "`\\Yiisoft\\User\\Event\\BeforeLogout`: raised at the beginning of `logout()`. If the event handler calls `invalidate()` on an event object, the logout process will be cancelled." +msgstr "`\\Yiisoft\\User\\Event\\BeforeLogout`: disparado no início de `logout()`. Se o handler do evento chamar `invalidate()` no objeto do evento, o processo de logout será cancelado." + +#. type: Bullet: '* ' +#: ../src/guide/security/authentication.md +msgid "`\\Yiisoft\\User\\Event\\AfterLogout`: raised after a successful logout." +msgstr "`\\Yiisoft\\User\\Event\\AfterLogout`: disparado após um logout bem-sucedido." + +#. type: Plain text +#: ../src/guide/security/authentication.md +msgid "You may respond to these events to implement features such as login audit, online user statistics. For example, in the handler for `\\Yiisoft\\User\\Event\\AfterLogin`, you may record the login time and IP address in the `user` database table." +msgstr "Você pode responder a esses eventos para implementar recursos como auditoria de login ou estatísticas de usuários online. Por exemplo, no handler de `\\Yiisoft\\User\\Event\\AfterLogin`, você pode registrar o horário e o endereço IP do login na tabela `user` do banco de dados." diff --git a/_translations/po/pt-BR/guide_security_authorization.md.po b/_translations/po/pt-BR/guide_security_authorization.md.po new file mode 100644 index 00000000..3badd80e --- /dev/null +++ b/_translations/po/pt-BR/guide_security_authorization.md.po @@ -0,0 +1,1188 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-06-05 20:33+0000\n" +"PO-Revision-Date: 2026-06-05 20:33+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Fenced code block +#: ../src/guide/databases/db-migrations.md ../src/guide/security/authorization.md +#, no-wrap +msgid "./yii migrate:up\n" +msgstr "./yii migrate:up\n" + +#. type: Title # +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Authorization" +msgstr "Autorização" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Authorization is the process of verifying that a user has enough permission to do something." +msgstr "Autorização é o processo de verificar se um usuário tem permissão suficiente para fazer algo." + +#. type: Title ## +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Checking for permission" +msgstr "Verificando permissões" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "You can check if a user has certain permissions by using `\\Yiisoft\\User\\CurrentUser` service:" +msgstr "Você pode verificar se um usuário tem determinadas permissões usando o serviço `\\Yiisoft\\User\\CurrentUser`:" + +#. type: Fenced code block (php) +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "" +"namespace App\\Blog\\Post;\n" +"\n" +"use Yiisoft\\User\\CurrentUser;\n" +"use Yiisoft\\Router\\HydratorAttribute\\RouteArgument;\n" +"use Psr\\Http\\Message\\ResponseInterface;\n" +"\n" +"final readonly class PostController\n" +"{\n" +" public function __construct(\n" +" private PostRepositoryInterface $postRepository,\n" +" private CurrentUser $user\n" +" )\n" +" {\n" +" }\n" +"\n" +" public function update(#[RouteArgument('id')] int $id): ResponseInterface\n" +" {\n" +" $post = $this->postRepository->findByPK($id);\n" +" if ($post === null) {\n" +" // respond with 404\n" +" }\n" +"\n" +" if (!$this->canCurrentUserUpdatePost($post)) {\n" +" // respond with 403\n" +" }\n" +"\n" +" // continue with updating the post\n" +" }\n" +"\n" +" private function canCurrentUserUpdatePost(Post $post): bool\n" +" {\n" +" return $post->getAuthorId() === $this->user->getId() &&\n" +" $this->user->can('updatePost');\n" +" }\n" +"}\n" +msgstr "" +"namespace App\\Blog\\Post;\n" +"\n" +"use Yiisoft\\User\\CurrentUser;\n" +"use Yiisoft\\Router\\HydratorAttribute\\RouteArgument;\n" +"use Psr\\Http\\Message\\ResponseInterface;\n" +"\n" +"final readonly class PostController\n" +"{\n" +" public function __construct(\n" +" private PostRepositoryInterface $postRepository,\n" +" private CurrentUser $user\n" +" )\n" +" {\n" +" }\n" +"\n" +" public function update(#[RouteArgument('id')] int $id): ResponseInterface\n" +" {\n" +" $post = $this->postRepository->findByPK($id);\n" +" if ($post === null) {\n" +" // responda com 404\n" +" }\n" +"\n" +" if (!$this->canCurrentUserUpdatePost($post)) {\n" +" // responda com 403\n" +" }\n" +"\n" +" // continue com a atualização do post\n" +" }\n" +"\n" +" private function canCurrentUserUpdatePost(Post $post): bool\n" +" {\n" +" return $post->getAuthorId() === $this->user->getId() &&\n" +" $this->user->can('updatePost');\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Behind the scenes, `Yiisoft\\User\\CurrentUser::can()` method calls `Yiisoft\\Access\\AccessCheckerInterface::userHasPermission()` so you should provide an implementation in dependency container in order for it to work." +msgstr "Por baixo dos panos, o método `Yiisoft\\User\\CurrentUser::can()` chama `Yiisoft\\Access\\AccessCheckerInterface::userHasPermission()`, então você precisa fornecer uma implementação no container de dependências para que ele funcione." + +#. type: Title ## +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Role-based access control (RBAC)" +msgstr "Controle de acesso baseado em papéis (RBAC)" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Role-Based Access Control (RBAC) provides a simple yet powerful centralized access control. Please refer to the [Wikipedia](https://en.wikipedia.org/wiki/Role-based_access_control) for details about comparing RBAC with other more traditional access control schemes." +msgstr "O controle de acesso baseado em papéis (RBAC, Role-Based Access Control) oferece um controle de acesso centralizado simples e flexível. Consulte a [Wikipedia](https://en.wikipedia.org/wiki/Role-based_access_control) para detalhes sobre a comparação do RBAC com outros esquemas de controle de acesso mais tradicionais." + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Yii implements a General Hierarchical RBAC, following the [NIST RBAC model](https://csrc.nist.gov/CSRC/media/Publications/conference-paper/2000/07/26/the-nist-model-for-role-based-access-control-towards-a-unified-/documents/sandhu-ferraiolo-kuhn-00.pdf)." +msgstr "O Yii implementa um RBAC hierárquico geral, seguindo o [modelo RBAC do NIST](https://csrc.nist.gov/CSRC/media/Publications/conference-paper/2000/07/26/the-nist-model-for-role-based-access-control-towards-a-unified-/documents/sandhu-ferraiolo-kuhn-00.pdf)." + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Using RBAC involves two parts of work. The first part is to build up the RBAC authorization data, and the second part is to use the authorization data to perform access check in places where it's necessary. Since RBAC implements `\\Yiisoft\\Access\\AccessCheckerInterface`, using it's similar to using any other implementation of an access checker." +msgstr "Usar RBAC envolve duas partes de trabalho. A primeira é montar os dados de autorização do RBAC, e a segunda é usar esses dados para fazer a verificação de acesso onde for necessário. Como o RBAC implementa `\\Yiisoft\\Access\\AccessCheckerInterface`, usá-lo é parecido com usar qualquer outra implementação de verificador de acesso." + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "To ease description next, there are some basic RBAC concepts first." +msgstr "Para facilitar a explicação a seguir, primeiro alguns conceitos básicos de RBAC." + +#. type: Title ### +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Basic concepts" +msgstr "Conceitos básicos" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "A role represents a collection of *permissions* (for example, creating posts, updating posts). You may assign a role to one or many users. To check if a user has a specified permission, you may check if the user has a role with that permission." +msgstr "Um papel representa um conjunto de *permissões* (por exemplo, criar posts, atualizar posts). Você pode atribuir um papel a um ou mais usuários. Para verificar se um usuário tem uma determinada permissão, você pode verificar se ele tem um papel com essa permissão." + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Associated with each role or permission, there may be a *rule*. A rule represents a piece of code that an access checker will execute to decide if the corresponding role or permission applies to the current user. For example, the \"update post\" permission may have a rule that checks if the current user is the post creator. During access checking, if the user is NOT the post creator, there's no \"update post\" permission." +msgstr "Cada papel ou permissão pode ter uma *regra* associada. Uma regra representa um trecho de código que o verificador de acesso executa para decidir se o papel ou a permissão correspondente se aplica ao usuário atual. Por exemplo, a permissão \"atualizar post\" pode ter uma regra que verifica se o usuário atual é o criador do post. Durante a verificação de acesso, se o usuário NÃO for o criador do post, ele não tem a permissão \"atualizar post\"." + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Both roles and permissions are in a hierarchy. In particular, a role may consist of other roles or permissions. And a permission may consist of other permissions. Yii implements a *partial order* hierarchy which includes the more special *tree* hierarchy. While a role can contain a permission, it isn't `true` vice versa." +msgstr "Tanto papéis quanto permissões ficam em uma hierarquia. Em particular, um papel pode ser composto de outros papéis ou permissões. E uma permissão pode ser composta de outras permissões. O Yii implementa uma hierarquia de *ordem parcial*, que inclui a hierarquia mais específica em *árvore*. Embora um papel possa conter uma permissão, o inverso não é verdadeiro." + +#. type: Title ### +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Configuring RBAC" +msgstr "Configurando o RBAC" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Yii RBAC requires storage to be provided." +msgstr "O RBAC do Yii exige que um armazenamento seja fornecido." + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "One of the following storages could be installed:" +msgstr "Um dos seguintes armazenamentos pode ser instalado:" + +#. type: Bullet: '- ' +#: ../src/guide/security/authorization.md +msgid "[PHP storage](https://github.com/yiisoft/rbac-php) - PHP file storage;" +msgstr "[Armazenamento PHP](https://github.com/yiisoft/rbac-php) - armazenamento em arquivos PHP;" + +#. type: Bullet: '- ' +#: ../src/guide/security/authorization.md +msgid "[DB storage](https://github.com/yiisoft/rbac-db) - database storage based on [Yii DB](https://github.com/yiisoft/db);" +msgstr "[Armazenamento em DB](https://github.com/yiisoft/rbac-db) - armazenamento em banco de dados baseado no [Yii DB](https://github.com/yiisoft/db);" + +#. type: Bullet: '- ' +#: ../src/guide/security/authorization.md +msgid "[Cycle DB storage](https://github.com/yiisoft/rbac-cycle-db) - database storage based on [Cycle DBAL](https://github.com/cycle/database)." +msgstr "[Armazenamento Cycle DB](https://github.com/yiisoft/rbac-cycle-db) - armazenamento em banco de dados baseado no [Cycle DBAL](https://github.com/cycle/database)." + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "You can also provide your own storage using the [yiisoft/rbac](https://github.com/yiisoft/rbac) package." +msgstr "Você também pode fornecer seu próprio armazenamento usando o pacote [yiisoft/rbac](https://github.com/yiisoft/rbac)." + +#. type: Title #### +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Configuring RBAC with the [PHP storage](https://github.com/yiisoft/rbac-php)" +msgstr "Configurando o RBAC com o [armazenamento PHP](https://github.com/yiisoft/rbac-php)" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Install [yiisoft/rbac-php](https://github.com/yiisoft/rbac-php) package:" +msgstr "Instale o pacote [yiisoft/rbac-php](https://github.com/yiisoft/rbac-php):" + +#. type: Fenced code block +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "composer require yiisoft/rbac-php\n" +msgstr "composer require yiisoft/rbac-php\n" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Before we set off to define authorization data and perform access checking, you need to configure the `Yiisoft\\Access\\AccessCheckerInterface` in dependency container:" +msgstr "Antes de definir os dados de autorização e fazer verificações de acesso, você precisa configurar a `Yiisoft\\Access\\AccessCheckerInterface` no container de dependências:" + +#. type: Fenced code block (php) +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "" +"use Yiisoft\\Rbac\\ItemsStorageInterface;\n" +"use Yiisoft\\Rbac\\AssignmentsStorageInterface;\n" +"use Yiisoft\\Rbac\\ManagerInterface;\n" +"use Yiisoft\\Rbac\\Php\\ItemsStorage;\n" +"use Yiisoft\\Rbac\\Php\\AssignmentsStorage;\n" +"use Yiisoft\\Access\\AccessCheckerInterface;\n" +"use Yiisoft\\User\\CurrentUser;\n" +"\n" +"return [\n" +" // ...\n" +" ItemsStorageInterface::class => [\n" +" 'class' => ItemsStorage::class,\n" +" '__construct()' => [\n" +" 'filePath' => $params['rbacItemsStorageFilePath']\n" +" ]\n" +" ],\n" +" AssignmentsStorageInterface::class => [\n" +" 'class' => AssignmentsStorage::class,\n" +" '__construct()' => [\n" +" 'filePath' => $params['rbacAssignmentsStorageFilePath']\n" +" ]\n" +" ],\n" +" AccessCheckerInterface::class => ManagerInterface::class,\n" +"\n" +" CurrentUser::class => [\n" +" 'withAccessChecker()' => [Reference::to(AccessCheckerInterface::class)]\n" +" ],\n" +"];\n" +msgstr "" +"use Yiisoft\\Rbac\\ItemsStorageInterface;\n" +"use Yiisoft\\Rbac\\AssignmentsStorageInterface;\n" +"use Yiisoft\\Rbac\\ManagerInterface;\n" +"use Yiisoft\\Rbac\\Php\\ItemsStorage;\n" +"use Yiisoft\\Rbac\\Php\\AssignmentsStorage;\n" +"use Yiisoft\\Access\\AccessCheckerInterface;\n" +"use Yiisoft\\User\\CurrentUser;\n" +"\n" +"return [\n" +" // ...\n" +" ItemsStorageInterface::class => [\n" +" 'class' => ItemsStorage::class,\n" +" '__construct()' => [\n" +" 'filePath' => $params['rbacItemsStorageFilePath']\n" +" ]\n" +" ],\n" +" AssignmentsStorageInterface::class => [\n" +" 'class' => AssignmentsStorage::class,\n" +" '__construct()' => [\n" +" 'filePath' => $params['rbacAssignmentsStorageFilePath']\n" +" ]\n" +" ],\n" +" AccessCheckerInterface::class => ManagerInterface::class,\n" +"\n" +" CurrentUser::class => [\n" +" 'withAccessChecker()' => [Reference::to(AccessCheckerInterface::class)]\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "`Yiisoft\\Rbac\\Manager` uses PHP script files to store authorization data. Make sure the directory and all the files in it are writable by the Web server process if you want to change permission hierarchy online." +msgstr "O `Yiisoft\\Rbac\\Manager` usa arquivos de script PHP para armazenar os dados de autorização. Garanta que o diretório e todos os arquivos dentro dele tenham permissão de escrita para o processo do servidor web, se você quiser alterar a hierarquia de permissões em tempo de execução." + +#. type: Title #### +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Configuring RBAC with the [DB storage](https://github.com/yiisoft/rbac-db)" +msgstr "Configurando o RBAC com o [armazenamento em DB](https://github.com/yiisoft/rbac-db)" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Install [yiisoft/rbac-db](https://github.com/yiisoft/rbac-db) package:" +msgstr "Instale o pacote [yiisoft/rbac-db](https://github.com/yiisoft/rbac-db):" + +#. type: Fenced code block +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "composer require yiisoft/rbac-db\n" +msgstr "composer require yiisoft/rbac-db\n" + +#. type: Plain text +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "" +"Install one of the following drivers:\n" +" - [SQLite](https://github.com/yiisoft/db-sqlite) (minimal required version is 3.8.3)\n" +" - [MySQL](https://github.com/yiisoft/db-mysql)\n" +" - [PostgreSQL](https://github.com/yiisoft/db-pgsql)\n" +" - [Microsoft SQL Server](https://github.com/yiisoft/db-mssql)\n" +" - [Oracle](https://github.com/yiisoft/db-oracle)\n" +msgstr "" +"Instale um dos seguintes drivers:\n" +" - [SQLite](https://github.com/yiisoft/db-sqlite) (a versão mínima exigida é a 3.8.3)\n" +" - [MySQL](https://github.com/yiisoft/db-mysql)\n" +" - [PostgreSQL](https://github.com/yiisoft/db-pgsql)\n" +" - [Microsoft SQL Server](https://github.com/yiisoft/db-mssql)\n" +" - [Oracle](https://github.com/yiisoft/db-oracle)\n" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "[Configure connection](https://yiisoft.github.io/docs/guide/start/databases.html#configuring-connection)." +msgstr "[Configure a conexão](https://yiisoft.github.io/docs/guide/start/databases.html#configuring-connection)." + +#. type: Fenced code block (php) +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "" +"use Yiisoft\\Rbac\\ItemsStorageInterface;\n" +"use Yiisoft\\Rbac\\AssignmentsStorageInterface;\n" +"use Yiisoft\\Rbac\\ManagerInterface;\n" +"use Yiisoft\\Rbac\\Db\\ItemsStorage;\n" +"use Yiisoft\\Rbac\\Db\\AssignmentsStorage;\n" +"use Yiisoft\\Access\\AccessCheckerInterface;\n" +"\n" +"return [\n" +" // ...\n" +" ItemsStorageInterface::class => ItemsStorage::class,\n" +" AssignmentsStorageInterface::class => AssignmentsStorage::class,\n" +" AccessCheckerInterface::class => ManagerInterface::class,\n" +"];\n" +msgstr "" +"use Yiisoft\\Rbac\\ItemsStorageInterface;\n" +"use Yiisoft\\Rbac\\AssignmentsStorageInterface;\n" +"use Yiisoft\\Rbac\\ManagerInterface;\n" +"use Yiisoft\\Rbac\\Db\\ItemsStorage;\n" +"use Yiisoft\\Rbac\\Db\\AssignmentsStorage;\n" +"use Yiisoft\\Access\\AccessCheckerInterface;\n" +"\n" +"return [\n" +" // ...\n" +" ItemsStorageInterface::class => ItemsStorage::class,\n" +" AssignmentsStorageInterface::class => AssignmentsStorage::class,\n" +" AccessCheckerInterface::class => ManagerInterface::class,\n" +"];\n" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Add the RBAC [DB storage](https://github.com/yiisoft/rbac-db) migration paths to params.php:" +msgstr "Adicione os caminhos das migrations do [armazenamento em DB](https://github.com/yiisoft/rbac-db) do RBAC ao params.php:" + +#. type: Fenced code block (php) +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "" +"return [\n" +" // ...\n" +" 'yiisoft/db-migration' => [\n" +" 'sourcePaths' => [\n" +" __DIR__ . '/../../vendor/yiisoft/rbac-db/migrations/items',\n" +" __DIR__ . '/../../vendor/yiisoft/rbac-db/migrations/assignments',\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +"return [\n" +" // ...\n" +" 'yiisoft/db-migration' => [\n" +" 'sourcePaths' => [\n" +" __DIR__ . '/../../vendor/yiisoft/rbac-db/migrations/items',\n" +" __DIR__ . '/../../vendor/yiisoft/rbac-db/migrations/assignments',\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Apply migrations:" +msgstr "Aplique as migrations:" + +#. type: Title ### +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Building authorization data" +msgstr "Montando os dados de autorização" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Building authorization data is all about the following tasks:" +msgstr "Montar os dados de autorização consiste nas seguintes tarefas:" + +#. type: Bullet: '- ' +#: ../src/guide/security/authorization.md +msgid "defining roles and permissions;" +msgstr "definir papéis e permissões;" + +#. type: Bullet: '- ' +#: ../src/guide/security/authorization.md +msgid "establishing relations between roles and permissions;" +msgstr "estabelecer relações entre papéis e permissões;" + +#. type: Bullet: '- ' +#: ../src/guide/security/authorization.md +msgid "defining rules;" +msgstr "definir regras;" + +#. type: Bullet: '- ' +#: ../src/guide/security/authorization.md +msgid "associating rules with roles and permissions;" +msgstr "associar regras a papéis e permissões;" + +#. type: Bullet: '- ' +#: ../src/guide/security/authorization.md +msgid "assigning roles to users." +msgstr "atribuir papéis a usuários." + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Depending on authorization flexibility requirements, you can do the tasks in different ways. If only developers change your permission hierarchy, you can use either migrations or a console command. Migration advantage is that you could execute it along with other migrations. The Console command advantage is that you have a good overview of the hierarchy in the code without a need to read many migrations." +msgstr "Dependendo da flexibilidade de autorização exigida, você pode fazer essas tarefas de maneiras diferentes. Se apenas desenvolvedores alteram sua hierarquia de permissões, você pode usar migrations ou um comando de console. A vantagem da migration é que você pode executá-la junto com as outras migrations. A vantagem do comando de console é que você tem uma boa visão da hierarquia no código, sem precisar ler muitas migrations." + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Either way, in the end, you'll get the following RBAC hierarchy:" +msgstr "De qualquer forma, no fim você terá a seguinte hierarquia RBAC:" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "![Simple RBAC hierarchy](/images/guide/security/rbac-hierarchy-1.svg \"Simple RBAC hierarchy\")" +msgstr "![Hierarquia RBAC simples](/images/guide/security/rbac-hierarchy-1.svg \"Hierarquia RBAC simples\")" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "In case you want to build permission hierarchy dynamically, you need a UI or a console command. The API used to build the hierarchy itself won't be different." +msgstr "Caso você queira montar a hierarquia de permissões dinamicamente, precisa de uma interface de usuário ou de um comando de console. A API usada para montar a hierarquia em si não muda." + +#. type: Title ### +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Using console command" +msgstr "Usando um comando de console" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "If your permission hierarchy doesn't change at all, and you have a fixed number of users, you can create a [console command](../tutorial/console-applications.md) that will initialize authorization data once via APIs offered by `\\Yiisoft\\Rbac\\ManagerInterface`:" +msgstr "Se a sua hierarquia de permissões não muda nunca e você tem um número fixo de usuários, pode criar um [comando de console](../tutorial/console-applications.md) que inicializa os dados de autorização uma única vez, usando as APIs oferecidas por `\\Yiisoft\\Rbac\\ManagerInterface`:" + +#. type: Fenced code block (php) +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "" +"removeAll();\n" +"\n" +" $this->manager->addPermission((new Permission(RbacCommand::CREATE_POST_PERMISSION))->withDescription('Create a post'));\n" +" $this->manager->addPermission((new Permission(RbacCommand::UPDATE_POST_PERMISSION))->withDescription('Update post'));\n" +"\n" +" // add the \"author\" role and give this role the \"createPost\" permission\n" +" $this->manager->addRole(new Role(RbacCommand::ROLE_AUTHOR));\n" +" $this->manager->addChild(RbacCommand::ROLE_AUTHOR, RbacCommand::CREATE_POST_PERMISSION);\n" +"\n" +" // add the \"admin\" role and give this role the \"updatePost\" permission\n" +" // as well as the permissions of the \"author\" role\n" +" $this->manager->addRole(new Role(RbacCommand::ROLE_ADMIN));\n" +" $this->manager->addChild(RbacCommand::ROLE_ADMIN, RbacCommand::UPDATE_POST_PERMISSION);\n" +" $this->manager->addChild(RbacCommand::ROLE_ADMIN, RbacCommand::ROLE_AUTHOR);\n" +"\n" +" // Assign roles to users. 1 and 2 are IDs returned by IdentityInterface::getId()\n" +" // usually implemented in your User model.\n" +" $this->manager->assign(RbacCommand::ROLE_AUTHOR, 2);\n" +" $this->manager->assign(RbacCommand::ROLE_ADMIN, 1);\n" +"\n" +" return ExitCode::OK;\n" +" }\n" +"\n" +" private function removeAll(): void\n" +" {\n" +" $this->manager->revokeAll(2);\n" +" $this->manager->revokeAll(1);\n" +"\n" +" $this->manager->removeRole(RbacCommand::ROLE_ADMIN);\n" +" $this->manager->removeRole(RbacCommand::ROLE_AUTHOR);\n" +"\n" +" $this->manager->removePermission(RbacCommand::CREATE_POST_PERMISSION);\n" +" $this->manager->removePermission(RbacCommand::UPDATE_POST_PERMISSION);\n" +" }\n" +"}\n" +msgstr "" +"removeAll();\n" +"\n" +" $this->manager->addPermission((new Permission(RbacCommand::CREATE_POST_PERMISSION))->withDescription('Create a post'));\n" +" $this->manager->addPermission((new Permission(RbacCommand::UPDATE_POST_PERMISSION))->withDescription('Update post'));\n" +"\n" +" // adiciona o papel \"author\" e dá a ele a permissão \"createPost\"\n" +" $this->manager->addRole(new Role(RbacCommand::ROLE_AUTHOR));\n" +" $this->manager->addChild(RbacCommand::ROLE_AUTHOR, RbacCommand::CREATE_POST_PERMISSION);\n" +"\n" +" // adiciona o papel \"admin\" e dá a ele a permissão \"updatePost\"\n" +" // além das permissões do papel \"author\"\n" +" $this->manager->addRole(new Role(RbacCommand::ROLE_ADMIN));\n" +" $this->manager->addChild(RbacCommand::ROLE_ADMIN, RbacCommand::UPDATE_POST_PERMISSION);\n" +" $this->manager->addChild(RbacCommand::ROLE_ADMIN, RbacCommand::ROLE_AUTHOR);\n" +"\n" +" // Atribui papéis aos usuários. 1 e 2 são IDs retornados por IdentityInterface::getId(),\n" +" // normalmente implementado no seu model User.\n" +" $this->manager->assign(RbacCommand::ROLE_AUTHOR, 2);\n" +" $this->manager->assign(RbacCommand::ROLE_ADMIN, 1);\n" +"\n" +" return ExitCode::OK;\n" +" }\n" +"\n" +" private function removeAll(): void\n" +" {\n" +" $this->manager->revokeAll(2);\n" +" $this->manager->revokeAll(1);\n" +"\n" +" $this->manager->removeRole(RbacCommand::ROLE_ADMIN);\n" +" $this->manager->removeRole(RbacCommand::ROLE_AUTHOR);\n" +"\n" +" $this->manager->removePermission(RbacCommand::CREATE_POST_PERMISSION);\n" +" $this->manager->removePermission(RbacCommand::UPDATE_POST_PERMISSION);\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Add the command to `config/console/commands.php`:" +msgstr "Adicione o comando em `config/console/commands.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "" +"return [ \n" +" // ...\n" +" 'rbac:init' => App\\Command\\RbacCommand::class\n" +"];\n" +msgstr "" +"return [ \n" +" // ...\n" +" 'rbac:init' => App\\Command\\RbacCommand::class\n" +"];\n" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "You can execute the command above from the console the following way:" +msgstr "Você pode executar o comando acima no console da seguinte forma:" + +#. type: Fenced code block +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "./yii rbac:init\n" +msgstr "./yii rbac:init\n" + +#. type: Plain text +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "" +"> If you don't want to hardcode what users have certain roles, don't put `->assign()` calls into the command. Instead,\n" +" create either UI or console command to manage assignments.\n" +msgstr "" +"> Se você não quer deixar fixo no código quais usuários têm determinados papéis, não coloque chamadas `->assign()` no comando. Em vez disso,\n" +" crie uma interface de usuário ou um comando de console para gerenciar as atribuições.\n" + +#. type: Title #### +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Using migrations" +msgstr "Usando migrations" + +#. type: Plain text +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "**TODO**: finish it when migrations are implemented.\n" +msgstr "**TODO**: terminar quando as migrations forem implementadas.\n" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "You can use [migrations](../databases/db-migrations.md) to initialize and change hierarchy via APIs offered by `\\Yiisoft\\Rbac\\ManagerInterface`." +msgstr "Você pode usar [migrations](../databases/db-migrations.md) para inicializar e alterar a hierarquia via APIs oferecidas por `\\Yiisoft\\Rbac\\ManagerInterface`." + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Create new migration using `./yii migrate:create init_rbac` then implement creating a hierarchy:" +msgstr "Crie uma nova migration com `./yii migrate:create init_rbac` e implemente a criação da hierarquia:" + +#. type: Fenced code block (php) +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "" +"manager->addPermission((new Permission(M260112125812InitRbac::CREATE_POST_PERMISSION))->withDescription('Create a post'));\n" +" $this->manager->addPermission((new Permission(M260112125812InitRbac::UPDATE_POST_PERMISSION))->withDescription('Update post'));\n" +"\n" +" // add the \"author\" role and give this role the \"createPost\" permission\n" +" $this->manager->addRole(new Role(M260112125812InitRbac::ROLE_AUTHOR));\n" +" $this->manager->addChild(M260112125812InitRbac::ROLE_AUTHOR, M260112125812InitRbac::CREATE_POST_PERMISSION);\n" +"\n" +" // add the \"admin\" role and give this role the \"updatePost\" permission\n" +" // as well as the permissions of the \"author\" role\n" +" $this->manager->addRole(new Role(M260112125812InitRbac::ROLE_ADMIN));\n" +" $this->manager->addChild(M260112125812InitRbac::ROLE_ADMIN, M260112125812InitRbac::UPDATE_POST_PERMISSION);\n" +" $this->manager->addChild(M260112125812InitRbac::ROLE_ADMIN, M260112125812InitRbac::ROLE_AUTHOR);\n" +"\n" +" // Assign roles to users. 1 and 2 are IDs returned by IdentityInterface::getId()\n" +" // usually implemented in your User model.\n" +" $this->manager->assign(M260112125812InitRbac::ROLE_AUTHOR, 2);\n" +" $this->manager->assign(M260112125812InitRbac::ROLE_ADMIN, 1);\n" +" }\n" +"\n" +" public function down(MigrationBuilder $b): void\n" +" {\n" +" $this->manager->revokeAll(2);\n" +" $this->manager->revokeAll(1);\n" +"\n" +" $this->manager->removeRole(M260112125812InitRbac::ROLE_ADMIN);\n" +" $this->manager->removeRole(M260112125812InitRbac::ROLE_AUTHOR);\n" +"\n" +" $this->manager->removePermission(M260112125812InitRbac::CREATE_POST_PERMISSION);\n" +" $this->manager->removePermission(M260112125812InitRbac::UPDATE_POST_PERMISSION);\n" +" }\n" +"}\n" +msgstr "" +"manager->addPermission((new Permission(M260112125812InitRbac::CREATE_POST_PERMISSION))->withDescription('Create a post'));\n" +" $this->manager->addPermission((new Permission(M260112125812InitRbac::UPDATE_POST_PERMISSION))->withDescription('Update post'));\n" +"\n" +" // adiciona o papel \"author\" e dá a ele a permissão \"createPost\"\n" +" $this->manager->addRole(new Role(M260112125812InitRbac::ROLE_AUTHOR));\n" +" $this->manager->addChild(M260112125812InitRbac::ROLE_AUTHOR, M260112125812InitRbac::CREATE_POST_PERMISSION);\n" +"\n" +" // adiciona o papel \"admin\" e dá a ele a permissão \"updatePost\"\n" +" // além das permissões do papel \"author\"\n" +" $this->manager->addRole(new Role(M260112125812InitRbac::ROLE_ADMIN));\n" +" $this->manager->addChild(M260112125812InitRbac::ROLE_ADMIN, M260112125812InitRbac::UPDATE_POST_PERMISSION);\n" +" $this->manager->addChild(M260112125812InitRbac::ROLE_ADMIN, M260112125812InitRbac::ROLE_AUTHOR);\n" +"\n" +" // Atribui papéis aos usuários. 1 e 2 são IDs retornados por IdentityInterface::getId(),\n" +" // normalmente implementado no seu model User.\n" +" $this->manager->assign(M260112125812InitRbac::ROLE_AUTHOR, 2);\n" +" $this->manager->assign(M260112125812InitRbac::ROLE_ADMIN, 1);\n" +" }\n" +"\n" +" public function down(MigrationBuilder $b): void\n" +" {\n" +" $this->manager->revokeAll(2);\n" +" $this->manager->revokeAll(1);\n" +"\n" +" $this->manager->removeRole(M260112125812InitRbac::ROLE_ADMIN);\n" +" $this->manager->removeRole(M260112125812InitRbac::ROLE_AUTHOR);\n" +"\n" +" $this->manager->removePermission(M260112125812InitRbac::CREATE_POST_PERMISSION);\n" +" $this->manager->removePermission(M260112125812InitRbac::UPDATE_POST_PERMISSION);\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "" +"> If you don't want to hardcode which users have certain roles, don't put `->assign()` calls in migrations. Instead,\n" +" create either UI or console command to manage assignments.\n" +msgstr "" +"> Se você não quer deixar fixo no código quais usuários têm determinados papéis, não coloque chamadas `->assign()` nas migrations. Em vez disso,\n" +" crie uma interface de usuário ou um comando de console para gerenciar as atribuições.\n" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "You could apply migration by using `./yii migrate:up`." +msgstr "Você pode aplicar a migration com `./yii migrate:up`." + +#. type: Title ## +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Assigning roles to users" +msgstr "Atribuindo papéis a usuários" + +#. type: Plain text +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "TODO: update when signup implemented in demo / template.\n" +msgstr "TODO: atualizar quando o cadastro for implementado no demo / template.\n" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "The author can create a post, admin can update the post and do everything the author can." +msgstr "O autor pode criar um post, o admin pode atualizar o post e fazer tudo o que o autor pode." + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "If your application allows user signup, you need to assign roles to these new users at once. For example, in order for all signed-up users to become authors in your advanced project template, you need to change `frontend\\models\\SignupForm::signup()` as follows:" +msgstr "Se sua aplicação permite o cadastro de usuários, você precisa atribuir papéis a esses novos usuários imediatamente. Por exemplo, para que todos os usuários cadastrados se tornem autores no seu template de projeto avançado, você precisa alterar `frontend\\models\\SignupForm::signup()` da seguinte forma:" + +#. type: Fenced code block (php) +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "" +"public function signup()\n" +"{\n" +" if ($this->validate()) {\n" +" $user = new User();\n" +" $user->username = $this->username;\n" +" $user->email = $this->email;\n" +" $user->setPassword($this->password);\n" +" $user->generateAuthKey();\n" +" $user->save(false);\n" +"\n" +" // the following three lines were added:\n" +" $authorRole = $this->manager->getRole('author');\n" +" if ($authorRole !== null) {\n" +" $this->manager->assign($authorRole->getName(), $user->getId());\n" +" }\n" +"\n" +" return $user;\n" +" }\n" +"\n" +" return null;\n" +"}\n" +msgstr "" +"public function signup()\n" +"{\n" +" if ($this->validate()) {\n" +" $user = new User();\n" +" $user->username = $this->username;\n" +" $user->email = $this->email;\n" +" $user->setPassword($this->password);\n" +" $user->generateAuthKey();\n" +" $user->save(false);\n" +"\n" +" // as três linhas a seguir foram adicionadas:\n" +" $authorRole = $this->manager->getRole('author');\n" +" if ($authorRole !== null) {\n" +" $this->manager->assign($authorRole->getName(), $user->getId());\n" +" }\n" +"\n" +" return $user;\n" +" }\n" +"\n" +" return null;\n" +"}\n" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "For applications that require complex access control with dynamically updated authorization data (such as an admin panel), you many need to develop special user interfaces using APIs offered by `Yiisoft\\Rbac\\Manager`." +msgstr "Para aplicações que exigem controle de acesso complexo com dados de autorização atualizados dinamicamente (como um painel administrativo), talvez você precise desenvolver interfaces de usuário específicas usando as APIs oferecidas por `Yiisoft\\Rbac\\Manager`." + +#. type: Title ### +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Using rules" +msgstr "Usando regras" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "As aforementioned, rules add extra constraint to roles and permissions. A rule is a class extending from `\\Yiisoft\\Rbac\\Rule`. It must implement the `execute()` method. In the hierarchy you've created before, the author can't edit his own post. Let's fix it. First, you need a rule to verify that the user is the post author:" +msgstr "Como mencionado, regras adicionam restrições extras a papéis e permissões. Uma regra é uma classe que estende `\\Yiisoft\\Rbac\\Rule`. Ela deve implementar o método `execute()`. Na hierarquia que você criou antes, o autor não pode editar o próprio post. Vamos corrigir isso. Primeiro, você precisa de uma regra para verificar se o usuário é o autor do post:" + +#. type: Fenced code block (php) +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "" +"namespace App\\User\\Rbac;\n" +"\n" +"use Yiisoft\\Rbac\\Item;\n" +"use Yiisoft\\Rbac\\RuleContext;\n" +"use Yiisoft\\Rbac\\RuleInterface;\n" +"\n" +"/**\n" +" * Checks if the authorID matches user passed via params.\n" +" */\n" +"final readonly class AuthorRule implements RuleInterface\n" +"{\n" +" public function execute(?string $userId, Item $item, RuleContext $context): bool\n" +" {\n" +" $post = $context->getParameterValue('post');\n" +" return $post !== null && $post->getAuthorId() == $userId;\n" +" }\n" +"}\n" +msgstr "" +"namespace App\\User\\Rbac;\n" +"\n" +"use Yiisoft\\Rbac\\Item;\n" +"use Yiisoft\\Rbac\\RuleContext;\n" +"use Yiisoft\\Rbac\\RuleInterface;\n" +"\n" +"/**\n" +" * Checks if the authorID matches user passed via params.\n" +" */\n" +"final readonly class AuthorRule implements RuleInterface\n" +"{\n" +" public function execute(?string $userId, Item $item, RuleContext $context): bool\n" +" {\n" +" $post = $context->getParameterValue('post');\n" +" return $post !== null && $post->getAuthorId() == $userId;\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "The rule checks if user created the `post`. Create a special permission `updateOwnPost` in the command you've used before:" +msgstr "A regra verifica se o usuário criou o `post`. Crie uma permissão especial `updateOwnPost` no comando que você usou antes:" + +#. type: Fenced code block (php) +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "" +"use Yiisoft\\Rbac\\Permission;\n" +"use Yiisoft\\Rbac\\ManagerInterface;\n" +"\n" +"// add the \"updateOwnPost\" permission and associate the rule with it.\n" +"$updateOwnPost = (new Permission('updateOwnPost'))\n" +" ->withDescription('Update own post')\n" +" ->withRuleName(AuthorRule::class);\n" +"$this->manager->addPermission($updateOwnPost);\n" +"\n" +"// \"updateOwnPost\" will be used from \"updatePost\"\n" +"$this->manager->addChild($updateOwnPost->getName(), $updatePost->getName());\n" +"\n" +"// allow \"author\" to update their own posts\n" +"$this->manager->addChild($authorRole->getName(), $updateOwnPost->getName());\n" +"\n" +"// Remove this line since we don't want the AuthorRule to be applied to the 'admin' role\n" +"$this->manager->addChild('admin', 'author');\n" +msgstr "" +"use Yiisoft\\Rbac\\Permission;\n" +"use Yiisoft\\Rbac\\ManagerInterface;\n" +"\n" +"// adiciona a permissão \"updateOwnPost\" e associa a regra a ela.\n" +"$updateOwnPost = (new Permission('updateOwnPost'))\n" +" ->withDescription('Update own post')\n" +" ->withRuleName(AuthorRule::class);\n" +"$this->manager->addPermission($updateOwnPost);\n" +"\n" +"// \"updateOwnPost\" será usada a partir de \"updatePost\"\n" +"$this->manager->addChild($updateOwnPost->getName(), $updatePost->getName());\n" +"\n" +"// permite que \"author\" atualize os próprios posts\n" +"$this->manager->addChild($authorRole->getName(), $updateOwnPost->getName());\n" +"\n" +"// Remova esta linha, já que não queremos que a AuthorRule seja aplicada ao papel 'admin'\n" +"$this->manager->addChild('admin', 'author');\n" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Now you've got the following hierarchy:" +msgstr "Agora você tem a seguinte hierarquia:" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "![RBAC hierarchy with a rule](/images/guide/security/rbac-hierarchy-2.svg \"RBAC hierarchy with a rule\")" +msgstr "![Hierarquia RBAC com uma regra](/images/guide/security/rbac-hierarchy-2.svg \"Hierarquia RBAC com uma regra\")" + +#. type: Title ### +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Access check" +msgstr "Verificação de acesso" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "The check is done similarly to how it was done in the first section of this guide:" +msgstr "A verificação é feita de forma semelhante à da primeira seção deste guia:" + +#. type: Fenced code block (php) +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "" +"namespace App\\Blog\\Post;\n" +"\n" +"use Yiisoft\\User\\CurrentUser;\n" +"use Yiisoft\\Router\\HydratorAttribute\\RouteArgument;\n" +"use Psr\\Http\\Message\\ResponseInterface;\n" +"\n" +"final readonly class PostController\n" +"{\n" +" public function __construct(\n" +" private PostRepositoryInterface $postRepository,\n" +" private CurrentUser $user\n" +" )\n" +" {\n" +" }\n" +"\n" +" public function update(#[RouteArgument('id')] int $id): ResponseInterface\n" +" {\n" +" $post = $this->postRepository->findByPK($id);\n" +" if ($post === null) {\n" +" // respond with 404\n" +" }\n" +"\n" +" if (!$this->canCurrentUserUpdatePost($post)) {\n" +" // respond with 403\n" +" }\n" +"\n" +" // continue with updating the post\n" +" }\n" +"\n" +" private function canCurrentUserUpdatePost(Post $post): bool\n" +" {\n" +" return $this->user->can('updatePost', ['post' => $post]);\n" +" }\n" +"}\n" +msgstr "" +"namespace App\\Blog\\Post;\n" +"\n" +"use Yiisoft\\User\\CurrentUser;\n" +"use Yiisoft\\Router\\HydratorAttribute\\RouteArgument;\n" +"use Psr\\Http\\Message\\ResponseInterface;\n" +"\n" +"final readonly class PostController\n" +"{\n" +" public function __construct(\n" +" private PostRepositoryInterface $postRepository,\n" +" private CurrentUser $user\n" +" )\n" +" {\n" +" }\n" +"\n" +" public function update(#[RouteArgument('id')] int $id): ResponseInterface\n" +" {\n" +" $post = $this->postRepository->findByPK($id);\n" +" if ($post === null) {\n" +" // responda com 404\n" +" }\n" +"\n" +" if (!$this->canCurrentUserUpdatePost($post)) {\n" +" // responda com 403\n" +" }\n" +"\n" +" // continue com a atualização do post\n" +" }\n" +"\n" +" private function canCurrentUserUpdatePost(Post $post): bool\n" +" {\n" +" return $this->user->can('updatePost', ['post' => $post]);\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "The difference is that now checking for a user's own post is part of the RBAC." +msgstr "A diferença é que agora a verificação do próprio post do usuário faz parte do RBAC." + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "If the current user is Jane with `ID=1` you are starting at `createPost` and trying to get to `Jane`:" +msgstr "Se o usuário atual for Jane, com `ID=1`, você começa em `createPost` e tenta chegar a `Jane`:" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "![Access check](/images/guide/security/rbac-access-check-1.svg \"Access check\")" +msgstr "![Verificação de acesso](/images/guide/security/rbac-access-check-1.svg \"Verificação de acesso\")" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "To check if a user can update a post, you need to pass an extra parameter that's required by `AuthorRule` described before:" +msgstr "Para verificar se um usuário pode atualizar um post, você precisa passar um parâmetro extra exigido pela `AuthorRule` descrita antes:" + +#. type: Fenced code block (php) +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "" +"if ($user->can('updatePost', ['post' => $post])) {\n" +" // update post\n" +"}\n" +msgstr "" +"if ($user->can('updatePost', ['post' => $post])) {\n" +" // atualiza o post\n" +"}\n" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Here is what happens if the current user is John:" +msgstr "Veja o que acontece se o usuário atual for John:" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "![Access check](/images/guide/security/rbac-access-check-2.svg \"Access check\")" +msgstr "![Verificação de acesso](/images/guide/security/rbac-access-check-2.svg \"Verificação de acesso\")" + +#. type: Plain text +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "" +"You're starting with the `updatePost` and going through `updateOwnPost`. To pass the access check, `AuthorRule`\n" +"should return `true` from its `execute()` method. The method receives its `$params` from the `can()` method call, so the value is\n" +"`['post' => $post]`.\n" +"If everything is fine, you will get to `author` assigned to John.\n" +msgstr "" +"Você começa em `updatePost` e passa por `updateOwnPost`. Para passar na verificação de acesso, a `AuthorRule`\n" +"deve retornar `true` no método `execute()`. O método recebe seus `$params` da chamada do método `can()`, então o valor é\n" +"`['post' => $post]`.\n" +"Se tudo estiver certo, você chega a `author`, atribuído a John.\n" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "In the case of Jane, it's a bit simpler since she is an admin:" +msgstr "No caso de Jane, é um pouco mais simples, já que ela é admin:" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "![Access check](/images/guide/security/rbac-access-check-3.svg \"Access check\")" +msgstr "![Verificação de acesso](/images/guide/security/rbac-access-check-3.svg \"Verificação de acesso\")" + +#. type: Title ## +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Implementing your own access checker" +msgstr "Implementando seu próprio verificador de acesso" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "If RBAC doesn't suit your needs, you can implement your own access checker without changing the application code:" +msgstr "Se o RBAC não atende às suas necessidades, você pode implementar seu próprio verificador de acesso sem alterar o código da aplicação:" + +#. type: Fenced code block (php) +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "" +"namespace App\\User;\n" +"\n" +"use \\Yiisoft\\Access\\AccessCheckerInterface;\n" +"\n" +"final readonly class AccessChecker implements AccessCheckerInterface\n" +"{\n" +" private const PERMISSIONS = [\n" +" [\n" +" 1 => ['editPost'],\n" +" 42 => ['editPost', 'deletePost'],\n" +" ],\n" +" ];\n" +"\n" +" public function userHasPermission($userId, string $permissionName, array $parameters = []) : bool\n" +" {\n" +" if (!array_key_exists($userId, self::PERMISSIONS)) {\n" +" return false;\n" +" }\n" +"\n" +" return in_array($permissionName, self::PERMISSIONS[$userId], true); \n" +" }\n" +"}\n" +msgstr "" +"namespace App\\User;\n" +"\n" +"use \\Yiisoft\\Access\\AccessCheckerInterface;\n" +"\n" +"final readonly class AccessChecker implements AccessCheckerInterface\n" +"{\n" +" private const PERMISSIONS = [\n" +" [\n" +" 1 => ['editPost'],\n" +" 42 => ['editPost', 'deletePost'],\n" +" ],\n" +" ];\n" +"\n" +" public function userHasPermission($userId, string $permissionName, array $parameters = []) : bool\n" +" {\n" +" if (!array_key_exists($userId, self::PERMISSIONS)) {\n" +" return false;\n" +" }\n" +"\n" +" return in_array($permissionName, self::PERMISSIONS[$userId], true); \n" +" }\n" +"}\n" diff --git a/_translations/po/pt-BR/guide_security_best-practices.md.po b/_translations/po/pt-BR/guide_security_best-practices.md.po new file mode 100644 index 00000000..2070db4c --- /dev/null +++ b/_translations/po/pt-BR/guide_security_best-practices.md.po @@ -0,0 +1,534 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-06-29 17:10+0000\n" +"PO-Revision-Date: 2026-06-29 17:10+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md ../src/guide/concept/autoloading.md ../src/guide/concept/di-container.md ../src/guide/security/best-practices.md ../src/guide/structure/domain.md ../src/guide/tutorial/console-applications.md ../src/internals/004-namespaces.md ../src/internals/007-exceptions.md ../src/internals/008-interfaces.md +#, no-wrap +msgid "References" +msgstr "Referências" + +#. type: Title # +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "Security best practices" +msgstr "Boas práticas de segurança" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "Below, we'll review common security principles and describe how to avoid threats when developing applications using Yii. Most of these principles aren't unique to Yii alone but apply to website or software development in general, so you will also find links for further reading on the general ideas behind these." +msgstr "A seguir, vamos revisar princípios comuns de segurança e descrever como evitar ameaças ao desenvolver aplicações com o Yii. A maioria desses princípios não é exclusiva do Yii e vale para o desenvolvimento de sites e software em geral, por isso você também vai encontrar links para leitura adicional sobre as ideias gerais por trás deles." + +#. type: Title ## +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "Basic principles" +msgstr "Princípios básicos" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "There are two main principles when it comes to security no matter which application is being developed:" +msgstr "Há dois princípios principais quando o assunto é segurança, não importa qual aplicação esteja sendo desenvolvida:" + +#. type: Bullet: '1. ' +#: ../src/guide/security/best-practices.md +msgid "Filter input." +msgstr "Filtre a entrada." + +#. type: Bullet: '2. ' +#: ../src/guide/security/best-practices.md +msgid "Escape output." +msgstr "Escape a saída." + +#. type: Title ### +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "Filter input" +msgstr "Filtre a entrada" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "Filter input means that you should never consider input safe, and you should always check if the value you've got is actually among allowed ones. For example, if you know that you sort by three fields `title`, `created_at` and `status` and the field came from user input, it's better to check the value you've got right where you're receiving it. In terms of basic PHP, that would look like the following:" +msgstr "Filtrar a entrada significa que você nunca deve considerar uma entrada segura e deve sempre verificar se o valor recebido está de fato entre os permitidos. Por exemplo, se você sabe que a ordenação é feita por três campos, `title`, `created_at` e `status`, e o campo vem da entrada do usuário, é melhor verificar o valor no mesmo lugar em que você o recebe. Em PHP puro, isso ficaria assim:" + +#. type: Fenced code block (php) +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "" +"$sortBy = $_GET['sort'];\n" +"if (!in_array($sortBy, ['title', 'created_at', 'status'])) {\n" +"\tthrow new \\InvalidArgumentException('Invalid sort value.');\n" +"}\n" +msgstr "" +"$sortBy = $_GET['sort'];\n" +"if (!in_array($sortBy, ['title', 'created_at', 'status'])) {\n" +"\tthrow new \\InvalidArgumentException('Invalid sort value.');\n" +"}\n" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "In Yii, most probably you'll use form validation to do similar checks." +msgstr "No Yii, você provavelmente vai usar a validação de formulários para fazer verificações parecidas." + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "Further reading on the topic:" +msgstr "Leitura adicional sobre o assunto:" + +#. type: Bullet: '- ' +#: ../src/guide/security/best-practices.md +msgid "" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/security/best-practices.md +msgid "" +msgstr "" + +#. type: Title ### +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "Escape output" +msgstr "Escape a saída" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "" +"Escape output means that, depending on the context where you're using data,\n" +"you should prepend it with special characters to negate its special meaning.\n" +"In context of HTML you should escape `<`, `>` and alike special characters.\n" +"In the context of JavaScript or SQL, it will be a different set of characters.\n" +"Since it's error-prone to escape manually, Yii provides various tools to perform escaping in different contexts.\n" +msgstr "" +"Escapar a saída significa que, dependendo do contexto em que você usa os dados,\n" +"você deve prefixá-los com caracteres especiais para anular seu significado especial.\n" +"No contexto de HTML, você deve escapar `<`, `>` e caracteres especiais semelhantes.\n" +"No contexto de JavaScript ou SQL, o conjunto de caracteres será outro.\n" +"Como escapar manualmente é propenso a erros, o Yii fornece várias ferramentas para fazer o escape em diferentes contextos.\n" + +#. type: Bullet: '- ' +#: ../src/guide/security/best-practices.md +msgid "" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/security/best-practices.md +msgid "" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/security/best-practices.md +msgid "" +msgstr "" + +#. type: Title ## +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "Avoiding SQL injections" +msgstr "Evitando SQL injection" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "SQL injection happens when you form a query text by concatenating unescaped strings such as the following:" +msgstr "SQL injection acontece quando você monta o texto de uma consulta concatenando strings não escapadas, como a seguir:" + +#. type: Fenced code block (php) +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "" +"$username = $_GET['username'];\n" +"$sql = \"SELECT * FROM user WHERE username = '$username'\";\n" +msgstr "" +"$username = $_GET['username'];\n" +"$sql = \"SELECT * FROM user WHERE username = '$username'\";\n" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "Instead of supplying correct username attacker could give your applications something like `'; DROP TABLE user; --`. The Resulting SQL will be the following:" +msgstr "Em vez de informar um nome de usuário correto, um atacante pode passar para sua aplicação algo como `'; DROP TABLE user; --`. O SQL resultante será o seguinte:" + +#. type: Fenced code block (sql) +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "SELECT * FROM user WHERE username = ''; DROP TABLE user; --'\n" +msgstr "SELECT * FROM user WHERE username = ''; DROP TABLE user; --'\n" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "This is a valid query that will search for users with empty username and then will drop `user` table most probably resulting in a broken website and data loss (you've set up regular backups, right?)." +msgstr "Essa é uma consulta válida, que vai buscar usuários com nome de usuário vazio e depois apagar a tabela `user`, o que provavelmente resulta em um site quebrado e perda de dados (você configurou backups regulares, certo?)." + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "Make sure to either use PDO prepared statements directly or ensure that the library you prefer is doing it. In the case of prepared statements, it's impossible to manipulate the query as was demonstrated above." +msgstr "Use prepared statements do PDO diretamente ou garanta que a biblioteca que você prefere faça isso. Com prepared statements, é impossível manipular a consulta como demonstrado acima." + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "If you use data to specify column names or table names, the best thing to do is to allow only a predefined set of values:" +msgstr "Se você usa dados para especificar nomes de colunas ou de tabelas, o melhor é permitir apenas um conjunto predefinido de valores:" + +#. type: Fenced code block (php) +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "" +"function actionList($orderBy = null)\n" +"{\n" +" if (!in_array($orderBy, ['name', 'status'])) {\n" +" throw new \\InvalidArgumentException('Only name and status are allowed to order by.');\n" +" }\n" +" \n" +" // ...\n" +"}\n" +msgstr "" +"function actionList($orderBy = null)\n" +"{\n" +" if (!in_array($orderBy, ['name', 'status'])) {\n" +" throw new \\InvalidArgumentException('Only name and status are allowed to order by.');\n" +" }\n" +" \n" +" // ...\n" +"}\n" + +#. type: Bullet: '- ' +#: ../src/guide/security/best-practices.md +msgid "" +msgstr "" + +#. type: Title ## +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "Avoiding XSS" +msgstr "Evitando XSS" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "" +"XSS or cross-site scripting happens when output isn't escaped properly when outputting HTML to the browser. For example,\n" +"if user can enter his name and instead of `Alexander` he enters ``, every page that\n" +"outputs username without escaping it will execute JavaScript `alert('Hello!');` resulting in alert box popping up\n" +"in a browser. Depending on the website instead of innocent alert, such a script could send messages using your name or even\n" +"perform bank transactions.\n" +msgstr "" +"XSS, ou cross-site scripting, acontece quando a saída não é escapada corretamente ao enviar HTML para o navegador. Por exemplo,\n" +"se o usuário pode informar o nome dele e, em vez de `Alexander`, ele digita ``, toda página que\n" +"exibe o nome do usuário sem escapá-lo vai executar o JavaScript `alert('Hello!');`, fazendo uma caixa de alerta aparecer\n" +"no navegador. Dependendo do site, em vez de um alerta inofensivo, um script assim poderia enviar mensagens em seu nome ou até\n" +"fazer transações bancárias.\n" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "Avoiding XSS is quite easy in Yii. There are two cases:" +msgstr "Evitar XSS no Yii é bem fácil. Há dois casos:" + +#. type: Bullet: '1. ' +#: ../src/guide/security/best-practices.md +msgid "You want to output data as plain text." +msgstr "Você quer exibir os dados como texto puro." + +#. type: Bullet: '2. ' +#: ../src/guide/security/best-practices.md +msgid "You want to output data as HTML." +msgstr "Você quer exibir os dados como HTML." + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "If all you need is plain text, then escaping is as easy as the following:" +msgstr "Se tudo o que você precisa é de texto puro, escapar é tão simples quanto o seguinte:" + +#. type: Fenced code block (php) +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "\n" +msgstr "\n" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "If it should be HTML, you could get some help from [HtmlPurifier](https://github.com/ezyang/htmlpurifier). Note that HtmlPurifier processing is quite heavy, so consider adding caching." +msgstr "Se precisar ser HTML, você pode ter a ajuda do [HtmlPurifier](https://github.com/ezyang/htmlpurifier). Note que o processamento do HtmlPurifier é bem pesado, então considere usar cache." + +#. type: Title ## +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "Avoiding CSRF" +msgstr "Evitando CSRF" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "CSRF is an abbreviation for cross-site request forgery. The idea is that many applications assume that requests coming from a user browser are made by the user themselves. This assumption could be false." +msgstr "CSRF é a sigla de cross-site request forgery (falsificação de requisição entre sites). A ideia é que muitas aplicações assumem que as requisições vindas do navegador de um usuário são feitas pelo próprio usuário. Essa suposição pode ser falsa." + +#. type: Plain text +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "" +"For example, the website `an.example.com` has a `/logout` URL that, when accessed using a simple GET request, logs the user out. As long\n" +"as it's requested by the user themselves everything is OK, but one day bad guys are somehow posting\n" +"`` on a forum the user often visits. The browser doesn't make any difference between\n" +"requesting an image or requesting a page so when the user opens a page with such a manipulated `` tag,\n" +"the browser will send the GET request to that URL and the user will be logged out from `an.example.com`.\n" +msgstr "" +"Por exemplo, o site `an.example.com` tem uma URL `/logout` que, quando acessada com uma simples requisição GET, faz o logout do usuário. Enquanto\n" +"for o próprio usuário que faz a requisição, está tudo certo, mas um dia alguém mal-intencionado consegue publicar\n" +"`` em um fórum que o usuário visita com frequência. O navegador não faz diferença entre\n" +"requisitar uma imagem e requisitar uma página, então, quando o usuário abre uma página com essa tag `` manipulada,\n" +"o navegador envia a requisição GET para aquela URL e o usuário é deslogado de `an.example.com`.\n" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "" +"That's the basic idea of how a CSRF attack works. One can say that logging out a user isn't a serious thing.\n" +"However, this was just an example.\n" +"There are many more things one could do using this approach.\n" +"For example, triggering payments or changing data. Imagine that some website has a URL\n" +"`http://an.example.com/purse/transfer?to=anotherUser&amount=2000`. Accessing it using GET request, causes transfer of $2000\n" +"from an authorized user account to user `anotherUser`.\n" +"You know that the browser will always send a GET request to load an image,\n" +"so you can change the code to accept only POST requests on that URL.\n" +"Unfortunately, this won't save you, because an attacker\n" +"can put some JavaScript code instead of `` tag, which allows sending POST requests to that URL as well.\n" +msgstr "" +"Essa é a ideia básica de como um ataque CSRF funciona. Alguém pode dizer que deslogar um usuário não é grave.\n" +"Porém, isso foi só um exemplo.\n" +"Há muito mais coisas que se pode fazer com essa abordagem.\n" +"Por exemplo, disparar pagamentos ou alterar dados. Imagine que um site tem uma URL\n" +"`http://an.example.com/purse/transfer?to=anotherUser&amount=2000`. Acessá-la com uma requisição GET causa a transferência de $2000\n" +"da conta de um usuário autorizado para o usuário `anotherUser`.\n" +"Você sabe que o navegador sempre envia uma requisição GET para carregar uma imagem,\n" +"então pode alterar o código para aceitar apenas requisições POST nessa URL.\n" +"Infelizmente, isso não vai salvar você, porque um atacante\n" +"pode colocar algum código JavaScript no lugar da tag ``, o que permite enviar requisições POST para essa URL também.\n" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "For this reason, Yii applies extra mechanisms to protect against CSRF attacks." +msgstr "Por isso, o Yii aplica mecanismos extras para proteger contra ataques CSRF." + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "To avoid CSRF, you should always:" +msgstr "Para evitar CSRF, você deve sempre:" + +#. type: Bullet: '1. ' +#: ../src/guide/security/best-practices.md +msgid "Follow HTTP specification. GET shouldn't change the application state. See [RFC2616](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html) for more details." +msgstr "Seguir a especificação HTTP. GET não deve alterar o estado da aplicação. Veja a [RFC2616](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html) para mais detalhes." + +#. type: Bullet: '2. ' +#: ../src/guide/security/best-practices.md +msgid "Keep Yii CSRF protection enabled." +msgstr "Manter a proteção CSRF do Yii ativada." + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "Yii has CSRF protection via `Yiisoft\\Csrf\\CsrfTokenMiddleware` from the [`yiisoft/csrf`](https://github.com/yiisoft/csrf) package. Make sure it's in your application middleware stack. For AJAX/SPA backends that use cookie-based authentication, the same package provides `Yiisoft\\Csrf\\CsrfHeaderMiddleware` — an alternative approach that relies on custom request headers and the CORS preflight mechanism instead of token-in-form." +msgstr "O Yii tem proteção CSRF via `Yiisoft\\Csrf\\CsrfTokenMiddleware`, do pacote [`yiisoft/csrf`](https://github.com/yiisoft/csrf). Garanta que ele esteja na pilha de middlewares da sua aplicação. Para backends AJAX/SPA que usam autenticação baseada em cookie, o mesmo pacote fornece o `Yiisoft\\Csrf\\CsrfHeaderMiddleware`, uma abordagem alternativa que depende de headers de requisição personalizados e do mecanismo de preflight do CORS em vez de um token no formulário." + +#. type: Bullet: '- ' +#: ../src/guide/security/best-practices.md +msgid "" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/security/best-practices.md +msgid "" +msgstr "" + +#. type: Title ## +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "Avoiding file exposure" +msgstr "Evitando a exposição de arquivos" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "" +"By default, server webroot is meant to be pointed to `public` directory where `index.php` is. In the case of shared hosting\n" +" environments, it could be impossible to achieve, so you'll end up with all the code, configs and logs in server webroot.\n" +msgstr "" +"Por padrão, o webroot do servidor deve apontar para o diretório `public`, onde fica o `index.php`. Em ambientes de hospedagem\n" +" compartilhada, isso pode ser impossível, e você acaba com todo o código, as configurações e os logs no webroot do servidor.\n" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "If so, remember to deny access to everything except `web`. If it's impossible, consider hosting your application elsewhere." +msgstr "Nesse caso, lembre-se de negar o acesso a tudo, exceto `web`. Se isso for impossível, considere hospedar sua aplicação em outro lugar." + +#. type: Title ## +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "Avoiding debug info and tools in production" +msgstr "Evitando informações e ferramentas de debug em produção" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "In debug mode, Yii shows quite verbose errors which are certainly helpful for development. The thing is that these verbose errors are handy for attacker as well since these could reveal database structure, configuration values and parts of your code." +msgstr "No modo debug, o Yii mostra erros bem detalhados, que certamente ajudam no desenvolvimento. O problema é que esses erros detalhados também são úteis para um atacante, já que podem revelar a estrutura do banco de dados, valores de configuração e partes do seu código." + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "Never run production applications with debugger or Gii accessible to everyone. One could use it to get information about database structure, code and to simply rewrite code with what's generated by Gii." +msgstr "Nunca rode aplicações em produção com o debugger ou o Gii acessíveis a todos. Alguém poderia usá-los para obter informações sobre a estrutura do banco de dados e o código, ou simplesmente reescrever o código com o que o Gii gera." + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "You should avoid the debug toolbar in production unless necessary. It exposes all the application and config details possible. If you absolutely need it, check twice you restrict access to your IP only." +msgstr "Evite a barra de debug em produção, a menos que seja necessário. Ela expõe todos os detalhes possíveis da aplicação e da configuração. Se você realmente precisar dela, confira duas vezes se o acesso está restrito apenas ao seu IP." + +#. type: Bullet: '- ' +#: ../src/guide/security/best-practices.md +msgid "" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/security/best-practices.md +msgid "" +msgstr "" + +#. type: Title ## +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "Using secure connection over TLS" +msgstr "Usando conexão segura via TLS" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "Yii provides features that rely on cookies and/or PHP sessions. These can be vulnerable in case your connection is compromised. The risk is reduced if the app uses secure connection via TLS (often referred to as [SSL](https://en.wikipedia.org/wiki/Transport_Layer_Security))." +msgstr "O Yii fornece recursos que dependem de cookies e/ou sessões do PHP. Eles podem ficar vulneráveis caso sua conexão seja comprometida. O risco diminui se a aplicação usar conexão segura via TLS (muitas vezes chamado de [SSL](https://en.wikipedia.org/wiki/Transport_Layer_Security))." + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "Nowadays, anyone can get a certificate for free and automatically update it thanks to [Let's Encrypt](https://letsencrypt.org/)." +msgstr "Hoje em dia, qualquer pessoa pode obter um certificado de graça e renová-lo automaticamente graças ao [Let's Encrypt](https://letsencrypt.org/)." + +#. type: Title ## +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "Secure server configuration" +msgstr "Configuração segura do servidor" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "The purpose of this section is to highlight risks that need to be considered when creating a server configuration for serving a Yii-based website. Besides the points covered here, there may be other security-related configuration options to be considered, so don't consider this section to be complete." +msgstr "O objetivo desta seção é destacar os riscos que precisam ser considerados ao criar a configuração de um servidor para servir um site baseado em Yii. Além dos pontos tratados aqui, pode haver outras opções de configuração relacionadas à segurança a considerar, então não considere esta seção completa." + +#. type: Title ### +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "Avoiding `Host`-header attacks" +msgstr "Evitando ataques via header `Host`" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "If the webserver is configured to serve the same site independent of the value of the `Host` header, this information mayn't be reliable and [may be faked by the user sending the HTTP request](https://www.acunetix.com/vulnerabilities/web/host-header-attack). In such situations, you should fix your webserver configuration to serve the site only for specified host names." +msgstr "Se o servidor web estiver configurado para servir o mesmo site independentemente do valor do header `Host`, essa informação pode não ser confiável e [pode ser falsificada pelo usuário que envia a requisição HTTP](https://www.acunetix.com/vulnerabilities/web/host-header-attack). Nessas situações, você deve corrigir a configuração do servidor web para servir o site apenas para os nomes de host especificados." + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "For more information about the server configuration, please refer to the documentation of your webserver:" +msgstr "Para mais informações sobre a configuração do servidor, consulte a documentação do seu servidor web:" + +#. type: Bullet: '- ' +#: ../src/guide/security/best-practices.md +msgid "Apache 2: " +msgstr "Apache 2: " + +#. type: Bullet: '- ' +#: ../src/guide/security/best-practices.md +msgid "Nginx: " +msgstr "Nginx: " + +#. type: Title ### +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "Configuring SSL peer validation" +msgstr "Configurando a validação SSL do peer" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "There is a typical misconception about how to solve SSL certificate validation issues such as:" +msgstr "Há um equívoco comum sobre como resolver problemas de validação de certificado SSL, como:" + +#. type: Fenced code block +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "cURL error 60: SSL certificate problem: unable to get local issuer certificate\n" +msgstr "cURL error 60: SSL certificate problem: unable to get local issuer certificate\n" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "or" +msgstr "ou" + +#. type: Fenced code block +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "stream_socket_enable_crypto(): SSL operation failed with code 1. OpenSSL Error messages: error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed\n" +msgstr "stream_socket_enable_crypto(): SSL operation failed with code 1. OpenSSL Error messages: error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed\n" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "Many sources wrongly suggest disabling SSL peer verification. That shouldn't be ever done since it enables man-in-the middle type of attacks. Instead, PHP should be configured properly:" +msgstr "Muitas fontes sugerem, erroneamente, desativar a verificação SSL do peer. Isso nunca deve ser feito, porque abre caminho para ataques do tipo man-in-the-middle. Em vez disso, o PHP deve ser configurado corretamente:" + +#. type: Bullet: '1. ' +#: ../src/guide/security/best-practices.md +msgid "Download [https://curl.haxx.se/ca/cacert.pem](https://curl.haxx.se/ca/cacert.pem)." +msgstr "Baixe [https://curl.haxx.se/ca/cacert.pem](https://curl.haxx.se/ca/cacert.pem)." + +#. type: Bullet: '2. ' +#: ../src/guide/security/best-practices.md +msgid "Add the following to your php.ini:" +msgstr "Adicione o seguinte ao seu php.ini:" + +#. type: Fenced code block +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "" +" openssl.cafile=\"/path/to/cacert.pem\"\n" +" curl.cainfo=\"/path/to/cacert.pem\".\n" +msgstr "" +" openssl.cafile=\"/path/to/cacert.pem\"\n" +" curl.cainfo=\"/path/to/cacert.pem\".\n" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "Note that you should keep the file up to date." +msgstr "Note que você deve manter o arquivo atualizado." + +#. type: Bullet: '- ' +#: ../src/guide/security/best-practices.md +msgid "[OWASP top 10](https://owasp.org/Top10/)" +msgstr "[OWASP top 10](https://owasp.org/Top10/)" + +#. type: Bullet: '- ' +#: ../src/guide/security/best-practices.md +msgid "[The Basics of Web Application Security](https://martinfowler.com/articles/web-security-basics.html) by Martin Fowler" +msgstr "[The Basics of Web Application Security](https://martinfowler.com/articles/web-security-basics.html), de Martin Fowler" + +#. type: Bullet: '- ' +#: ../src/guide/security/best-practices.md +msgid "[PHP manual: security](https://www.php.net/manual/en/security.php)" +msgstr "[Manual do PHP: segurança](https://www.php.net/manual/en/security.php)" + +#. type: Bullet: '- ' +#: ../src/guide/security/best-practices.md +msgid "[Information security at STackExchange](https://security.stackexchange.com/)" +msgstr "[Segurança da informação no StackExchange](https://security.stackexchange.com/)" diff --git a/_translations/po/pt-BR/guide_security_cryptography.md.po b/_translations/po/pt-BR/guide_security_cryptography.md.po new file mode 100644 index 00000000..2feca247 --- /dev/null +++ b/_translations/po/pt-BR/guide_security_cryptography.md.po @@ -0,0 +1,258 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-09-04 08:34+0500\n" +"PO-Revision-Date: 2025-09-04 08:34+0500\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: en/security/cryptography.md +#, no-wrap +msgid "Cryptography" +msgstr "Criptografia" + +#. type: Plain text +#: en/security/cryptography.md +msgid "In this section, we'll review the following security aspects:" +msgstr "Nesta seção, vamos ver os seguintes aspectos de segurança:" + +#. type: Bullet: '- ' +#: en/security/cryptography.md +msgid "Generating random data" +msgstr "Geração de dados aleatórios" + +#. type: Bullet: '- ' +#: en/security/cryptography.md +msgid "Encryption and Decryption" +msgstr "Cifrar e decifrar dados" + +#. type: Bullet: '- ' +#: en/security/cryptography.md +msgid "Confirming Data Integrity" +msgstr "Confirmação da integridade dos dados" + +#. type: Plain text +#: en/security/cryptography.md +msgid "To use these features, you need to install `yiisoft/security` package:" +msgstr "Para usar esses recursos, você precisa instalar o pacote `yiisoft/security`:" + +#. type: Fenced code block +#: en/security/cryptography.md +#, no-wrap +msgid "composer install yiisoft/security\n" +msgstr "composer install yiisoft/security\n" + +#. type: Title ## +#: en/security/cryptography.md +#, no-wrap +msgid "Generating pseudorandom data" +msgstr "Geração de dados pseudoaleatórios" + +#. type: Plain text +#: en/security/cryptography.md +msgid "Pseudorandom data are useful in many situations. For example, when resetting a password via email, you need to generate a token, save it to the database, and send it via email to the end user, which in turn will allow them to prove ownership of that account. It's important that this token be unique and hard to guess, else there is a possibility that an attacker can predict the token's value and reset the user's password." +msgstr "Dados pseudoaleatórios são úteis em muitas situações. Por exemplo, ao redefinir uma senha por e-mail, você precisa gerar um token, salvá-lo no banco de dados e enviá-lo por e-mail ao usuário final, o que permite a ele provar que é o dono daquela conta. É importante que esse token seja único e difícil de adivinhar; caso contrário, existe a possibilidade de um atacante prever o valor do token e redefinir a senha do usuário." + +#. type: Plain text +#: en/security/cryptography.md +msgid "`\\Yiisoft\\Security\\Random` makes generating pseudorandom data simple:" +msgstr "`\\Yiisoft\\Security\\Random` torna simples gerar dados pseudoaleatórios:" + +#. type: Fenced code block (php) +#: en/security/cryptography.md +#, no-wrap +msgid "$key = \\Yiisoft\\Security\\Random::string(42);\n" +msgstr "$key = \\Yiisoft\\Security\\Random::string(42);\n" + +#. type: Plain text +#: en/security/cryptography.md +msgid "The code above would give you a random string consisting of 42 characters." +msgstr "O código acima gera uma string aleatória com 42 caracteres." + +#. type: Plain text +#: en/security/cryptography.md +msgid "If you need bytes or integers, use PHP functions directly:" +msgstr "Se você precisar de bytes ou inteiros, use as funções do PHP diretamente:" + +#. type: Bullet: '- ' +#: en/security/cryptography.md +msgid "`random_bytes()` for bytes. Note that the output may not be ASCII." +msgstr "`random_bytes()` para bytes. Note que a saída pode não ser ASCII." + +#. type: Bullet: '- ' +#: en/security/cryptography.md +msgid "`random_int()` for integers." +msgstr "`random_int()` para inteiros." + +#. type: Title ## +#: en/security/cryptography.md +#, no-wrap +msgid "Encryption and decryption" +msgstr "Cifrar e decifrar dados" + +#. type: Plain text +#: en/security/cryptography.md +msgid "Yii provides convenient helper functions to encrypt/decrypt data using a secret key. The data is passed through the encryption function so that only the person who has the secret key will be able to decrypt it. For example, you need to store some information in your database, but you need to make sure only the user who has the secret key can view it (even if one compromises the application database):" +msgstr "O Yii fornece funções auxiliares práticas para cifrar e decifrar dados usando uma chave secreta. Os dados passam pela função de cifragem de modo que apenas quem tem a chave secreta consiga decifrá-los. Por exemplo, você precisa armazenar alguma informação no banco de dados, mas precisa garantir que apenas o usuário que tem a chave secreta possa vê-la (mesmo que alguém comprometa o banco de dados da aplicação):" + +#. type: Fenced code block (php) +#: en/security/cryptography.md +#, no-wrap +msgid "" +"$encryptedData = (new \\Yiisoft\\Security\\Crypt())->encryptByPassword($data, $password);\n" +"\n" +"// save data to a database or another storage\n" +"saveData($encryptedData);\n" +msgstr "" +"$encryptedData = (new \\Yiisoft\\Security\\Crypt())->encryptByPassword($data, $password);\n" +"\n" +"// salve os dados em um banco de dados ou outro armazenamento\n" +"saveData($encryptedData);\n" + +#. type: Plain text +#: en/security/cryptography.md +msgid "Decrypting it:" +msgstr "Para decifrar:" + +#. type: Fenced code block (php) +#: en/security/cryptography.md +#, no-wrap +msgid "" +"// collect encrypted data from a database or another storage\n" +"$encryptedData = getEncryptedData();\n" +"\n" +"$data = (new \\Yiisoft\\Security\\Crypt())->decryptByPassword($encryptedData, $password);\n" +msgstr "" +"// obtenha os dados cifrados de um banco de dados ou outro armazenamento\n" +"$encryptedData = getEncryptedData();\n" +"\n" +"$data = (new \\Yiisoft\\Security\\Crypt())->decryptByPassword($encryptedData, $password);\n" + +#. type: Plain text +#: en/security/cryptography.md +msgid "You could use a key instead of a password:" +msgstr "Você pode usar uma chave em vez de uma senha:" + +#. type: Fenced code block (php) +#: en/security/cryptography.md +#, no-wrap +msgid "" +"$encryptedData = (new \\Yiisoft\\Security\\Crypt())->encryptByKey($data, $key);\n" +"\n" +"// save data to a database or another storage\n" +"saveData($encryptedData);\n" +msgstr "" +"$encryptedData = (new \\Yiisoft\\Security\\Crypt())->encryptByKey($data, $key);\n" +"\n" +"// salve os dados em um banco de dados ou outro armazenamento\n" +"saveData($encryptedData);\n" + +#. type: Fenced code block (php) +#: en/security/cryptography.md +#, no-wrap +msgid "" +"// collect encrypted data from a database or another storage\n" +"$encryptedData = getEncryptedData();\n" +"\n" +"$data = (new \\Yiisoft\\Security\\Crypt())->decryptByKey($encryptedData, $key);\n" +msgstr "" +"// obtenha os dados cifrados de um banco de dados ou outro armazenamento\n" +"$encryptedData = getEncryptedData();\n" +"\n" +"$data = (new \\Yiisoft\\Security\\Crypt())->decryptByKey($encryptedData, $key);\n" + +#. type: Title ## +#: en/security/cryptography.md +#, no-wrap +msgid "Confirming data integrity" +msgstr "Confirmação da integridade dos dados" + +#. type: Plain text +#: en/security/cryptography.md +msgid "There are situations in which you need to verify that your data hasn't been tampered with by a third party or even corrupted in some way. Yii provides a way to confirm data integrity by MAC signing." +msgstr "Há situações em que você precisa verificar se seus dados não foram adulterados por terceiros ou até corrompidos de alguma forma. O Yii oferece uma maneira de confirmar a integridade dos dados por meio de assinatura MAC." + +#. type: Plain text +#: en/security/cryptography.md +msgid "The `$key` should be present at both sending and receiving sides. On the sending side:" +msgstr "A `$key` deve estar presente tanto no lado que envia quanto no que recebe. No lado que envia:" + +#. type: Fenced code block (php) +#: en/security/cryptography.md +#, no-wrap +msgid "" +"$signedMessage = (new \\Yiisoft\\Security\\Mac())->sign($message, $key);\n" +"\n" +"sendMessage($signedMessage);\n" +msgstr "" +"$signedMessage = (new \\Yiisoft\\Security\\Mac())->sign($message, $key);\n" +"\n" +"sendMessage($signedMessage);\n" + +#. type: Plain text +#: en/security/cryptography.md +msgid "On the receiving side:" +msgstr "No lado que recebe:" + +#. type: Fenced code block (php) +#: en/security/cryptography.md +#, no-wrap +msgid "" +"$signedMessage = receiveMessage($signedMessage);\n" +"\n" +"try {\n" +" $message = (new \\Yiisoft\\Security\\Mac())->getMessage($signedMessage, $key);\n" +"} catch (\\Yiisoft\\Security\\DataIsTamperedException $e) {\n" +" // data is tampered\n" +"}\n" +msgstr "" +"$signedMessage = receiveMessage($signedMessage);\n" +"\n" +"try {\n" +" $message = (new \\Yiisoft\\Security\\Mac())->getMessage($signedMessage, $key);\n" +"} catch (\\Yiisoft\\Security\\DataIsTamperedException $e) {\n" +" // os dados foram adulterados\n" +"}\n" + +#. type: Title ## +#: en/security/cryptography.md +#, no-wrap +msgid "Masking token length" +msgstr "Mascaramento do comprimento do token" + +#. type: Plain text +#: en/security/cryptography.md +msgid "Masking a token helps to mitigate a BREACH attack by randomizing how the token outputted on each request. A random mask is applied to the token, making the string always unique." +msgstr "Mascarar um token ajuda a mitigar um ataque BREACH, tornando aleatória a forma como o token é exibido em cada requisição. Uma máscara aleatória é aplicada ao token, fazendo com que a string seja sempre única." + +#. type: Plain text +#: en/security/cryptography.md +msgid "To mask a token:" +msgstr "Para mascarar um token:" + +#. type: Fenced code block (php) +#: en/security/cryptography.md +#, no-wrap +msgid "$maskedToken = \\Yiisoft\\Security\\TokenMask::apply($token);\n" +msgstr "$maskedToken = \\Yiisoft\\Security\\TokenMask::apply($token);\n" + +#. type: Plain text +#: en/security/cryptography.md +msgid "To get the original value from the masked one:" +msgstr "Para obter o valor original a partir do mascarado:" + +#. type: Fenced code block (php) +#: en/security/cryptography.md +#, no-wrap +msgid "$token = \\Yiisoft\\Security\\TokenMask::remove($maskedToken);\n" +msgstr "$token = \\Yiisoft\\Security\\TokenMask::remove($maskedToken);\n" diff --git a/_translations/po/pt-BR/guide_security_overview.md.po b/_translations/po/pt-BR/guide_security_overview.md.po new file mode 100644 index 00000000..a26c7f2e --- /dev/null +++ b/_translations/po/pt-BR/guide_security_overview.md.po @@ -0,0 +1,67 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-09-04 11:19+0500\n" +"PO-Revision-Date: 2025-09-04 11:19+0500\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: en/security/overview.md +#, no-wrap +msgid "Security" +msgstr "Segurança" + +#. type: Plain text +#: en/security/overview.md +msgid "Good security is vital to the health and success of any application. Unfortunately, many developers cut corners when it comes to security, either due to a lack of understanding or because implementation is too much of a hurdle. To make your Yii-powered application as secure as possible, Yii has included several excellent and easy-to-use security features." +msgstr "Uma boa segurança é vital para a saúde e o sucesso de qualquer aplicação. Infelizmente, muitos desenvolvedores negligenciam a segurança, seja por falta de entendimento, seja porque a implementação parece um obstáculo grande demais. Para deixar sua aplicação Yii o mais segura possível, o Yii inclui vários recursos de segurança excelentes e fáceis de usar." + +#. type: Bullet: '* ' +#: en/security/overview.md +msgid "[Authentication](authentication.md)" +msgstr "[Autenticação](authentication.md)" + +#. type: Bullet: '* ' +#: en/security/overview.md +msgid "[Authorization](authorization.md)" +msgstr "[Autorização](authorization.md)" + +#. type: Bullet: '* ' +#: en/security/overview.md +msgid "[Working with Passwords](passwords.md)" +msgstr "[Trabalhando com senhas](passwords.md)" + +#. type: Bullet: '* ' +#: en/security/overview.md +msgid "[Cryptography](cryptography.md)" +msgstr "[Criptografia](cryptography.md)" + +#. type: Bullet: '* ' +#: en/security/overview.md +msgid "[Best Practices](best-practices.md)" +msgstr "[Boas práticas](best-practices.md)" + +#. type: Bullet: '* ' +#: en/security/overview.md +msgid "[Trusted request](trusted-request.md)" +msgstr "[Requisição confiável](trusted-request.md)" + +#. type: Plain text +#: en/security/overview.md +msgid "See also:" +msgstr "Veja também:" + +#. type: Bullet: '* ' +#: en/security/overview.md +msgid "[Views security](../views/view.md#security)" +msgstr "[Segurança de views](../views/view.md#security)" diff --git a/_translations/po/pt-BR/guide_security_passwords.md.po b/_translations/po/pt-BR/guide_security_passwords.md.po new file mode 100644 index 00000000..28100c94 --- /dev/null +++ b/_translations/po/pt-BR/guide_security_passwords.md.po @@ -0,0 +1,89 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-09-04 11:19+0500\n" +"PO-Revision-Date: 2025-09-04 11:19+0500\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: en/security/passwords.md +#, no-wrap +msgid "Working with passwords" +msgstr "Trabalhando com senhas" + +#. type: Plain text +#: en/security/passwords.md +msgid "Most developers know that passwords can't be stored in plain text, but many developers believe it's still safe to hash passwords using `md5`, `sha1` or `sha256` etc. There was a time when using the aforementioned hashing algorithms was enough, but modern hardware makes it possible to reverse such hashes and even stronger ones using brute force attacks." +msgstr "A maioria dos desenvolvedores sabe que senhas não podem ser armazenadas em texto puro, mas muitos ainda acreditam que é seguro gerar o hash de senhas com `md5`, `sha1`, `sha256` etc. Houve um tempo em que esses algoritmos de hash bastavam, mas o hardware moderno permite reverter esses hashes, e até outros mais fortes, com ataques de força bruta." + +#. type: Plain text +#: en/security/passwords.md +msgid "To offer increased security for user passwords, even in the worst case scenario (when one breaches your application), you need to use a hashing algorithm that's resilient against brute force attacks. The best current choice is `argon2`. Yii `yiisoft/security` package make securely generate and verify hashes easier and ensure the best possible hashing solution used." +msgstr "Para oferecer mais segurança às senhas dos usuários, mesmo no pior cenário (quando alguém invade sua aplicação), você precisa usar um algoritmo de hash resistente a ataques de força bruta. A melhor escolha atual é o `argon2`. O pacote `yiisoft/security` do Yii facilita gerar e verificar hashes com segurança e garante que a melhor solução de hash possível seja usada." + +#. type: Plain text +#: en/security/passwords.md +msgid "To use it, you need to require the package first:" +msgstr "Para usá-lo, primeiro instale o pacote:" + +#. type: Fenced code block +#: en/security/passwords.md +#, no-wrap +msgid "composer require yiisoft/security\n" +msgstr "composer require yiisoft/security\n" + +#. type: Plain text +#: en/security/passwords.md +msgid "When a user provides a password for the first time (e.g., upon registration), the password needs to be hashed and stored:" +msgstr "Quando um usuário fornece uma senha pela primeira vez (por exemplo, no cadastro), é preciso gerar o hash da senha e armazená-lo:" + +#. type: Fenced code block (php) +#: en/security/passwords.md +#, no-wrap +msgid "" +"$hash = (new PasswordHasher())->hash($password);\n" +"\n" +"// save hash to a database or another storage\n" +"saveHash($hash); \n" +msgstr "" +"$hash = (new PasswordHasher())->hash($password);\n" +"\n" +"// salve o hash em um banco de dados ou outro armazenamento\n" +"saveHash($hash); \n" + +#. type: Plain text +#: en/security/passwords.md +msgid "When a user attempts to log in, the submitted password must be verified against the previously hashed and stored password:" +msgstr "Quando um usuário tenta fazer login, a senha enviada deve ser verificada contra o hash armazenado anteriormente:" + +#. type: Fenced code block (php) +#: en/security/passwords.md +#, no-wrap +msgid "" +"// get hash from a database or another storage\n" +"$hash = getHash();\n" +"\n" +"if ((new PasswordHasher())->validate($password, $hash)) {\n" +" // all good, logging in user\n" +"} else {\n" +" // wrong password\n" +"}\n" +msgstr "" +"// obtenha o hash de um banco de dados ou outro armazenamento\n" +"$hash = getHash();\n" +"\n" +"if ((new PasswordHasher())->validate($password, $hash)) {\n" +" // tudo certo, fazendo login do usuário\n" +"} else {\n" +" // senha incorreta\n" +"}\n" diff --git a/_translations/po/pt-BR/guide_security_trusted-request.md.po b/_translations/po/pt-BR/guide_security_trusted-request.md.po new file mode 100644 index 00000000..0d8feb00 --- /dev/null +++ b/_translations/po/pt-BR/guide_security_trusted-request.md.po @@ -0,0 +1,88 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-09-04 11:19+0500\n" +"PO-Revision-Date: 2025-09-04 11:19+0500\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: en/security/trusted-request.md +#, no-wrap +msgid "Trusted request" +msgstr "Requisição confiável" + +#. type: Plain text +#: en/security/trusted-request.md +msgid "Getting user information, like a host and IP address, will work out of the box in a normal setup where a single webserver is used to serve the website. If your Yii application, however, runs behind a reverse proxy, you need to add configuration to retrieve this information as the direct client is now the proxy, and the user IP address is passed to the Yii application by a header set by the proxy." +msgstr "Obter informações do usuário, como host e endereço IP, funciona de imediato em uma configuração normal, em que um único servidor web atende o site. Porém, se sua aplicação Yii roda atrás de um proxy reverso, você precisa adicionar configuração para obter essas informações, já que o cliente direto passa a ser o proxy e o endereço IP do usuário é repassado para a aplicação Yii por um header definido pelo proxy." + +#. type: Plain text +#: en/security/trusted-request.md +msgid "You shouldn't blindly trust headers provided by proxies unless you explicitly trust the proxy. Yii supports configuring trusted proxies via the `Yiisoft\\Yii\\Web\\Middleware\\TrustedHostsNetworkResolver`. You should add it to [middleware stack](../structure/middleware.md)." +msgstr "Você não deve confiar cegamente nos headers fornecidos por proxies, a menos que confie explicitamente no proxy. O Yii permite configurar proxies confiáveis via `Yiisoft\\Yii\\Web\\Middleware\\TrustedHostsNetworkResolver`. Você deve adicioná-lo à [pilha de middlewares](../structure/middleware.md)." + +#. type: Plain text +#: en/security/trusted-request.md +msgid "The following is a request config for an application that runs behind an array of reverse proxies, which are located in the `10.0.2.0/24` IP network:" +msgstr "A seguir está uma configuração de requisição para uma aplicação que roda atrás de um conjunto de proxies reversos localizados na rede IP `10.0.2.0/24`:" + +#. type: Fenced code block (php) +#: en/security/trusted-request.md +#, no-wrap +msgid "" +"/** @var \\Yiisoft\\Yii\\Web\\Middleware\\TrustedHostsNetworkResolver $trustedHostsNetworkResolver */\n" +"$trustedHostsNetworkResolver = $trustedHostsNetworkResolver->withAddedTrustedHosts(['1.0.2.0/24']);\n" +msgstr "" +"/** @var \\Yiisoft\\Yii\\Web\\Middleware\\TrustedHostsNetworkResolver $trustedHostsNetworkResolver */\n" +"$trustedHostsNetworkResolver = $trustedHostsNetworkResolver->withAddedTrustedHosts(['1.0.2.0/24']);\n" + +#. type: Plain text +#: en/security/trusted-request.md +msgid "The proxy sends the IP in the `X-Forwarded-For` header by default, and the protocol (`http` or `https`) is in `X-Forwarded-Proto`." +msgstr "Por padrão, o proxy envia o IP no header `X-Forwarded-For` e o protocolo (`http` ou `https`) em `X-Forwarded-Proto`." + +#. type: Plain text +#: en/security/trusted-request.md +msgid "In case your proxies are using different headers, you can use the request configuration to adjust these, e.g.:" +msgstr "Caso seus proxies usem headers diferentes, você pode ajustá-los na configuração da requisição, por exemplo:" + +#. type: Fenced code block (php) +#: en/security/trusted-request.md +#, no-wrap +msgid "" +"/** @var \\Yiisoft\\Yii\\Web\\Middleware\\TrustedHostsNetworkResolver $trustedHostsNetworkResolver */\n" +"$trustedHostsNetworkResolver = $trustedHostsNetworkResolver\n" +" ->withAddedTrustedHosts(\n" +" ['1.0.2.0/24'],\n" +" ['X-ProxyUser-Ip'],\n" +" ['Front-End-Https'],\n" +" [],\n" +" [],\n" +" ['X-Proxy-User-Ip']\n" +" );\n" +msgstr "" +"/** @var \\Yiisoft\\Yii\\Web\\Middleware\\TrustedHostsNetworkResolver $trustedHostsNetworkResolver */\n" +"$trustedHostsNetworkResolver = $trustedHostsNetworkResolver\n" +" ->withAddedTrustedHosts(\n" +" ['1.0.2.0/24'],\n" +" ['X-ProxyUser-Ip'],\n" +" ['Front-End-Https'],\n" +" [],\n" +" [],\n" +" ['X-Proxy-User-Ip']\n" +" );\n" + +#. type: Plain text +#: en/security/trusted-request.md +msgid "With the above configuration, `X-ProxyUser-Ip` and `Front-End-Https` headers are used to get user IP and protocol." +msgstr "Com a configuração acima, os headers `X-ProxyUser-Ip` e `Front-End-Https` são usados para obter o IP e o protocolo do usuário." diff --git a/_translations/po/pt-BR/guide_start_creating-project.md.po b/_translations/po/pt-BR/guide_start_creating-project.md.po new file mode 100644 index 00000000..7d8026fb --- /dev/null +++ b/_translations/po/pt-BR/guide_start_creating-project.md.po @@ -0,0 +1,154 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-04-07 16:34+0000\n" +"PO-Revision-Date: 2026-04-07 16:34+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/start/creating-project.md +#, no-wrap +msgid "Creating a project" +msgstr "Criando um projeto" + +#. type: Plain text +#: ../src/guide/start/creating-project.md +msgid "In this guide we'll provide commands for both [Docker](https://docs.docker.com/get-started/get-docker/) and the built-in dev server with everything installed locally." +msgstr "Neste guia mostramos os comandos tanto para o [Docker](https://docs.docker.com/get-started/get-docker/) quanto para o servidor de desenvolvimento embutido, com tudo instalado localmente." + +#. type: Plain text +#: ../src/guide/start/creating-project.md +#, no-wrap +msgid "" +"> [!NOTE]\n" +"> If you want to use another web server,\n" +"> see [\"Configuring web servers\"](../../cookbook/configuring-webservers/general.md).\n" +msgstr "" +"> [!NOTE]\n" +"> Se você quiser usar outro servidor web,\n" +"> veja [\"Configurando servidores web\"](../../cookbook/configuring-webservers/general.md).\n" + +#. type: Plain text +#: ../src/guide/start/creating-project.md +msgid "We recommend starting with a project template that's a minimal working Yii project implementing some basic features. It can serve as a good starting point for your projects." +msgstr "Recomendamos começar com um template de projeto, que é um projeto Yii mínimo e funcional com alguns recursos básicos. Ele serve como um bom ponto de partida para os seus projetos." + +#. type: Plain text +#: ../src/guide/start/creating-project.md +msgid "You can create a new project from a template using the [Composer](https://getcomposer.org) package manager:" +msgstr "Você pode criar um novo projeto a partir de um template usando o gerenciador de pacotes [Composer](https://getcomposer.org):" + +#. type: Fenced code block (sh) +#: ../src/guide/start/creating-project.md +#, no-wrap +msgid "composer create-project yiisoft/app your_project\n" +msgstr "composer create-project yiisoft/app your_project\n" + +#. type: Plain text +#: ../src/guide/start/creating-project.md +msgid "Docker users can run the following commands:" +msgstr "Quem usa Docker pode rodar os seguintes comandos:" + +#. type: Fenced code block (sh) +#: ../src/guide/start/creating-project.md +#, no-wrap +msgid "" +"docker run --rm -it -v \"$(pwd):/app\" --user $(id -u):$(id -g) composer/composer create-project yiisoft/app your_project\n" +"sudo chown -R $(id -u):$(id -g) your_project\n" +"cd your_project\n" +"make composer update\n" +msgstr "" +"docker run --rm -it -v \"$(pwd):/app\" --user $(id -u):$(id -g) composer/composer create-project yiisoft/app your_project\n" +"sudo chown -R $(id -u):$(id -g) your_project\n" +"cd your_project\n" +"make composer update\n" + +#. type: Plain text +#: ../src/guide/start/creating-project.md +msgid "If you want development version instead of release one:" +msgstr "Se você quiser a versão de desenvolvimento em vez da versão de release:" + +#. type: Fenced code block (sh) +#: ../src/guide/start/creating-project.md +#, no-wrap +msgid "" +"git clone https://github.com/yiisoft/app.git --depth 1 your_project && \\\n" +"cd your_project && \\\n" +"rm -rf .git && \\\n" +"make composer update\n" +msgstr "" +"git clone https://github.com/yiisoft/app.git --depth 1 your_project && \\\n" +"cd your_project && \\\n" +"rm -rf .git && \\\n" +"make composer update\n" + +#. type: Plain text +#: ../src/guide/start/creating-project.md +msgid "This installs the latest stable version of the Yii project template in a directory named `your_project`. You can choose a different directory name if you want." +msgstr "Isso instala a versão estável mais recente do template de projeto do Yii em um diretório chamado `your_project`. Você pode escolher outro nome de diretório se quiser." + +#. type: Plain text +#: ../src/guide/start/creating-project.md +#, no-wrap +msgid "" +"> [!TIP]\n" +"> If you want to install the latest development version of Yii, you may add `--stability=dev` to the command.\n" +"> Don't use the development version of Yii for production because it may break your running code.\n" +msgstr "" +"> [!TIP]\n" +"> Se você quiser instalar a versão de desenvolvimento mais recente do Yii, pode adicionar `--stability=dev` ao comando.\n" +"> Não use a versão de desenvolvimento do Yii em produção, porque ela pode quebrar o seu código em execução.\n" + +#. type: Plain text +#: ../src/guide/start/creating-project.md +msgid "Go into the newly created directory, copy `.env.example` to `.env`, and run:" +msgstr "Entre no diretório recém-criado, copie `.env.example` para `.env` e rode:" + +#. type: Fenced code block (sh) +#: ../src/guide/start/creating-project.md +#, no-wrap +msgid "./yii serve --port=80\n" +msgstr "./yii serve --port=80\n" + +#. type: Plain text +#: ../src/guide/start/creating-project.md +msgid "For Docker users, run:" +msgstr "Se você usa Docker, rode:" + +#. type: Fenced code block (sh) +#: ../src/guide/start/creating-project.md +#, no-wrap +msgid "make up\n" +msgstr "make up\n" + +#. type: Plain text +#: ../src/guide/start/creating-project.md +msgid "Open your browser to the URL `http://localhost/`." +msgstr "Abra no navegador a URL `http://localhost/`." + +#. type: Plain text +#: ../src/guide/start/creating-project.md +#, no-wrap +msgid "" +"> [!NOTE]\n" +"> To change the port for the built-in server, pass `--port` to `./yii serve`. For Docker, set `DEV_PORT`\n" +"> in `docker/.env`.\n" +msgstr "" +"> [!NOTE]\n" +"> Para mudar a porta do servidor embutido, passe `--port` para `./yii serve`. No Docker, defina `DEV_PORT`\n" +"> em `docker/.env`.\n" + +#. type: Plain text +#: ../src/guide/start/creating-project.md +msgid "![Successful Installation of Yii](/images/guide/start/app-installed.png)" +msgstr "![Instalação do Yii concluída com sucesso](/images/guide/start/app-installed.png)" diff --git a/_translations/po/pt-BR/guide_start_databases.md.po b/_translations/po/pt-BR/guide_start_databases.md.po new file mode 100644 index 00000000..956731cd --- /dev/null +++ b/_translations/po/pt-BR/guide_start_databases.md.po @@ -0,0 +1,1837 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-10-11 10:37+0000\n" +"PO-Revision-Date: 2026-10-11 10:37+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/organizing-code/domain.md ../src/cookbook/organizing-code/service.md ../src/guide/start/databases.md +#, no-wrap +msgid "Repository" +msgstr "Repositório" + +#. type: Fenced code block (sh) +#: ../src/guide/databases/db-migrations.md ../src/guide/start/databases.md +#, no-wrap +msgid "make composer require yiisoft/db-migration\n" +msgstr "make composer require yiisoft/db-migration\n" + +#. type: Fenced code block (php) +#: ../src/guide/databases/db-migrations.md ../src/guide/start/databases.md +#, no-wrap +msgid "" +"'yiisoft/db-migration' => [\n" +" 'newMigrationNamespace' => 'App\\\\Migration',\n" +" 'sourceNamespaces' => ['App\\\\Migration'],\n" +"],\n" +msgstr "" +"'yiisoft/db-migration' => [\n" +" 'newMigrationNamespace' => 'App\\\\Migration',\n" +" 'sourceNamespaces' => ['App\\\\Migration'],\n" +"],\n" + +#. type: Title # +#: ../src/guide/index.md ../src/guide/start/databases.md +#, no-wrap +msgid "Working with databases" +msgstr "Trabalhando com bancos de dados" + +#. type: Title ### +#: ../src/guide/runtime/routing.md ../src/guide/start/databases.md +#, no-wrap +msgid "Routing" +msgstr "Roteamento" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Yii doesn't dictate using a particular database or storage for your application. There are many ways you can work with relational databases:" +msgstr "O Yii não impõe um banco de dados ou armazenamento específico para a sua aplicação. Há muitas formas de trabalhar com bancos de dados relacionais:" + +#. type: Bullet: '- ' +#: ../src/guide/start/databases.md +msgid "[Yii DB](https://github.com/yiisoft/db)" +msgstr "[Yii DB](https://github.com/yiisoft/db)" + +#. type: Bullet: '- ' +#: ../src/guide/start/databases.md +msgid "[Yii Active Record](https://github.com/yiisoft/active-record)" +msgstr "[Yii Active Record](https://github.com/yiisoft/active-record)" + +#. type: Bullet: '- ' +#: ../src/guide/start/databases.md +msgid "[Cycle](https://github.com/cycle) via [Yii Cycle package](https://github.com/yiisoft/yii-cycle)" +msgstr "[Cycle](https://github.com/cycle) pelo [pacote Yii Cycle](https://github.com/yiisoft/yii-cycle)" + +#. type: Bullet: '- ' +#: ../src/guide/start/databases.md +msgid "[Doctrine](https://www.doctrine-project.org/) via [Yii Doctrine package](https://github.com/stargazer-team/yii-doctrine)" +msgstr "[Doctrine](https://www.doctrine-project.org/) pelo [pacote Yii Doctrine](https://github.com/stargazer-team/yii-doctrine)" + +#. type: Bullet: '- ' +#: ../src/guide/start/databases.md +msgid "[PDO](https://www.php.net/manual/en/book.pdo.php)" +msgstr "[PDO](https://www.php.net/manual/en/book.pdo.php)" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "For non-relational ones, there are usually official libraries available:" +msgstr "Para os não relacionais, geralmente existem bibliotecas oficiais:" + +#. type: Bullet: '- ' +#: ../src/guide/start/databases.md +msgid "[ElasticSearch](https://github.com/elastic/elasticsearch-php)" +msgstr "[ElasticSearch](https://github.com/elastic/elasticsearch-php)" + +#. type: Bullet: '- ' +#: ../src/guide/start/databases.md +msgid "[Redis](https://redis.io/docs/latest/develop/clients/php/)" +msgstr "[Redis](https://redis.io/docs/latest/develop/clients/php/)" + +#. type: Bullet: ' - ' +#: ../src/guide/start/databases.md ../src/internals/000-packages.md +msgid "..." +msgstr "..." + +#. type: Title ## +#: ../src/guide/start/databases.md +#, no-wrap +msgid "Choosing a data access approach" +msgstr "Escolhendo uma forma de acesso aos dados" + +#. type: Plain text +#: ../src/guide/start/databases.md +#, no-wrap +msgid "" +"Yii3 keeps database access in optional packages. A new application doesn't get a global `Yii::$app->db` component\n" +"or a built-in Active Record layer automatically, so choose the package and boundary that fit your application.\n" +msgstr "" +"O Yii3 deixa o acesso ao banco de dados em pacotes opcionais. Uma aplicação nova não ganha automaticamente um componente global `Yii::$app->db`\n" +"nem uma camada de Active Record embutida, então escolha o pacote e a fronteira que fazem sentido para a sua aplicação.\n" + +#. type: Plain text +#: ../src/guide/start/databases.md +#, no-wrap +msgid "" +"If you used Yii 2.0 database access layer, `yiisoft/db` is the closest Yii3 equivalent. It provides database\n" +"connections, commands, schema support, and a query builder. Instead of calling `Yii::$app->db`, configure a\n" +"connection as a service and inject `ConnectionInterface` where the database is needed.\n" +msgstr "" +"Se você usava a camada de acesso ao banco de dados do Yii 2.0, o `yiisoft/db` é o equivalente mais próximo no Yii3. Ele oferece\n" +"conexões, comandos, suporte a esquema e um query builder. Em vez de chamar `Yii::$app->db`, configure uma\n" +"conexão como serviço e injete `ConnectionInterface` onde o banco de dados for necessário.\n" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "If you used Yii 2.0 Active Record, you can install `yiisoft/active-record`. It is useful when your model classes mostly describe tables and relations. For applications where Yii 2.0 Active Record classes also contain form validation, request scenarios, authorization checks, or business workflows, move those responsibilities to form models, services, and domain objects instead of putting them back into the record class." +msgstr "Se você usava o Active Record do Yii 2.0, pode instalar o `yiisoft/active-record`. Ele é útil quando suas classes de model descrevem principalmente tabelas e relações. Em aplicações em que as classes Active Record do Yii 2.0 também contêm validação de formulário, cenários de requisição, verificações de autorização ou fluxos de negócio, mova essas responsabilidades para form models, serviços e objetos de domínio em vez de colocá-las de volta na classe do registro." + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "For most application code, put a repository or query service between the action/service layer and storage:" +msgstr "Na maior parte do código da aplicação, coloque um repositório ou serviço de consulta entre a camada de actions/serviços e o armazenamento:" + +#. type: Bullet: '- ' +#: ../src/guide/start/databases.md +msgid "actions and application services depend on repository methods such as `findOneBySlug()`, `findAll()`, `save()`, and `deleteBySlug()`;" +msgstr "actions e serviços da aplicação dependem de métodos do repositório como `findOneBySlug()`, `findAll()`, `save()` e `deleteBySlug()`;" + +#. type: Bullet: '- ' +#: ../src/guide/start/databases.md +msgid "the repository hides whether persistence is implemented with `yiisoft/db`, Active Record, Cycle, Doctrine, or another storage;" +msgstr "o repositório esconde se a persistência é feita com `yiisoft/db`, Active Record, Cycle, Doctrine ou outro armazenamento;" + +#. type: Bullet: '- ' +#: ../src/guide/start/databases.md +msgid "the repository is the place to map raw database rows or records to typed objects used by the rest of the code." +msgstr "o repositório é o lugar para converter as linhas brutas do banco de dados ou os registros em objetos tipados usados pelo resto do código." + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Small CRUD applications can start with a concrete repository class. Larger applications usually benefit from a repository interface in the domain or module and an implementation in the infrastructure layer." +msgstr "Aplicações CRUD pequenas podem começar com uma classe de repositório concreta. Aplicações maiores costumam se beneficiar de uma interface de repositório no domínio ou módulo e de uma implementação na camada de infraestrutura." + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "In this guide, we will focus on working with relational databases using Yii DB. We'll use PostgreSQL to implement a simple CRUD (create read update delete)." +msgstr "Neste guia, vamos focar no trabalho com bancos de dados relacionais usando o Yii DB. Vamos usar PostgreSQL para implementar um CRUD simples (create, read, update, delete: criar, ler, atualizar e excluir)." + +#. type: Title ## +#: ../src/guide/start/databases.md +#, no-wrap +msgid "Installing PostgreSQL" +msgstr "Instalando o PostgreSQL" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "You need to install PostgreSQL. If you prefer not to use Docker, [get the installer from official website](https://www.postgresql.org/download/), install it and create a database." +msgstr "Você precisa instalar o PostgreSQL. Se preferir não usar Docker, [baixe o instalador no site oficial](https://www.postgresql.org/download/), instale e crie um banco de dados." + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "If you use Docker, it is a bit simpler. Modify `docker/dev/compose.yml`:" +msgstr "Se você usa Docker, é um pouco mais simples. Altere `docker/dev/compose.yml`:" + +#. type: Fenced code block (yaml) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "" +"services:\n" +" app:\n" +" build:\n" +" dockerfile: docker/Dockerfile\n" +" context: ..\n" +" target: dev\n" +" args:\n" +" USER_ID: ${UID}\n" +" GROUP_ID: ${GID}\n" +" env_file:\n" +" - path: ./dev/.env\n" +" - path: ./dev/override.env\n" +" required: false\n" +" ports:\n" +" - \"${DEV_PORT:-80}:80\"\n" +" volumes:\n" +" - ../:/app\n" +" - ../runtime:/app/runtime\n" +" - caddy_data:/data\n" +" - caddy_config:/config\n" +" tty: true\n" +" depends_on:\n" +" db:\n" +" condition: service_healthy\n" +"\n" +" db:\n" +" image: postgres:${POSTGRES_VERSION:-18}-alpine\n" +" environment:\n" +" POSTGRES_DB: app\n" +" POSTGRES_PASSWORD: password\n" +" POSTGRES_USER: user\n" +" POSTGRES_INITDB_ARGS: \"--locale-provider=icu --icu-locale=und --encoding=UTF8\"\n" +" volumes:\n" +" - ../runtime/db:/var/lib/postgresql:rw\n" +" ports:\n" +" - \"${DEV_DB_PORT:-5432}:5432\"\n" +" healthcheck:\n" +" test: [ \"CMD-SHELL\", \"pg_isready -U user -d app\" ]\n" +" interval: 5s\n" +" timeout: 5s\n" +" retries: 5\n" +msgstr "" +"services:\n" +" app:\n" +" build:\n" +" dockerfile: docker/Dockerfile\n" +" context: ..\n" +" target: dev\n" +" args:\n" +" USER_ID: ${UID}\n" +" GROUP_ID: ${GID}\n" +" env_file:\n" +" - path: ./dev/.env\n" +" - path: ./dev/override.env\n" +" required: false\n" +" ports:\n" +" - \"${DEV_PORT:-80}:80\"\n" +" volumes:\n" +" - ../:/app\n" +" - ../runtime:/app/runtime\n" +" - caddy_data:/data\n" +" - caddy_config:/config\n" +" tty: true\n" +" depends_on:\n" +" db:\n" +" condition: service_healthy\n" +"\n" +" db:\n" +" image: postgres:${POSTGRES_VERSION:-18}-alpine\n" +" environment:\n" +" POSTGRES_DB: app\n" +" POSTGRES_PASSWORD: password\n" +" POSTGRES_USER: user\n" +" POSTGRES_INITDB_ARGS: \"--locale-provider=icu --icu-locale=und --encoding=UTF8\"\n" +" volumes:\n" +" - ../runtime/db:/var/lib/postgresql:rw\n" +" ports:\n" +" - \"${DEV_DB_PORT:-5432}:5432\"\n" +" healthcheck:\n" +" test: [ \"CMD-SHELL\", \"pg_isready -U user -d app\" ]\n" +" interval: 5s\n" +" timeout: 5s\n" +" retries: 5\n" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Note that we add `depends_on` so application waits for database to be up." +msgstr "Repare que adicionamos `depends_on` para que a aplicação espere o banco de dados subir." + +#. type: Plain text +#: ../src/guide/start/databases.md +#, no-wrap +msgid "" +"> [!IMPORTANT]\n" +"> Also, we'll need a `pdo_pgsql` extension to communicate with PostgreSQL. You can enable it locally in `php.ini`.\n" +msgstr "" +"> [!IMPORTANT]\n" +"> Também vamos precisar da extensão `pdo_pgsql` para falar com o PostgreSQL. Você pode habilitá-la localmente no `php.ini`.\n" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "If you use Docker, check `docker/Dockerfile` and add `pdo_pgsql` in `install-php-extensions` list:" +msgstr "Se você usa Docker, abra `docker/Dockerfile` e adicione `pdo_pgsql` à lista do `install-php-extensions`:" + +#. type: Fenced code block (dockerfile) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "" +"RUN install-php-extensions \\\n" +" opcache \\\n" +" mbstring \\\n" +" intl \\\n" +" dom \\\n" +" ctype \\\n" +" curl \\\n" +" phar \\\n" +" openssl \\\n" +" xml \\\n" +" xmlwriter \\\n" +" simplexml \\\n" +" pdo \\\n" +" pdo_pgsql\n" +msgstr "" +"RUN install-php-extensions \\\n" +" opcache \\\n" +" mbstring \\\n" +" intl \\\n" +" dom \\\n" +" ctype \\\n" +" curl \\\n" +" phar \\\n" +" openssl \\\n" +" xml \\\n" +" xmlwriter \\\n" +" simplexml \\\n" +" pdo \\\n" +" pdo_pgsql\n" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Then rebuild PHP image with" +msgstr "Depois, reconstrua a imagem do PHP com" + +#. type: Fenced code block (sh) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "make build && make down && make up\n" +msgstr "make build && make down && make up\n" + +#. type: Title ## +#: ../src/guide/start/databases.md +#, no-wrap +msgid "Configuring connection" +msgstr "Configurando a conexão" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Now that we have the database, it's time to define the connection." +msgstr "Agora que temos o banco de dados, é hora de definir a conexão." + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "First we need a package to be installed:" +msgstr "Primeiro, precisamos instalar um pacote:" + +#. type: Fenced code block (sh) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "make composer require yiisoft/db-pgsql:2.*\n" +msgstr "make composer require yiisoft/db-pgsql:2.*\n" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Now create `config/common/di/db-pgsql.php`:" +msgstr "Agora crie `config/common/di/db-pgsql.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "" +" [\n" +" 'class' => Connection::class,\n" +" '__construct()' => [\n" +" 'driver' => new Driver(\n" +" $params['yiisoft/db-pgsql']['dsn'],\n" +" $params['yiisoft/db-pgsql']['username'],\n" +" $params['yiisoft/db-pgsql']['password'],\n" +" ),\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +" [\n" +" 'class' => Connection::class,\n" +" '__construct()' => [\n" +" 'driver' => new Driver(\n" +" $params['yiisoft/db-pgsql']['dsn'],\n" +" $params['yiisoft/db-pgsql']['username'],\n" +" $params['yiisoft/db-pgsql']['password'],\n" +" ),\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "And define parameters in `config/common/params.php`. For Docker that would be:" +msgstr "E defina os parâmetros em `config/common/params.php`. Para o Docker, fica assim:" + +#. type: Fenced code block (php) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "" +"use Yiisoft\\Db\\Pgsql\\Dsn;\n" +"\n" +"return [\n" +" // ...\n" +" 'yiisoft/db-pgsql' => [\n" +" 'dsn' => new Dsn('pgsql', 'db', 'app', '5432'),\n" +" 'username' => 'user',\n" +" 'password' => 'password',\n" +" ],\n" +"];\n" +msgstr "" +"use Yiisoft\\Db\\Pgsql\\Dsn;\n" +"\n" +"return [\n" +" // ...\n" +" 'yiisoft/db-pgsql' => [\n" +" 'dsn' => new Dsn('pgsql', 'db', 'app', '5432'),\n" +" 'username' => 'user',\n" +" 'password' => 'password',\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "`db` host is resolved automatically within the Docker network." +msgstr "O host `db` é resolvido automaticamente dentro da rede do Docker." + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "For local installation without Docker the host in Dsn would be `localhost`. You'll have to adjust the rest to match how you configured the database." +msgstr "Em uma instalação local sem Docker, o host no Dsn seria `localhost`. Ajuste o resto conforme a forma como você configurou o banco de dados." + +#. type: Title ### +#: ../src/guide/start/databases.md +#, no-wrap +msgid "Multiple database connections" +msgstr "Várias conexões de banco de dados" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "When the application works with several databases, keep `ConnectionInterface` for the primary connection and add a class alias for each named connection:" +msgstr "Quando a aplicação trabalha com vários bancos de dados, mantenha `ConnectionInterface` para a conexão principal e adicione um alias de classe para cada conexão nomeada:" + +#. type: Fenced code block (php) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "" +" MainDatabase::class,\n" +"\n" +" MainDatabase::class => [\n" +" 'class' => Connection::class,\n" +" '__construct()' => [\n" +" 'driver' => new Driver(\n" +" $params['app/db']['main']['dsn'],\n" +" $params['app/db']['main']['username'],\n" +" $params['app/db']['main']['password'],\n" +" ),\n" +" ],\n" +" ],\n" +"\n" +" AnalyticsDatabase::class => [\n" +" 'class' => Connection::class,\n" +" '__construct()' => [\n" +" 'driver' => new Driver(\n" +" $params['app/db']['analytics']['dsn'],\n" +" $params['app/db']['analytics']['username'],\n" +" $params['app/db']['analytics']['password'],\n" +" ),\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +" MainDatabase::class,\n" +"\n" +" MainDatabase::class => [\n" +" 'class' => Connection::class,\n" +" '__construct()' => [\n" +" 'driver' => new Driver(\n" +" $params['app/db']['main']['dsn'],\n" +" $params['app/db']['main']['username'],\n" +" $params['app/db']['main']['password'],\n" +" ),\n" +" ],\n" +" ],\n" +"\n" +" AnalyticsDatabase::class => [\n" +" 'class' => Connection::class,\n" +" '__construct()' => [\n" +" 'driver' => new Driver(\n" +" $params['app/db']['analytics']['dsn'],\n" +" $params['app/db']['analytics']['username'],\n" +" $params['app/db']['analytics']['password'],\n" +" ),\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "The alias class names are used as service IDs and type hints. They don't need PHP files of their own." +msgstr "Os nomes das classes alias são usados como IDs de serviço e type hints. Eles não precisam de arquivos PHP próprios." + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Define matching parameters:" +msgstr "Defina os parâmetros correspondentes:" + +#. type: Fenced code block (php) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "" +"use Yiisoft\\Db\\Pgsql\\Dsn;\n" +"\n" +"return [\n" +" // ...\n" +" 'app/db' => [\n" +" 'main' => [\n" +" 'dsn' => new Dsn('pgsql', 'db', 'app', '5432'),\n" +" 'username' => 'user',\n" +" 'password' => 'password',\n" +" ],\n" +" 'analytics' => [\n" +" 'dsn' => new Dsn('pgsql', 'analytics-db', 'analytics', '5432'),\n" +" 'username' => 'analytics_user',\n" +" 'password' => 'analytics_password',\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +"use Yiisoft\\Db\\Pgsql\\Dsn;\n" +"\n" +"return [\n" +" // ...\n" +" 'app/db' => [\n" +" 'main' => [\n" +" 'dsn' => new Dsn('pgsql', 'db', 'app', '5432'),\n" +" 'username' => 'user',\n" +" 'password' => 'password',\n" +" ],\n" +" 'analytics' => [\n" +" 'dsn' => new Dsn('pgsql', 'analytics-db', 'analytics', '5432'),\n" +" 'username' => 'analytics_user',\n" +" 'password' => 'analytics_password',\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Services that need the primary database can still depend on `ConnectionInterface`. Services that need another database should type-hint the corresponding alias:" +msgstr "Serviços que precisam do banco de dados principal continuam podendo depender de `ConnectionInterface`. Serviços que precisam de outro banco de dados devem usar o alias correspondente como type hint:" + +#. type: Fenced code block (php) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "" +"columnBuilder();\n" +"\n" +" $b->createTable('page', [\n" +" 'id' => $column::uuidPrimaryKey(),\n" +" 'title' => $column::string()->notNull(),\n" +" 'slug' => $column::string()->notNull()->unique(),\n" +" 'text' => $column::text()->notNull(),\n" +" 'created_at' => $column::dateTime(),\n" +" 'updated_at' => $column::dateTime(),\n" +" ]);\n" +" }\n" +"\n" +" public function down(MigrationBuilder $b): void\n" +" {\n" +" $b->dropTable('page');\n" +" }\n" +"}\n" +msgstr "" +"columnBuilder();\n" +"\n" +" $b->createTable('page', [\n" +" 'id' => $column::uuidPrimaryKey(),\n" +" 'title' => $column::string()->notNull(),\n" +" 'slug' => $column::string()->notNull()->unique(),\n" +" 'text' => $column::text()->notNull(),\n" +" 'created_at' => $column::dateTime(),\n" +" 'updated_at' => $column::dateTime(),\n" +" ]);\n" +" }\n" +"\n" +" public function down(MigrationBuilder $b): void\n" +" {\n" +" $b->dropTable('page');\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "The `M251102141707Page` name of the migration class is generated so replace the `Page` suffix with the actual migration name. The `M251102141707` prefix is needed to find and sort migrations in the order they were added." +msgstr "O nome `M251102141707Page` da classe da migration é gerado, então substitua o sufixo `Page` pelo nome real da migration. O prefixo `M251102141707` é necessário para encontrar e ordenar as migrations na ordem em que foram adicionadas." + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Note that we use UUID as the primary key. We are going to generate these IDs ourselves instead of relying on database so we'll need an extra compose package for that." +msgstr "Repare que usamos UUID como chave primária. Vamos gerar esses IDs nós mesmos, em vez de depender do banco de dados, então precisamos de um pacote extra do Composer para isso." + +#. type: Fenced code block (shell) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "make composer require ramsey/uuid\n" +msgstr "make composer require ramsey/uuid\n" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "While the storage space is a bit bigger than using int, the workflow with such IDs is beneficial. Since you generate the ID yourself so you can define a set of related data and save it in a single transaction. The entities that define this set of data in the code are often called an \"aggregate\"." +msgstr "O espaço de armazenamento é um pouco maior do que com int, mas o fluxo de trabalho com esse tipo de ID compensa. Como você mesmo gera o ID, pode definir um conjunto de dados relacionados e salvá-lo em uma única transação. As entidades que definem esse conjunto de dados no código costumam ser chamadas de \"agregado\"." + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Apply the migration with `make yii migrate:up`." +msgstr "Aplique a migration com `make yii migrate:up`." + +#. type: Title ## +#: ../src/guide/start/databases.md +#, no-wrap +msgid "An entity" +msgstr "Uma entidade" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Now that you have a table it is time to define an entity in the code. Create `src/Web/Page/Page.php`:" +msgstr "Agora que você tem uma tabela, é hora de definir uma entidade no código. Crie `src/Web/Page/Page.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "" +"toSlug($title),\n" +" text: $text,\n" +" createdAt: $createdAt,\n" +" updatedAt: $updatedAt,\n" +" );\n" +" }\n" +"}\n" +msgstr "" +"toSlug($title),\n" +" text: $text,\n" +" createdAt: $createdAt,\n" +" updatedAt: $updatedAt,\n" +" );\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Now that we have an entity, we need a place for methods to save it, delete it, and select either a single page or multiple pages. This is the repository boundary described earlier: the rest of the application works with `Page` objects and doesn't need to know how they are stored." +msgstr "Agora que temos uma entidade, precisamos de um lugar para os métodos que a salvam, a excluem e selecionam uma única página ou várias. Essa é a fronteira de repositório descrita antes: o resto da aplicação trabalha com objetos `Page` e não precisa saber como eles são armazenados." + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Create `src/Web/Page/PageRepository.php`:" +msgstr "Crie `src/Web/Page/PageRepository.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "" +" $page->id,\n" +" 'title' => $page->title,\n" +" 'slug' => $page->slug,\n" +" 'text' => $page->text,\n" +" 'created_at' => $page->createdAt,\n" +" 'updated_at' => $page->updatedAt,\n" +" ];\n" +"\n" +" if ($this->exists($page->id)) {\n" +" $this->connection->createCommand()->update('{{%page}}', $row, ['id' => $page->id])->execute();\n" +" } else {\n" +" $this->connection->createCommand()->insert('{{%page}}', $row)->execute();\n" +" }\n" +" }\n" +"\n" +" public function findOneBySlug(string $slug): ?Page\n" +" {\n" +" $query = $this->connection\n" +" ->select()\n" +" ->from('{{%page}}')\n" +" ->where('slug = :slug', ['slug' => $slug]);\n" +"\n" +" return $this->createPage($query->one());\n" +" }\n" +"\n" +" /**\n" +" * @return iterable\n" +" */\n" +" public function findAll(): iterable\n" +" {\n" +" $rows = $this->connection\n" +" ->select()\n" +" ->from('{{%page}}')\n" +" ->all();\n" +"\n" +" foreach ($rows as $row) {\n" +" yield $this->createPage($row);\n" +" }\n" +" }\n" +"\n" +" private function createPage(?array $row): ?Page\n" +" {\n" +" if ($row === null) {\n" +" return null;\n" +" }\n" +"\n" +" return Page::create(\n" +" id: $row['id'],\n" +" title: $row['title'],\n" +" text: $row['text'],\n" +" slug: $row['slug'],\n" +" createdAt: new DateTimeImmutable($row['created_at']),\n" +" updatedAt: new DateTimeImmutable($row['updated_at']),\n" +" );\n" +" }\n" +"\n" +" public function deleteBySlug(string $slug): void\n" +" {\n" +" $this->connection->createCommand()->delete(\n" +" '{{%page}}',\n" +" ['slug' => $slug],\n" +" )->execute();\n" +" }\n" +"\n" +" public function exists(string $id): bool\n" +" {\n" +" return $this->connection->createQuery()\n" +" ->from('{{%page}}')\n" +" ->where(['id' => $id])\n" +" ->exists();\n" +" }\n" +"}\n" +msgstr "" +" $page->id,\n" +" 'title' => $page->title,\n" +" 'slug' => $page->slug,\n" +" 'text' => $page->text,\n" +" 'created_at' => $page->createdAt,\n" +" 'updated_at' => $page->updatedAt,\n" +" ];\n" +"\n" +" if ($this->exists($page->id)) {\n" +" $this->connection->createCommand()->update('{{%page}}', $row, ['id' => $page->id])->execute();\n" +" } else {\n" +" $this->connection->createCommand()->insert('{{%page}}', $row)->execute();\n" +" }\n" +" }\n" +"\n" +" public function findOneBySlug(string $slug): ?Page\n" +" {\n" +" $query = $this->connection\n" +" ->select()\n" +" ->from('{{%page}}')\n" +" ->where('slug = :slug', ['slug' => $slug]);\n" +"\n" +" return $this->createPage($query->one());\n" +" }\n" +"\n" +" /**\n" +" * @return iterable\n" +" */\n" +" public function findAll(): iterable\n" +" {\n" +" $rows = $this->connection\n" +" ->select()\n" +" ->from('{{%page}}')\n" +" ->all();\n" +"\n" +" foreach ($rows as $row) {\n" +" yield $this->createPage($row);\n" +" }\n" +" }\n" +"\n" +" private function createPage(?array $row): ?Page\n" +" {\n" +" if ($row === null) {\n" +" return null;\n" +" }\n" +"\n" +" return Page::create(\n" +" id: $row['id'],\n" +" title: $row['title'],\n" +" text: $row['text'],\n" +" slug: $row['slug'],\n" +" createdAt: new DateTimeImmutable($row['created_at']),\n" +" updatedAt: new DateTimeImmutable($row['updated_at']),\n" +" );\n" +" }\n" +"\n" +" public function deleteBySlug(string $slug): void\n" +" {\n" +" $this->connection->createCommand()->delete(\n" +" '{{%page}}',\n" +" ['slug' => $slug],\n" +" )->execute();\n" +" }\n" +"\n" +" public function exists(string $id): bool\n" +" {\n" +" return $this->connection->createQuery()\n" +" ->from('{{%page}}')\n" +" ->where(['id' => $id])\n" +" ->exists();\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "In this repository there are both methods to get data and `save()` to do insert or update. DB returns raw data as arrays but our repository automatically creates entities from this raw data so later we operate typed data." +msgstr "Neste repositório há tanto métodos para buscar dados quanto o `save()`, que faz insert ou update. O DB retorna os dados brutos como arrays, mas o nosso repositório cria entidades automaticamente a partir deles, e daí em diante trabalhamos com dados tipados." + +#. type: Title ## +#: ../src/guide/start/databases.md +#, no-wrap +msgid "Actions and routes" +msgstr "Actions e rotas" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "We need some actions to:" +msgstr "Precisamos de algumas actions para:" + +#. type: Bullet: '1. ' +#: ../src/guide/start/databases.md +msgid "List all pages." +msgstr "Listar todas as páginas." + +#. type: Bullet: '2. ' +#: ../src/guide/start/databases.md +msgid "View a page." +msgstr "Ver uma página." + +#. type: Bullet: '3. ' +#: ../src/guide/start/databases.md +msgid "Delete a page." +msgstr "Excluir uma página." + +#. type: Bullet: '4. ' +#: ../src/guide/start/databases.md +msgid "Create a page." +msgstr "Criar uma página." + +#. type: Bullet: '5. ' +#: ../src/guide/start/databases.md +msgid "Update a page." +msgstr "Atualizar uma página." + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Then we need routing for all these." +msgstr "Depois, precisamos do roteamento para tudo isso." + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Let's tackle these one by one." +msgstr "Vamos resolver uma coisa de cada vez." + +#. type: Title ### +#: ../src/guide/start/databases.md +#, no-wrap +msgid "List all pages" +msgstr "Listar todas as páginas" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Create `src/Web/Page/ListAction.php`:" +msgstr "Crie `src/Web/Page/ListAction.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "" +"viewRenderer->render(__DIR__ . '/list', [\n" +" 'pages' => $this->pageRepository->findAll(),\n" +" ]);\n" +" }\n" +"}\n" +msgstr "" +"viewRenderer->render(__DIR__ . '/list', [\n" +" 'pages' => $this->pageRepository->findAll(),\n" +" ]);\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Define list view in `src/Web/Page/list.php`:" +msgstr "Defina a view da lista em `src/Web/Page/list.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "" +" $pages */\n" +"/** @var UrlGeneratorInterface $urlGenerator */\n" +"?>\n" +"\n" +"
    \n" +" \n" +"
  • \n" +" title, $urlGenerator->generate('page/view', ['slug' => $page->slug])) ?>\n" +"
  • \n" +" \n" +"
\n" +"\n" +"generate('page/edit', ['slug' => 'new'])) ?>\n" +msgstr "" +" $pages */\n" +"/** @var UrlGeneratorInterface $urlGenerator */\n" +"?>\n" +"\n" +"
    \n" +" \n" +"
  • \n" +" title, $urlGenerator->generate('page/view', ['slug' => $page->slug])) ?>\n" +"
  • \n" +" \n" +"
\n" +"\n" +"generate('page/edit', ['slug' => 'new'])) ?>\n" + +#. type: Title ### +#: ../src/guide/start/databases.md +#, no-wrap +msgid "View a page" +msgstr "Ver uma página" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Create `src/Web/Page/ViewAction.php`:" +msgstr "Crie `src/Web/Page/ViewAction.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "" +"pageRepository->findOneBySlug($slug);\n" +" if ($page === null) {\n" +" return $this->responseFactory->createResponse(Status::NOT_FOUND);\n" +" }\n" +"\n" +" return $this->viewRenderer->render(__DIR__ . '/view', [\n" +" 'page' => $page,\n" +" ]);\n" +" }\n" +"}\n" +msgstr "" +"pageRepository->findOneBySlug($slug);\n" +" if ($page === null) {\n" +" return $this->responseFactory->createResponse(Status::NOT_FOUND);\n" +" }\n" +"\n" +" return $this->viewRenderer->render(__DIR__ . '/view', [\n" +" 'page' => $page,\n" +" ]);\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Now, a template in `src/Web/Page/view.php`:" +msgstr "Agora, um template em `src/Web/Page/view.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "" +"\n" +"\n" +"

generate('page/list')) ?> → title) ?>

\n" +"\n" +"

\n" +" text) ?>\n" +"

\n" +"\n" +"generate('page/edit', ['slug' => $page->slug])) ?> |\n" +"\n" +"\n" +"post($urlGenerator->generate('page/delete', ['slug' => $page->slug]))\n" +" ->csrf($csrf);\n" +"?>\n" +"open() ?>\n" +" \n" +"close() ?>\n" +msgstr "" +"\n" +"\n" +"

generate('page/list')) ?> → title) ?>

\n" +"\n" +"

\n" +" text) ?>\n" +"

\n" +"\n" +"generate('page/edit', ['slug' => $page->slug])) ?> |\n" +"\n" +"\n" +"post($urlGenerator->generate('page/delete', ['slug' => $page->slug]))\n" +" ->csrf($csrf);\n" +"?>\n" +"open() ?>\n" +" \n" +"close() ?>\n" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "In this view we have a form that submits a request for page deletion. Handing it with `GET` is common as well, but it is very wrong. Since deletion changes data, it needs to be handled by one of the non-idempotent HTTP methods. We use POST and a form in our example, but it could be `DELETE` and async request made with JavaScript. The button could be later styled properly to look similar to the \"Edit\"." +msgstr "Nesta view há um formulário que envia uma requisição para excluir a página. Tratar isso com `GET` também é comum, mas é muito errado. Como a exclusão altera dados, ela precisa ser tratada por um dos métodos HTTP não idempotentes. No nosso exemplo usamos POST e um formulário, mas poderia ser `DELETE` e uma requisição assíncrona feita com JavaScript. Depois, o botão pode ganhar um estilo adequado para ficar parecido com o \"Edit\"." + +#. type: Title ### +#: ../src/guide/start/databases.md +#, no-wrap +msgid "Delete a page" +msgstr "Excluir uma página" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Create `src/Web/Page/DeleteAction.php`:" +msgstr "Crie `src/Web/Page/DeleteAction.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "" +"pageRepository->deleteBySlug($slug);\n" +"\n" +" return $this->responseFactory\n" +" ->createResponse(Status::SEE_OTHER)\n" +" ->withHeader('Location', $this->urlGenerator->generate('page/list'));\n" +" }\n" +"}\n" +msgstr "" +"pageRepository->deleteBySlug($slug);\n" +"\n" +" return $this->responseFactory\n" +" ->createResponse(Status::SEE_OTHER)\n" +" ->withHeader('Location', $this->urlGenerator->generate('page/list'));\n" +" }\n" +"}\n" + +#. type: Title ### +#: ../src/guide/start/databases.md +#, no-wrap +msgid "Create or update a page" +msgstr "Criar ou atualizar uma página" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "First of all, we need a form at `src/Web/Page/Form.php`:" +msgstr "Antes de tudo, precisamos de um formulário em `src/Web/Page/Form.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "" +"findOneBySlug($slug);\n" +" if ($page === null) {\n" +" return $this->responseFactory->createResponse(Status::NOT_FOUND);\n" +" }\n" +"\n" +" $form->title = $page->title;\n" +" $form->text = $page->text;\n" +" }\n" +"\n" +" $this->formHydrator->populateFromPostAndValidate($form, $request);\n" +"\n" +" if ($form->isValid()) {\n" +" $id = $isNew ? Uuid::uuid7()->toString() : $page->id;\n" +"\n" +" $page = Page::create(\n" +" id: $id,\n" +" title: $form->title,\n" +" text: $form->text,\n" +" );\n" +"\n" +" $pageRepository->save($page);\n" +"\n" +" return $this->responseFactory\n" +" ->createResponse(Status::SEE_OTHER)\n" +" ->withHeader(\n" +" 'Location',\n" +" $this->urlGenerator->generate('page/view', ['slug' => $page->slug]),\n" +" );\n" +" }\n" +"\n" +" return $this->viewRenderer->render(__DIR__ . '/edit', [\n" +" 'form' => $form,\n" +" 'isNew' => $isNew,\n" +" 'slug' => $slug,\n" +" ]);\n" +" }\n" +"}\n" +msgstr "" +"findOneBySlug($slug);\n" +" if ($page === null) {\n" +" return $this->responseFactory->createResponse(Status::NOT_FOUND);\n" +" }\n" +"\n" +" $form->title = $page->title;\n" +" $form->text = $page->text;\n" +" }\n" +"\n" +" $this->formHydrator->populateFromPostAndValidate($form, $request);\n" +"\n" +" if ($form->isValid()) {\n" +" $id = $isNew ? Uuid::uuid7()->toString() : $page->id;\n" +"\n" +" $page = Page::create(\n" +" id: $id,\n" +" title: $form->title,\n" +" text: $form->text,\n" +" );\n" +"\n" +" $pageRepository->save($page);\n" +"\n" +" return $this->responseFactory\n" +" ->createResponse(Status::SEE_OTHER)\n" +" ->withHeader(\n" +" 'Location',\n" +" $this->urlGenerator->generate('page/view', ['slug' => $page->slug]),\n" +" );\n" +" }\n" +"\n" +" return $this->viewRenderer->render(__DIR__ . '/edit', [\n" +" 'form' => $form,\n" +" 'isNew' => $isNew,\n" +" 'slug' => $slug,\n" +" ]);\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/start/databases.md +#, no-wrap +msgid "Note that `Uuid::uuid7()->toString()` won't work for MySQL and you'll need bytes instead, `Uuid::uuid7()->getBytes()`.\n" +msgstr "Repare que `Uuid::uuid7()->toString()` não funciona no MySQL; lá você vai precisar dos bytes, com `Uuid::uuid7()->getBytes()`.\n" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "In the above we use a special slug in the URL for new pages so the URL looks like `http://localhost/pages/new`. If the page isn't new, we pre-fill the form with the data from the database. Similar to how we did in [Working with forms](forms.md), we handle the form submission. After successful save we redirect to the page view." +msgstr "Acima, usamos um slug especial na URL para páginas novas, então a URL fica como `http://localhost/pages/new`. Se a página não for nova, preenchemos o formulário com os dados do banco de dados. Assim como fizemos em [Trabalhando com formulários](forms.md), tratamos o envio do formulário. Depois de salvar com sucesso, redirecionamos para a view da página." + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Now, a template in `src/Web/Page/edit.php`:" +msgstr "Agora, um template em `src/Web/Page/edit.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "" +"post($urlGenerator->generate('page/edit', ['slug' => $slug]))\n" +" ->csrf($csrf);\n" +"?>\n" +"\n" +"open() ?>\n" +" required() ?>\n" +" required() ?>\n" +" \n" +"close() ?>\n" +msgstr "" +"post($urlGenerator->generate('page/edit', ['slug' => $slug]))\n" +" ->csrf($csrf);\n" +"?>\n" +"\n" +"open() ?>\n" +" required() ?>\n" +" required() ?>\n" +" \n" +"close() ?>\n" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Adjust `config/common/routes.php`:" +msgstr "Ajuste `config/common/routes.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "" +"routes(\n" +" Route::get('/')\n" +" ->action(Web\\HomePage\\Action::class)\n" +" ->name('home'),\n" +" Route::methods([Method::GET, Method::POST], '/say')\n" +" ->action(Web\\Echo\\Action::class)\n" +" ->name('echo/say'),\n" +"\n" +" Group::create('/pages')->routes(\n" +" Route::get('')\n" +" ->action(Web\\Page\\ListAction::class)\n" +" ->name('page/list'),\n" +" Route::get('/{slug}')\n" +" ->action(Web\\Page\\ViewAction::class)\n" +" ->name('page/view'),\n" +" Route::methods([Method::GET, Method::POST], '/{slug}/edit')\n" +" ->action(Web\\Page\\EditAction::class)\n" +" ->name('page/edit'),\n" +" Route::post('/{slug}/delete')\n" +" ->action(Web\\Page\\DeleteAction::class)\n" +" ->name('page/delete'),\n" +" ),\n" +" ),\n" +"];\n" +msgstr "" +"routes(\n" +" Route::get('/')\n" +" ->action(Web\\HomePage\\Action::class)\n" +" ->name('home'),\n" +" Route::methods([Method::GET, Method::POST], '/say')\n" +" ->action(Web\\Echo\\Action::class)\n" +" ->name('echo/say'),\n" +"\n" +" Group::create('/pages')->routes(\n" +" Route::get('')\n" +" ->action(Web\\Page\\ListAction::class)\n" +" ->name('page/list'),\n" +" Route::get('/{slug}')\n" +" ->action(Web\\Page\\ViewAction::class)\n" +" ->name('page/view'),\n" +" Route::methods([Method::GET, Method::POST], '/{slug}/edit')\n" +" ->action(Web\\Page\\EditAction::class)\n" +" ->name('page/edit'),\n" +" Route::post('/{slug}/delete')\n" +" ->action(Web\\Page\\DeleteAction::class)\n" +" ->name('page/delete'),\n" +" ),\n" +" ),\n" +"];\n" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Note that we've grouped all page-related routes with a group under `/pages` prefix. That is a convenient way to both not to repeat yourself and add some extra middleware, such as authentication, to the whole group." +msgstr "Repare que agrupamos todas as rotas relacionadas a páginas em um grupo com o prefixo `/pages`. É uma forma prática de não se repetir e também de adicionar algum middleware extra, como autenticação, ao grupo inteiro." + +#. type: Title ## +#: ../src/guide/start/databases.md ../src/guide/start/hello.md +#, no-wrap +msgid "Trying it out" +msgstr "Testando" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Now try it out by opening `http://localhost/pages` in your browser." +msgstr "Agora teste abrindo `http://localhost/pages` no navegador." diff --git a/_translations/po/pt-BR/guide_start_demo-apps.md.po b/_translations/po/pt-BR/guide_start_demo-apps.md.po new file mode 100644 index 00000000..bbdb705c --- /dev/null +++ b/_translations/po/pt-BR/guide_start_demo-apps.md.po @@ -0,0 +1,60 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-06-05 10:18+0000\n" +"PO-Revision-Date: 2026-06-05 10:18+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/start/demo-apps.md +#, no-wrap +msgid "Demo Applications" +msgstr "Aplicações de demonstração" + +#. type: Plain text +#: ../src/guide/start/demo-apps.md +msgid "There are several demo applications that showcase different architectural approaches and framework capabilities." +msgstr "Existem várias aplicações de demonstração que mostram diferentes abordagens de arquitetura e recursos do framework." + +#. type: Plain text +#: ../src/guide/start/demo-apps.md +#, no-wrap +msgid "**[Demo Blog](https://github.com/yiisoft/demo-blog) — Layered DDD architecture**\n" +msgstr "**[Demo Blog](https://github.com/yiisoft/demo-blog) — Arquitetura DDD em camadas**\n" + +#. type: Plain text +#: ../src/guide/start/demo-apps.md +msgid "A blog application demonstrating a layered architecture following Domain-Driven Design (DDD) principles. This demo is a good starting point if you want to learn how to structure a Yii3 application with a clear separation of concerns between domain, application, and infrastructure layers." +msgstr "Uma aplicação de blog que demonstra uma arquitetura em camadas seguindo os princípios do Domain-Driven Design (DDD). Esta demo é um bom ponto de partida se você quer aprender a estruturar uma aplicação Yii3 com uma separação clara de responsabilidades entre as camadas de domínio, aplicação e infraestrutura." + +#. type: Plain text +#: ../src/guide/start/demo-apps.md +#, no-wrap +msgid "**[Demo Diary](https://github.com/yiisoft/demo-diary) — Vertical slices architecture**\n" +msgstr "**[Demo Diary](https://github.com/yiisoft/demo-diary) — Arquitetura de vertical slices**\n" + +#. type: Plain text +#: ../src/guide/start/demo-apps.md +msgid "A diary application built using the vertical slices architecture pattern. In this approach, each feature is implemented end-to-end rather than being split across horizontal layers, making it easier to add or modify features independently." +msgstr "Uma aplicação de diário construída com o padrão de arquitetura de vertical slices. Nessa abordagem, cada funcionalidade é implementada de ponta a ponta em vez de ser dividida em camadas horizontais, o que facilita adicionar ou modificar funcionalidades de forma independente." + +#. type: Plain text +#: ../src/guide/start/demo-apps.md +#, no-wrap +msgid "**[Demo Summarizer](https://github.com/yiisoft/demo-summarizer) — Large language model (LLM) document summarizer**\n" +msgstr "**[Demo Summarizer](https://github.com/yiisoft/demo-summarizer) — Resumidor de documentos com modelo de linguagem (LLM)**\n" + +#. type: Plain text +#: ../src/guide/start/demo-apps.md +msgid "A runnable Yii3 demo for uploading documents, extracting readable Markdown, summarizing content, and tracking processing progress." +msgstr "Uma demo executável do Yii3 para enviar documentos, extrair Markdown legível, resumir o conteúdo e acompanhar o progresso do processamento." diff --git a/_translations/po/pt-BR/guide_start_forms.md.po b/_translations/po/pt-BR/guide_start_forms.md.po new file mode 100644 index 00000000..442bc1db --- /dev/null +++ b/_translations/po/pt-BR/guide_start_forms.md.po @@ -0,0 +1,799 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-06-30 09:05+0000\n" +"PO-Revision-Date: 2026-06-30 09:05+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md ../src/guide/start/forms.md ../src/guide/start/hello.md +#, no-wrap +msgid "Summary" +msgstr "Resumo" + +#. type: Title # +#: ../src/guide/start/forms.md +#, no-wrap +msgid "Working with forms" +msgstr "Trabalhando com formulários" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "This section continues to improve on \"Saying Hello.\" Instead of using URL, you will now ask a user for a message via form." +msgstr "Esta seção continua a melhorar o \"Dizendo olá\". Em vez de usar a URL, agora você vai pedir a mensagem ao usuário por meio de um formulário." + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "Through this tutorial, you will learn how to:" +msgstr "Neste tutorial, você vai aprender a:" + +#. type: Bullet: '* ' +#: ../src/guide/start/forms.md +msgid "Create a form model to represent the data entered by a user through a form." +msgstr "Criar um form model para representar os dados que o usuário informa em um formulário." + +#. type: Bullet: '* ' +#: ../src/guide/start/forms.md +msgid "Declare rules to validate the data entered." +msgstr "Declarar regras para validar os dados informados." + +#. type: Bullet: '* ' +#: ../src/guide/start/forms.md +msgid "Build an HTML form in a view." +msgstr "Montar um formulário HTML em uma view." + +#. type: Title ## +#: ../src/guide/start/forms.md +#, no-wrap +msgid "Installing form package" +msgstr "Instalando o pacote de formulários" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "To install form package, issue the following command in your application directory:" +msgstr "Para instalar o pacote de formulários, rode o seguinte comando no diretório da sua aplicação:" + +#. type: Fenced code block +#: ../src/guide/start/forms.md +#, no-wrap +msgid "composer require yiisoft/form-model\n" +msgstr "composer require yiisoft/form-model\n" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "For Docker that would be:" +msgstr "No Docker, fica assim:" + +#. type: Fenced code block +#: ../src/guide/start/forms.md +#, no-wrap +msgid "make composer require yiisoft/form-model\n" +msgstr "make composer require yiisoft/form-model\n" + +#. type: Title ## +#: ../src/guide/start/forms.md +#, no-wrap +msgid "Creating a form" +msgstr "Criando um formulário" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "The data to be requested from the user will be represented by a `Form` class as shown below and saved in the file `/src/Web/Echo/Form.php`:" +msgstr "Os dados que serão pedidos ao usuário ficam representados por uma classe `Form`, como mostrado abaixo, salva no arquivo `/src/Web/Echo/Form.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/start/forms.md +#, no-wrap +msgid "" +" Note: Validation attributes are Yii Validator rules. For common checks, first look for an existing rule. If a field\n" +"> also needs application-specific validation, use `Callback` for that domain logic. With PHP attributes, use the `method`\n" +"> option because PHP attributes can't contain closures. For example, validate UUID syntax with `Uuid`, then add\n" +"> `#[Callback(method: 'validateUuidV7', skipOnError: true)]` only when your domain specifically requires UUID version 7.\n" +msgstr "" +"> Nota: os atributos de validação são regras do Yii Validator. Para verificações comuns, procure primeiro uma regra existente. Se um campo\n" +"> também precisar de validação específica da aplicação, use `Callback` para essa lógica de domínio. Com atributos PHP, use a opção `method`,\n" +"> porque atributos PHP não podem conter closures. Por exemplo, valide a sintaxe do UUID com `Uuid` e só então adicione\n" +"> `#[Callback(method: 'validateUuidV7', skipOnError: true)]` quando o seu domínio exigir especificamente UUID versão 7.\n" + +#. type: Fenced code block (php) +#: ../src/guide/start/forms.md +#, no-wrap +msgid "" +"use Yiisoft\\Validator\\Result;\n" +"use Yiisoft\\Validator\\Rule\\Callback;\n" +"use Yiisoft\\Validator\\Rule\\Uuid;\n" +"\n" +"#[Uuid(skipOnError: true)]\n" +"#[Callback(method: 'validateUuidV7', skipOnError: true)]\n" +"public string $id = '';\n" +"\n" +"private function validateUuidV7(mixed $value): Result\n" +"{\n" +" return \\App\\Support\\Uuid::isVersion7($value)\n" +" ? new Result()\n" +" : (new Result())->addError('ID must be a UUID version 7.');\n" +"}\n" +msgstr "" +"use Yiisoft\\Validator\\Result;\n" +"use Yiisoft\\Validator\\Rule\\Callback;\n" +"use Yiisoft\\Validator\\Rule\\Uuid;\n" +"\n" +"#[Uuid(skipOnError: true)]\n" +"#[Callback(method: 'validateUuidV7', skipOnError: true)]\n" +"public string $id = '';\n" +"\n" +"private function validateUuidV7(mixed $value): Result\n" +"{\n" +" return \\App\\Support\\Uuid::isVersion7($value)\n" +" ? new Result()\n" +" : (new Result())->addError('ID must be a UUID version 7.');\n" +"}\n" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "The callback method returns a `Result`: return an empty result when the value is valid or add an error when it isn't. The method body can call any validation code your application already uses, such as `App\\Support\\Uuid::isValid($value, 'v7')`. See [Callback rule details](https://github.com/yiisoft/validator/blob/master/docs/guide/en/built-in-rules-callback.md) for full examples and available method signatures." +msgstr "O método de callback retorna um `Result`: retorne um resultado vazio quando o valor for válido ou adicione um erro quando não for. O corpo do método pode chamar qualquer código de validação que a sua aplicação já usa, como `App\\Support\\Uuid::isValid($value, 'v7')`. Veja os [detalhes da regra Callback](https://github.com/yiisoft/validator/blob/master/docs/guide/en/built-in-rules-callback.md) para exemplos completos e as assinaturas de método disponíveis." + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "For validation logic reused in several forms, create a custom Yii Validator rule and handler instead of copying callback methods. See the [custom rule guide](https://github.com/yiisoft/validator/blob/master/docs/guide/en/creating-custom-rules.md) for the rule/handler structure." +msgstr "Para uma lógica de validação reaproveitada em vários formulários, crie uma regra e um handler personalizados do Yii Validator em vez de copiar métodos de callback. Veja o [guia de regras personalizadas](https://github.com/yiisoft/validator/blob/master/docs/guide/en/creating-custom-rules.md) para a estrutura de regra/handler." + +#. type: Title ## +#: ../src/guide/start/forms.md +#, no-wrap +msgid "Custom validation" +msgstr "Validação personalizada" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "Validation attributes are Yii Validator rules. For common checks, first look for an existing rule. For example, to validate a UUID string, use `Uuid`:" +msgstr "Os atributos de validação são regras do Yii Validator. Para verificações comuns, procure primeiro uma regra existente. Por exemplo, para validar uma string UUID, use `Uuid`:" + +#. type: Fenced code block (php) +#: ../src/guide/start/forms.md +#, no-wrap +msgid "" +"use Yiisoft\\FormModel\\FormModel;\n" +"use Yiisoft\\Validator\\Rule\\Uuid;\n" +"\n" +"final class Form extends FormModel\n" +"{\n" +" #[Uuid]\n" +" public string $id = '';\n" +"}\n" +msgstr "" +"use Yiisoft\\FormModel\\FormModel;\n" +"use Yiisoft\\Validator\\Rule\\Uuid;\n" +"\n" +"final class Form extends FormModel\n" +"{\n" +" #[Uuid]\n" +" public string $id = '';\n" +"}\n" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "When a field needs application-specific validation that isn't covered by a built-in rule, use `Callback`. This is useful for one-off checks or for delegating to a domain/library method. With PHP attributes, use the `method` option because PHP attributes can't contain closures. For example, the following form validates a card number checksum:" +msgstr "Quando um campo precisa de uma validação específica da aplicação que nenhuma regra embutida cobre, use `Callback`. Isso é útil para verificações pontuais ou para delegar a um método do domínio ou de uma biblioteca. Com atributos PHP, use a opção `method`, porque atributos PHP não podem conter closures. Por exemplo, o formulário a seguir valida o dígito verificador de um número de cartão:" + +#. type: Fenced code block (php) +#: ../src/guide/start/forms.md +#, no-wrap +msgid "" +"addError('Card number must be a string.');\n" +" }\n" +"\n" +" $digits = str_replace([' ', '-'], '', $value);\n" +"\n" +" if ($digits === '' || !ctype_digit($digits)) {\n" +" return (new Result())->addError('Card number must contain digits only.');\n" +" }\n" +"\n" +" $sum = 0;\n" +" $double = false;\n" +"\n" +" foreach (array_reverse(str_split($digits)) as $digit) {\n" +" $number = (int) $digit;\n" +"\n" +" if ($double) {\n" +" $number *= 2;\n" +" if ($number > 9) {\n" +" $number -= 9;\n" +" }\n" +" }\n" +"\n" +" $sum += $number;\n" +" $double = !$double;\n" +" }\n" +"\n" +" if ($sum % 10 !== 0) {\n" +" return (new Result())->addError('Card number checksum is invalid.');\n" +" }\n" +"\n" +" return new Result();\n" +" }\n" +"}\n" +msgstr "" +"addError('Card number must be a string.');\n" +" }\n" +"\n" +" $digits = str_replace([' ', '-'], '', $value);\n" +"\n" +" if ($digits === '' || !ctype_digit($digits)) {\n" +" return (new Result())->addError('Card number must contain digits only.');\n" +" }\n" +"\n" +" $sum = 0;\n" +" $double = false;\n" +"\n" +" foreach (array_reverse(str_split($digits)) as $digit) {\n" +" $number = (int) $digit;\n" +"\n" +" if ($double) {\n" +" $number *= 2;\n" +" if ($number > 9) {\n" +" $number -= 9;\n" +" }\n" +" }\n" +"\n" +" $sum += $number;\n" +" $double = !$double;\n" +" }\n" +"\n" +" if ($sum % 10 !== 0) {\n" +" return (new Result())->addError('Card number checksum is invalid.');\n" +" }\n" +"\n" +" return new Result();\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "The callback method returns a `Result`: return an empty result when the value is valid or add an error when it isn't. The method body can call any validation code your application already uses, such as `App\\Payment\\CardNumber::hasValidChecksum($value)`." +msgstr "O método de callback retorna um `Result`: retorne um resultado vazio quando o valor for válido ou adicione um erro quando não for. O corpo do método pode chamar qualquer código de validação que a sua aplicação já usa, como `App\\Payment\\CardNumber::hasValidChecksum($value)`." + +#. type: Title ## +#: ../src/guide/start/forms.md +#, no-wrap +msgid "Validating several fields together" +msgstr "Validando vários campos juntos" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "Property attributes are enough when each field can be validated independently. When a rule depends on several fields, put a `Callback` rule on the form model class and attach an error to the field that should display it." +msgstr "Atributos nas propriedades bastam quando cada campo pode ser validado de forma independente. Quando uma regra depende de vários campos, coloque uma regra `Callback` na classe do form model e associe o erro ao campo que deve exibi-lo." + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "For example, a report filter may require the start date to be earlier than or equal to the end date:" +msgstr "Por exemplo, um filtro de relatório pode exigir que a data inicial seja anterior ou igual à data final:" + +#. type: Fenced code block (php) +#: ../src/guide/start/forms.md +#, no-wrap +msgid "" +"dateFrom === '' || $this->dateTo === '') {\n" +" return $result;\n" +" }\n" +"\n" +" $dateFrom = $this->parseDate($this->dateFrom);\n" +" $dateTo = $this->parseDate($this->dateTo);\n" +"\n" +" if ($dateFrom === null || $dateTo === null) {\n" +" return $result;\n" +" }\n" +"\n" +" if ($dateFrom > $dateTo) {\n" +" $result->addError('The start date must be earlier than or equal to the end date.', [], ['dateFrom']);\n" +" }\n" +"\n" +" return $result;\n" +" }\n" +"\n" +" private function parseDate(string $value): ?DateTimeImmutable\n" +" {\n" +" $date = DateTimeImmutable::createFromFormat('!Y-m-d', $value);\n" +" $errors = DateTimeImmutable::getLastErrors();\n" +"\n" +" if ($date === false || ($errors !== false && ($errors['warning_count'] > 0 || $errors['error_count'] > 0))) {\n" +" return null;\n" +" }\n" +"\n" +" return $date;\n" +" }\n" +"}\n" +msgstr "" +"dateFrom === '' || $this->dateTo === '') {\n" +" return $result;\n" +" }\n" +"\n" +" $dateFrom = $this->parseDate($this->dateFrom);\n" +" $dateTo = $this->parseDate($this->dateTo);\n" +"\n" +" if ($dateFrom === null || $dateTo === null) {\n" +" return $result;\n" +" }\n" +"\n" +" if ($dateFrom > $dateTo) {\n" +" $result->addError('The start date must be earlier than or equal to the end date.', [], ['dateFrom']);\n" +" }\n" +"\n" +" return $result;\n" +" }\n" +"\n" +" private function parseDate(string $value): ?DateTimeImmutable\n" +" {\n" +" $date = DateTimeImmutable::createFromFormat('!Y-m-d', $value);\n" +" $errors = DateTimeImmutable::getLastErrors();\n" +"\n" +" if ($date === false || ($errors !== false && ($errors['warning_count'] > 0 || $errors['error_count'] > 0))) {\n" +" return null;\n" +" }\n" +"\n" +" return $date;\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "The class-level `Callback` receives the whole object as `$value`, but using `$this` is usually clearer in a form model method. Returning an empty `Result` means the cross-field rule passed. The third argument of `addError()` is the value path; `['dateFrom']` makes the error appear on the `dateFrom` field when rendering the form." +msgstr "O `Callback` no nível da classe recebe o objeto inteiro como `$value`, mas usar `$this` costuma ser mais claro em um método do form model. Retornar um `Result` vazio significa que a regra entre campos passou. O terceiro argumento de `addError()` é o caminho do valor; `['dateFrom']` faz o erro aparecer no campo `dateFrom` quando o formulário é renderizado." + +#. type: Title ## +#: ../src/guide/start/forms.md +#, no-wrap +msgid "Using the form " +msgstr "Usando o formulário" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "Now that you have a form, use it in your action from \"[Saying Hello](hello.md)\"." +msgstr "Agora que você tem um formulário, use-o na sua action do \"[Dizendo olá](hello.md)\"." + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "Here's what you end up with in `/src/Web/Echo/Action.php`:" +msgstr "Este é o resultado final em `/src/Web/Echo/Action.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/start/forms.md +#, no-wrap +msgid "" +"formHydrator->populateFromPostAndValidate($form, $request);\n" +"\n" +" return $this->viewRenderer->render(__DIR__ . '/template', [\n" +" 'form' => $form,\n" +" ]);\n" +" }\n" +"}\n" +msgstr "" +"formHydrator->populateFromPostAndValidate($form, $request);\n" +"\n" +" return $this->viewRenderer->render(__DIR__ . '/template', [\n" +" 'form' => $form,\n" +" ]);\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "Instead of reading from route, you fill your form from request's POST data and validate it with the help of `FormHydrator`. Next you pass the form to the view." +msgstr "Em vez de ler da rota, você preenche o formulário com os dados POST da requisição e o valida com a ajuda do `FormHydrator`. Depois, passa o formulário para a view." + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "For the form to function we need to allow both GET to render the form and POST to send the data. Adjust your route in `config/common/routes.php`:" +msgstr "Para o formulário funcionar, precisamos permitir tanto GET, para renderizar o formulário, quanto POST, para enviar os dados. Ajuste a sua rota em `config/common/routes.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/start/forms.md +#, no-wrap +msgid "" +"routes(\n" +" Route::get('/')\n" +" ->action(Web\\HomePage\\Action::class)\n" +" ->name('home'),\n" +" Route::methods([Method::GET, Method::POST], '/say')\n" +" ->action(Web\\Echo\\Action::class)\n" +" ->name('echo/say'),\n" +" ),\n" +"];\n" +msgstr "" +"routes(\n" +" Route::get('/')\n" +" ->action(Web\\HomePage\\Action::class)\n" +" ->name('home'),\n" +" Route::methods([Method::GET, Method::POST], '/say')\n" +" ->action(Web\\Echo\\Action::class)\n" +" ->name('echo/say'),\n" +" ),\n" +"];\n" + +#. type: Title ## +#: ../src/guide/start/forms.md +#, no-wrap +msgid "Adjusting view" +msgstr "Ajustando a view" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "To render a form, you need to change your view, `src/Web/Echo/template.php`:" +msgstr "Para renderizar um formulário, você precisa alterar a sua view, `src/Web/Echo/template.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/start/forms.md +#, no-wrap +msgid "" +"post($urlGenerator->generate('echo/say'))\n" +" ->csrf($csrf);\n" +"?>\n" +"\n" +"open() ?>\n" +" required() ?>\n" +" \n" +"close() ?>\n" +"\n" +"isValid()): ?>\n" +" Echo said: message) ?>\n" +"\n" +msgstr "" +"post($urlGenerator->generate('echo/say'))\n" +" ->csrf($csrf);\n" +"?>\n" +"\n" +"open() ?>\n" +" required() ?>\n" +" \n" +"close() ?>\n" +"\n" +"isValid()): ?>\n" +" Echo said: message) ?>\n" +"\n" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "If the form is valid, you display a message. The rest initializes and renders the form." +msgstr "Se o formulário for válido, você exibe uma mensagem. O restante inicializa e renderiza o formulário." + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "First, you initialize `$htmlForm` with the POST type and the action URL generated with the help from the URL generator. You can access it as `$urlGenerator` in all views. You also need to pass the CSRF token to the form, which is also available in every view as `$csrf` thanks to the view injections listed in `config/common/params.php`:" +msgstr "Primeiro, você inicializa `$htmlForm` com o tipo POST e a URL da action gerada com a ajuda do gerador de URLs. Você pode acessá-lo como `$urlGenerator` em todas as views. Também precisa passar o token CSRF para o formulário, que também está disponível em toda view como `$csrf` graças às view injections listadas em `config/common/params.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/start/forms.md +#, no-wrap +msgid "" +"'yiisoft/yii-view-renderer' => [\n" +" 'injections' => [\n" +" Reference::to(CsrfViewInjection::class),\n" +" ],\n" +"],\n" +msgstr "" +"'yiisoft/yii-view-renderer' => [\n" +" 'injections' => [\n" +" Reference::to(CsrfViewInjection::class),\n" +" ],\n" +"],\n" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "The template renders the CSRF token value as a hidden input to ensure that the request originates from the form page and not from another website. It will be submitted along with POST form data. Omitting it would result in [HTTP response code 422](https://tools.ietf.org/html/rfc4918#section-11.2)." +msgstr "O template renderiza o valor do token CSRF como um input oculto para garantir que a requisição vem da página do formulário e não de outro site. Ele é enviado junto com os dados POST do formulário. Sem ele, o resultado seria o [código de resposta HTTP 422](https://tools.ietf.org/html/rfc4918#section-11.2)." + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "You use `Field::text()` to output \"message\" field, so it takes care about filling the value, escaping it, rendering field label and validation errors." +msgstr "Você usa `Field::text()` para exibir o campo \"message\", então ele cuida de preencher o valor, escapá-lo e renderizar o label do campo e os erros de validação." + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "Now, in case you submit an empty message, you will get a validation error: \"The message to be echoed must contain at least 2 characters.\"" +msgstr "Agora, se você enviar uma mensagem vazia, vai receber um erro de validação: \"The message to be echoed must contain at least 2 characters.\"" + +#. type: Title ## +#: ../src/guide/start/forms.md +#, no-wrap +msgid "Trying it Out" +msgstr "Testando" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "To see how it works, use your browser to access the following URL:" +msgstr "Para ver como funciona, acesse a seguinte URL no navegador:" + +#. type: Fenced code block +#: ../src/guide/start/forms.md +#, no-wrap +msgid "http://localhost:8080/say\n" +msgstr "http://localhost:8080/say\n" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "You will see a page with a form input field and a label that indicates what data to enter. Also, the form has a \"submit\" button labeled \"Say\". If you click the \"submit\" button without entering anything, you will see that the field is required. If you enter a single character, the form displays an error message next to the problematic input field." +msgstr "Você vai ver uma página com um campo de formulário e um label indicando qual dado informar. O formulário também tem um botão \"submit\" com o texto \"Say\". Se você clicar no botão \"submit\" sem digitar nada, vai ver que o campo é obrigatório. Se digitar um único caractere, o formulário mostra uma mensagem de erro ao lado do campo com problema." + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "![Form with a validation error](/images/guide/start/form-error.png)" +msgstr "![Formulário com erro de validação](/images/guide/start/form-error.png)" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "After you enter a valid message and click the \"submit\" button, the page echoes the data that you entered." +msgstr "Depois de digitar uma mensagem válida e clicar no botão \"submit\", a página mostra de volta os dados que você digitou." + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "![Form with a success message](/images/guide/start/form-success.png)" +msgstr "![Formulário com mensagem de sucesso](/images/guide/start/form-success.png)" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "In this section of the guide, you've learned how to create a form model class to represent the user data and validate said data." +msgstr "Nesta seção do guia, você aprendeu a criar uma classe de form model para representar os dados do usuário e validar esses dados." + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "You've also learned how to get data from users and how to display data back in the browser. This is a task that could take you a lot of time when developing an application, but Yii provides powerful widgets to make this task easy." +msgstr "Você também aprendeu a receber dados dos usuários e a exibi-los de volta no navegador. Essa é uma tarefa que pode tomar muito tempo no desenvolvimento de uma aplicação, mas o Yii oferece widgets poderosos que a tornam fácil." + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "In the next section, you will learn how to work with databases, which are needed in nearly every application." +msgstr "Na próxima seção, você vai aprender a trabalhar com bancos de dados, que são necessários em quase toda aplicação." diff --git a/_translations/po/pt-BR/guide_start_gii.md.po b/_translations/po/pt-BR/guide_start_gii.md.po new file mode 100644 index 00000000..7399c8e6 --- /dev/null +++ b/_translations/po/pt-BR/guide_start_gii.md.po @@ -0,0 +1,32 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-03-06 12:40+0000\n" +"PO-Revision-Date: 2026-03-06 12:40+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/start/gii.md +#, no-wrap +msgid "Generating code with Gii" +msgstr "Gerando código com o Gii" + +#. type: Plain text +#: ../src/guide/start/gii.md +#, no-wrap +msgid "" +"> [!NOTE]\n" +"> Gii is under development and will be available later.\n" +msgstr "" +"> [!NOTE]\n" +"> O Gii está em desenvolvimento e vai ficar disponível mais tarde.\n" diff --git a/_translations/po/pt-BR/guide_start_hello.md.po b/_translations/po/pt-BR/guide_start_hello.md.po new file mode 100644 index 00000000..ba17a6b6 --- /dev/null +++ b/_translations/po/pt-BR/guide_start_hello.md.po @@ -0,0 +1,362 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-06-05 20:33+0000\n" +"PO-Revision-Date: 2026-06-05 20:33+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md ../src/guide/start/forms.md ../src/guide/start/hello.md +#, no-wrap +msgid "Summary" +msgstr "Resumo" + +#. type: Title ## +#: ../src/guide/start/databases.md ../src/guide/start/hello.md +#, no-wrap +msgid "Trying it out" +msgstr "Testando" + +#. type: Title # +#: ../src/guide/start/hello.md +#, no-wrap +msgid "Saying hello" +msgstr "Dizendo olá" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "This section describes how to create a new \"Hello\" page in your application. It's a simple page that will echo back whatever you pass to it or, if nothing passed, will just say \"Hello!\"." +msgstr "Esta seção descreve como criar uma nova página \"Hello\" na sua aplicação. É uma página simples que devolve o que você passar para ela ou, se nada for passado, apenas diz \"Hello!\"." + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "To achieve this goal, you will define a route and create [a handler](../structure/action.md) that does the job and forms the response. Then you will improve it to use [view](../views/view.md) for building the response." +msgstr "Para isso, você vai definir uma rota e criar [um handler](../structure/action.md) que faz o trabalho e monta a resposta. Depois, vai melhorá-lo para usar uma [view](../views/view.md) na construção da resposta." + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "Through this tutorial, you will learn three things:" +msgstr "Neste tutorial, você vai aprender três coisas:" + +#. type: Bullet: '1. ' +#: ../src/guide/start/hello.md +msgid "How to create a handler to respond to a request." +msgstr "Como criar um handler para responder a uma requisição." + +#. type: Bullet: '2. ' +#: ../src/guide/start/hello.md +msgid "How to map URL to the handler." +msgstr "Como mapear uma URL para o handler." + +#. type: Bullet: '3. ' +#: ../src/guide/start/hello.md +msgid "How to use [view](../views/view.md) to compose the response's content." +msgstr "Como usar uma [view](../views/view.md) para compor o conteúdo da resposta." + +#. type: Title ## +#: ../src/guide/start/hello.md +#, no-wrap +msgid "Creating a handler" +msgstr "Criando um handler" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "For the \"Hello\" task, you will create a handler class that reads a `message` parameter from the request and displays that message back to the user. If the request doesn't provide a `message` parameter, the action will display the default \"Hello\" message." +msgstr "Para a tarefa \"Hello\", você vai criar uma classe handler que lê o parâmetro `message` da requisição e mostra essa mensagem de volta para o usuário. Se a requisição não trouxer o parâmetro `message`, a action mostra a mensagem padrão \"Hello\"." + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "Create `src/Web/Echo/Action.php`:" +msgstr "Crie `src/Web/Echo/Action.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/start/hello.md +#, no-wrap +msgid "" +"responseFactory->createResponse();\n" +" $response->getBody()->write('The message is: ' . Html::encode($message));\n" +" return $response;\n" +" }\n" +"}\n" +msgstr "" +"responseFactory->createResponse();\n" +" $response->getBody()->write('The message is: ' . Html::encode($message));\n" +" return $response;\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "In your example, the `__invoke` method receives the `$message` parameter that with the help of `RouteArgument` attribute gets the message from URL. The value defaults to `\"Hello!\"`. If the request is made to `/say/Goodbye`, the action assigns the value \"Goodbye\" to the `$message` variable." +msgstr "No exemplo, o método `__invoke` recebe o parâmetro `$message`, que, com a ajuda do atributo `RouteArgument`, pega a mensagem da URL. O valor padrão é `\"Hello!\"`. Se a requisição for feita para `/say/Goodbye`, a action atribui o valor \"Goodbye\" à variável `$message`." + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "The application passes the response through the [middleware stack](../structure/middleware.md) to the emitter that outputs the response to the end user." +msgstr "A aplicação passa a resposta pela [pilha de middlewares](../structure/middleware.md) até o emitter, que envia a resposta ao usuário final." + +#. type: Title ## +#: ../src/guide/start/hello.md +#, no-wrap +msgid "Configuring router" +msgstr "Configurando o router" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "Now, to map your handler to URL, you need to add a route in `config/common/routes.php`:" +msgstr "Agora, para mapear o handler para uma URL, você precisa adicionar uma rota em `config/common/routes.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/start/hello.md +#, no-wrap +msgid "" +"routes(\n" +" Route::get('/')\n" +" ->action(Web\\HomePage\\Action::class)\n" +" ->name('home'),\n" +" Route::get('/say[/{message}]')\n" +" ->action(Web\\Echo\\Action::class)\n" +" ->name('echo/say'),\n" +" ),\n" +"];\n" +msgstr "" +"routes(\n" +" Route::get('/')\n" +" ->action(Web\\HomePage\\Action::class)\n" +" ->name('home'),\n" +" Route::get('/say[/{message}]')\n" +" ->action(Web\\Echo\\Action::class)\n" +" ->name('echo/say'),\n" +" ),\n" +"];\n" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "In the above, you map the `/say[/{message}]` pattern to `\\App\\Web\\Echo\\Action`. For a request, the router creates an instance and calls the `__invoke()` method. The `{message}` part of the pattern writes anything specified in this place to the `message` route argument. `[]` marks this part of the pattern as optional." +msgstr "Acima, você mapeia o padrão `/say[/{message}]` para `\\App\\Web\\Echo\\Action`. A cada requisição, o router cria uma instância e chama o método `__invoke()`. A parte `{message}` do padrão grava o que for informado nessa posição no argumento de rota `message`. `[]` marca essa parte do padrão como opcional." + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "You also give a `echo/say` name to this route to be able to generate URLs pointing to it." +msgstr "Você também dá o nome `echo/say` a essa rota para poder gerar URLs que apontem para ela." + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "After creating the action and the view open `http://localhost/say/Hello+World` in your browser." +msgstr "Depois de criar a action e a view, abra `http://localhost/say/Hello+World` no navegador." + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "This URL displays a page with \"The message is: Hello World\"." +msgstr "Essa URL mostra uma página com \"The message is: Hello World\"." + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "If you omit the `message` parameter in the URL, the page displays \"The message is: Hello!\"." +msgstr "Se você omitir o parâmetro `message` na URL, a página mostra \"The message is: Hello!\"." + +#. type: Title ## +#: ../src/guide/start/hello.md +#, no-wrap +msgid "Creating a View Template" +msgstr "Criando um template de view" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "Usually, the task is more complicated than printing out \"hello world\" and involves rendering some complex HTML. For this task, it's handy to use view templates. They're scripts you write to generate a response's body." +msgstr "Normalmente, a tarefa é mais complicada do que imprimir \"hello world\" e envolve renderizar algum HTML complexo. Para isso, é prático usar templates de view. Eles são scripts que você escreve para gerar o corpo de uma resposta." + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "For the \"Hello\" task, create a `src/Web/Echo/template.php` template that prints the `message` parameter received from the action method:" +msgstr "Para a tarefa \"Hello\", crie um template `src/Web/Echo/template.php` que imprime o parâmetro `message` recebido do método da action:" + +#. type: Fenced code block (php) +#: ../src/guide/start/hello.md ../src/guide/views/view.md +#, no-wrap +msgid "" +"\n" +"\n" +"

The message is:

\n" +msgstr "" +"\n" +"\n" +"

The message is:

\n" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "In the above code, the `message` parameter uses HTML encoding before you print it. You need that because the parameter comes from an end user and is vulnerable to [cross-site scripting (XSS) attacks](https://en.wikipedia.org/wiki/Cross-site_scripting) by embedding malicious JavaScript in the parameter." +msgstr "No código acima, o parâmetro `message` passa por codificação HTML antes de ser impresso. Isso é necessário porque o parâmetro vem do usuário final e está sujeito a [ataques de cross-site scripting (XSS)](https://pt.wikipedia.org/wiki/Cross-site_scripting) com JavaScript malicioso embutido no parâmetro." + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "Naturally, you may put more content in the `say` view. The content can consist of HTML tags, plain text, and even PHP statements. In fact, the view service executes the `say` view as a PHP script." +msgstr "Naturalmente, você pode colocar mais conteúdo na view `say`. O conteúdo pode ter tags HTML, texto puro e até instruções PHP. Na verdade, o serviço de view executa a view `say` como um script PHP." + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "To use the view, you need to change `src/Web/Echo/Action.php`:" +msgstr "Para usar a view, você precisa alterar `src/Web/Echo/Action.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/start/hello.md ../src/guide/views/view.md +#, no-wrap +msgid "" +"viewRenderer->render(__DIR__ . '/template', [\n" +" 'message' => $message,\n" +" ]);\n" +" }\n" +"}\n" +msgstr "" +"viewRenderer->render(__DIR__ . '/template', [\n" +" 'message' => $message,\n" +" ]);\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "Now open your browser and check it again. You should see the similar text but with a layout applied." +msgstr "Agora abra o navegador e confira de novo. Você deve ver um texto parecido, mas com um layout aplicado." + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "Also, you've separated the part about how it works and part of how it's presented. In the larger applications, it helps a lot to deal with complexity." +msgstr "Além disso, você separou a parte de como funciona da parte de como é apresentado. Em aplicações maiores, isso ajuda muito a lidar com a complexidade." + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "In this section, you've touched the handler and template parts of the typical web application. You created a handler as part of a class to handle a specific request. You also created a view to compose the response's content. In this simple example, no data source was involved as the only data used was the `message` parameter." +msgstr "Nesta seção, você passou pelas partes de handler e de template de uma aplicação web típica. Você criou um handler como parte de uma classe para tratar uma requisição específica. Também criou uma view para compor o conteúdo da resposta. Neste exemplo simples, nenhuma fonte de dados foi usada, já que o único dado era o parâmetro `message`." + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "You've also learned about routing in Yii, which acts as the bridge between user requests and handlers." +msgstr "Você também aprendeu sobre o roteamento no Yii, que funciona como a ponte entre as requisições do usuário e os handlers." + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "In the next section, you will learn how to fetch data and add a new page containing an HTML form." +msgstr "Na próxima seção, você vai aprender a buscar dados e adicionar uma nova página com um formulário HTML." diff --git a/_translations/po/pt-BR/guide_start_looking-ahead.md.po b/_translations/po/pt-BR/guide_start_looking-ahead.md.po new file mode 100644 index 00000000..cd8f7556 --- /dev/null +++ b/_translations/po/pt-BR/guide_start_looking-ahead.md.po @@ -0,0 +1,27 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 13:00+0000\n" +"PO-Revision-Date: 2025-12-24 13:00+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/start/looking-ahead.md +#, no-wrap +msgid "Looking ahead" +msgstr "Seguindo em frente" + +#. type: Plain text +#: ../src/guide/start/looking-ahead.md +msgid "If you've read through the entire \"Getting Started\" chapter, you have now created a complete Yii application. In the process, you've learned how to implement some commonly necessary features, such as getting data from users via an HTML form, fetching data from a database, and displaying data in a paginated fashion. You've also learned how to use [Gii](gii.md) to generate code automatically. Using Gii for code generation turns the bulk of your Web development process into a task as simple as just filling out some forms." +msgstr "Se você leu todo o capítulo \"Primeiros passos\", já criou uma aplicação Yii completa. No caminho, aprendeu a implementar alguns recursos comuns, como receber dados dos usuários por um formulário HTML, buscar dados em um banco de dados e exibir dados de forma paginada. Também aprendeu a usar o [Gii](gii.md) para gerar código automaticamente. Usar o Gii para gerar código transforma boa parte do desenvolvimento web em algo tão simples quanto preencher alguns formulários." diff --git a/_translations/po/pt-BR/guide_start_prerequisites.md.po b/_translations/po/pt-BR/guide_start_prerequisites.md.po new file mode 100644 index 00000000..8fcf717a --- /dev/null +++ b/_translations/po/pt-BR/guide_start_prerequisites.md.po @@ -0,0 +1,97 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-05-28 20:46+0000\n" +"PO-Revision-Date: 2026-05-28 20:46+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/start/prerequisites.md +#, no-wrap +msgid "What do you need to know?" +msgstr "O que você precisa saber?" + +#. type: Plain text +#: ../src/guide/start/prerequisites.md +msgid "The Yii learning curve isn't as steep as other PHP frameworks, but still, there are some things you should learn before starting with Yii." +msgstr "A curva de aprendizado do Yii não é tão íngreme quanto a de outros frameworks PHP, mas ainda assim há algumas coisas que você deve aprender antes de começar com o Yii." + +#. type: Title ## +#: ../src/guide/start/prerequisites.md +#, no-wrap +msgid "PHP" +msgstr "PHP" + +#. type: Plain text +#: ../src/guide/start/prerequisites.md +msgid "Yii is a PHP framework, so make sure you [read and understand language reference](https://www.php.net/manual/en/langref.php)." +msgstr "O Yii é um framework PHP, então [leia e entenda a referência da linguagem](https://www.php.net/manual/pt_BR/langref.php)." + +#. type: Title ## +#: ../src/guide/start/prerequisites.md +#, no-wrap +msgid "Object-oriented programming" +msgstr "Programação orientada a objetos" + +#. type: Plain text +#: ../src/guide/start/prerequisites.md +msgid "You need a basic understanding of object-oriented programming. If you're not familiar with it, check one of the many tutorials available such as [the one from tuts+](https://code.tutsplus.com/tutorials/object-oriented-php-for-beginners--net-12762)." +msgstr "Você precisa de uma noção básica de programação orientada a objetos. Se ainda não conhece, veja um dos muitos tutoriais disponíveis, como [o do tuts+](https://code.tutsplus.com/tutorials/object-oriented-php-for-beginners--net-12762)." + +#. type: Plain text +#: ../src/guide/start/prerequisites.md +msgid "When you develop with Yii, you write code in an object-oriented fashion, so make sure you're familiar with [PHP OOP support](https://www.php.net/manual/en/language.oop5.php)." +msgstr "Ao desenvolver com o Yii, você escreve código orientado a objetos, então conheça bem o [suporte do PHP a POO](https://www.php.net/manual/pt_BR/language.oop5.php)." + +#. type: Plain text +#: ../src/guide/start/prerequisites.md +msgid "Note that the more complicated your application is, the more advanced OOP concepts you should learn to successfully manage that complexity." +msgstr "Quanto mais complexa for a sua aplicação, mais conceitos avançados de POO você vai precisar aprender para lidar bem com essa complexidade." + +#. type: Title ## +#: ../src/guide/start/prerequisites.md +#, no-wrap +msgid "Command line and Composer" +msgstr "Linha de comando e Composer" + +#. type: Plain text +#: ../src/guide/start/prerequisites.md +msgid "Yii extensively uses the de-facto standard PHP package manager, [Composer](https://getcomposer.org) so make sure you read and understand its [guide](https://getcomposer.org/doc/01-basic-usage.md). If you aren't familiar with using the command line, it's time to start trying. Once you learn the basics, you'll never want to work without it." +msgstr "O Yii usa amplamente o gerenciador de pacotes que é o padrão de fato no PHP, o [Composer](https://getcomposer.org), então leia e entenda o [guia dele](https://getcomposer.org/doc/01-basic-usage.md). Se você não tem costume de usar a linha de comando, é hora de começar. Depois de aprender o básico, você não vai querer trabalhar sem ela." + +#. type: Title ## +#: ../src/guide/start/prerequisites.md +#, no-wrap +msgid "HTTP" +msgstr "HTTP" + +#. type: Plain text +#: ../src/guide/start/prerequisites.md +msgid "Since Yii is a web framework and the web largely uses HTTP, it's a good idea to [learn more about it](https://developer.mozilla.org/en-US/docs/Web/HTTP)." +msgstr "Como o Yii é um framework web e a web usa principalmente HTTP, é uma boa ideia [aprender mais sobre ele](https://developer.mozilla.org/pt-BR/docs/Web/HTTP)." + +#. type: Title ## +#: ../src/guide/start/prerequisites.md +#, no-wrap +msgid "Docker" +msgstr "Docker" + +#. type: Plain text +#: ../src/guide/start/prerequisites.md +msgid "The default application template leverages Docker, so we recommend that you [read and understand the concepts](https://docs.docker.com/get-started/)." +msgstr "O template de aplicação padrão usa Docker, então recomendamos que você [leia e entenda os conceitos](https://docs.docker.com/get-started/)." + +#. type: Plain text +#: ../src/guide/start/prerequisites.md +msgid "Also, you will benefit from familiarizing yourself with [twelve-factor app](https://12factor.net/) principles." +msgstr "Também vale a pena conhecer os princípios do [twelve-factor app](https://12factor.net/pt_br/)." diff --git a/_translations/po/pt-BR/guide_start_workflow.md.po b/_translations/po/pt-BR/guide_start_workflow.md.po new file mode 100644 index 00000000..24b643a3 --- /dev/null +++ b/_translations/po/pt-BR/guide_start_workflow.md.po @@ -0,0 +1,286 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-06-05 20:33+0000\n" +"PO-Revision-Date: 2026-06-05 20:33+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/guide/index.md ../src/guide/start/workflow.md +#, no-wrap +msgid "Application structure" +msgstr "Estrutura da aplicação" + +#. type: Title # +#: ../src/guide/start/workflow.md +#, no-wrap +msgid "Application Workflow" +msgstr "Fluxo da aplicação" + +#. type: Plain text +#: ../src/guide/start/workflow.md +msgid "After installing Yii, you have a working Yii application. This section introduces the application's built-in functionality, how the code is organized, and how the application handles requests in general." +msgstr "Depois de instalar o Yii, você tem uma aplicação Yii funcionando. Esta seção apresenta as funcionalidades que vêm com a aplicação, como o código está organizado e como a aplicação trata as requisições de forma geral." + +#. type: Plain text +#: ../src/guide/start/workflow.md +msgid "Note that unlike the framework itself, after you install a project template, it's all yours. You're free to add or delete code and overall change it as you need." +msgstr "Diferente do próprio framework, depois que você instala um template de projeto, ele é todo seu. Você pode adicionar ou remover código e mudar o que precisar." + +#. type: Title ## +#: ../src/guide/start/workflow.md +#, no-wrap +msgid "Functionality" +msgstr "Funcionalidades" + +#. type: Plain text +#: ../src/guide/start/workflow.md +msgid "The installed application contains only one page, accessible at `http://localhost/`. It shares a common layout that you can reuse on further pages." +msgstr "A aplicação instalada tem apenas uma página, acessível em `http://localhost/`. Ela usa um layout comum que você pode reaproveitar nas próximas páginas." + +#. type: Plain text +#: ../src/guide/start/workflow.md +#, no-wrap +msgid "" +"\n" +msgstr "" +"\n" + +#. type: Plain text +#: ../src/guide/start/workflow.md +msgid "In addition to the web application, you can access a console script via `./yii` or, in case of Docker, `make yii`. Use this script to run background and maintenance tasks for the application, which the [Console Application Section](../tutorial/console-applications.md) describes." +msgstr "Além da aplicação web, você pode acessar um script de console via `./yii` ou, no caso do Docker, `make yii`. Use esse script para rodar tarefas em segundo plano e de manutenção da aplicação, descritas na [seção de aplicações de console](../tutorial/console-applications.md)." + +#. type: Title ## +#: ../src/guide/start/workflow.md +#, no-wrap +msgid "Experimental debugger" +msgstr "Debugger experimental" + +#. type: Plain text +#: ../src/guide/start/workflow.md +msgid "Yii has a debugger that can collect debug data for web requests and expose it through the [Yii Dev Panel](https://yiisoft.github.io/yii-dev-panel/). The debugger is a work in progress. It isn't released as a stable package, and its API, routes, and setup may change or be deprecated." +msgstr "O Yii tem um debugger que coleta dados de debug das requisições web e os expõe pelo [Yii Dev Panel](https://yiisoft.github.io/yii-dev-panel/). O debugger ainda está em desenvolvimento. Ele não foi lançado como pacote estável, e a API, as rotas e a configuração podem mudar ou ser descontinuadas." + +#. type: Plain text +#: ../src/guide/start/workflow.md +msgid "To try the current development version, install the debug API package:" +msgstr "Para testar a versão de desenvolvimento atual, instale o pacote da API de debug:" + +#. type: Fenced code block (shell) +#: ../src/guide/start/workflow.md +#, no-wrap +msgid "composer require yiisoft/yii-debug-api:^3.0@dev\n" +msgstr "composer require yiisoft/yii-debug-api:^3.0@dev\n" + +#. type: Plain text +#: ../src/guide/start/workflow.md +msgid "Enable debug mode in `.env`:" +msgstr "Ative o modo debug no `.env`:" + +#. type: Fenced code block (dotenv) +#: ../src/guide/start/workflow.md +#, no-wrap +msgid "APP_DEBUG=true\n" +msgstr "APP_DEBUG=true\n" + +#. type: Plain text +#: ../src/guide/start/workflow.md +msgid "The package registers its routes automatically. Start the application and open `/debug` to check that the debug API is available. Then open [Yii Dev Panel](https://yiisoft.github.io/yii-dev-panel/) and set your application URL there." +msgstr "O pacote registra as rotas automaticamente. Inicie a aplicação e abra `/debug` para conferir se a API de debug está disponível. Depois abra o [Yii Dev Panel](https://yiisoft.github.io/yii-dev-panel/) e informe a URL da sua aplicação." + +#. type: Plain text +#: ../src/guide/start/workflow.md +#, no-wrap +msgid "" +"> [!CAUTION]\n" +"> Use debug mode for local development. In production, keep `APP_DEBUG=false` and don't expose debug routes publicly.\n" +msgstr "" +"> [!CAUTION]\n" +"> Use o modo debug no desenvolvimento local. Em produção, mantenha `APP_DEBUG=false` e não exponha as rotas de debug publicamente.\n" + +#. type: Plain text +#: ../src/guide/start/workflow.md +msgid "The most important directories and files in your application are (assuming the application's root directory is `app`):" +msgstr "Os diretórios e arquivos mais importantes da sua aplicação são (considerando que o diretório raiz da aplicação é `app`):" + +#. type: Fenced code block +#: ../src/guide/start/workflow.md +#, no-wrap +msgid "" +"assets/ Asset bundle source files.\n" +"config/ Configuration files.\n" +" common/ Common configuration and DI definitions.\n" +" console/ Console-specific configuration.\n" +" environments/ Environment-specific configuration (dev/test/prod).\n" +" web/ Web-specific configuration.\n" +"docker/ Docker-specific files.\n" +"public/ Files publically accessible from the Internet.\n" +" assets/ Published/compiled assets.\n" +" index.php Entry script.\n" +"runtime/ Files generated during runtime.\n" +"src/ Application source code.\n" +" Console/ Console commands.\n" +" Shared/ Code shared between web and console applications.\n" +" Web/ Web-specific code (actions, handlers, layout).\n" +" Shared/ Shared web components.\n" +" Layout/ Layout components and templates.\n" +" Environment.php Environment configuration class.\n" +"tests/ A set of Codeception tests for the application.\n" +" Console/ Console command tests.\n" +" Functional/ Functional tests.\n" +" Unit/ Unit tests.\n" +" Web/ Web actions tests.\n" +"vendor/ Installed Composer packages.\n" +"Makefile Config for make command.\n" +"yii Console application entry point.\n" +msgstr "" +"assets/ Arquivos-fonte dos asset bundles.\n" +"config/ Arquivos de configuração.\n" +" common/ Configuração comum e definições de DI.\n" +" console/ Configuração específica do console.\n" +" environments/ Configuração por ambiente (dev/test/prod).\n" +" web/ Configuração específica da web.\n" +"docker/ Arquivos específicos do Docker.\n" +"public/ Arquivos acessíveis publicamente pela internet.\n" +" assets/ Assets publicados/compilados.\n" +" index.php Script de entrada.\n" +"runtime/ Arquivos gerados em tempo de execução.\n" +"src/ Código-fonte da aplicação.\n" +" Console/ Comandos de console.\n" +" Shared/ Código compartilhado entre as aplicações web e console.\n" +" Web/ Código específico da web (actions, handlers, layout).\n" +" Shared/ Componentes web compartilhados.\n" +" Layout/ Componentes e templates de layout.\n" +" Environment.php Classe de configuração do ambiente.\n" +"tests/ Conjunto de testes Codeception da aplicação.\n" +" Console/ Testes dos comandos de console.\n" +" Functional/ Testes funcionais.\n" +" Unit/ Testes unitários.\n" +" Web/ Testes das actions web.\n" +"vendor/ Pacotes do Composer instalados.\n" +"Makefile Configuração do comando make.\n" +"yii Ponto de entrada da aplicação de console.\n" + +#. type: Plain text +#: ../src/guide/start/workflow.md +msgid "In general, the files in the application fall into two groups: those under `app/public` and those under other directories. You can access the former directly via HTTP (i.e., in a browser), while you shouldn't expose the latter." +msgstr "De forma geral, os arquivos da aplicação se dividem em dois grupos: os que ficam em `app/public` e os que ficam nos outros diretórios. Os primeiros podem ser acessados diretamente via HTTP (ou seja, no navegador), enquanto os demais não devem ser expostos." + +#. type: Plain text +#: ../src/guide/start/workflow.md +msgid "Each application has an entry script `public/index.php`, the only web-accessible PHP script in the application. The entry script uses an [application runner](https://github.com/yiisoft/yii-runner) to create an instance of an incoming request with the help of one of PSR-7 packages and passes it to an [application](../structure/application.md) instance. The application executes a set of middleware sequentially to process the request. It then passes the result to the emitter, which sends the response to the browser." +msgstr "Toda aplicação tem um script de entrada `public/index.php`, o único script PHP acessível pela web na aplicação. O script de entrada usa um [application runner](https://github.com/yiisoft/yii-runner) para criar uma instância da requisição recebida com a ajuda de um dos pacotes PSR-7 e a passa para uma instância da [aplicação](../structure/application.md). A aplicação executa um conjunto de middlewares em sequência para processar a requisição. Depois, passa o resultado para o emitter, que envia a resposta ao navegador." + +#. type: Plain text +#: ../src/guide/start/workflow.md +msgid "Depending on the middleware you use, the application may behave differently. By default, a router uses the requested URL and configuration to choose a handler and execute it to produce a response." +msgstr "Dependendo dos middlewares que você usa, a aplicação pode se comportar de forma diferente. Por padrão, um router usa a URL requisitada e a configuração para escolher um handler e executá-lo para produzir a resposta." + +#. type: Plain text +#: ../src/guide/start/workflow.md +msgid "You can learn more about the application template from the [yiisoft/app package documentation](https://github.com/yiisoft/app/blob/master/README.md)." +msgstr "Você pode saber mais sobre o template de aplicação na [documentação do pacote yiisoft/app](https://github.com/yiisoft/app/blob/master/README.md)." + +#. type: Title ## +#: ../src/guide/start/workflow.md +#, no-wrap +msgid "Request Lifecycle" +msgstr "Ciclo de vida da requisição" + +#. type: Plain text +#: ../src/guide/start/workflow.md +msgid "The following diagram shows how an application handles a request." +msgstr "O diagrama a seguir mostra como uma aplicação trata uma requisição." + +#. type: Fenced code block (mermaid) +#: ../src/guide/start/workflow.md +#, no-wrap +msgid "" +"flowchart LR\n" +" user[User's client] --> index\n" +" index[index.php] --> DI[Initialize Dependency Container]\n" +" config[configs] -.-> DI\n" +" DI --> RequestFactory[RequestFactory]\n" +" RequestFactory -->|Request| app[Application]\n" +" app -->|Request| middleware[Middleware]\n" +" middleware -->|Request| router[Router]\n" +" router -->|Request| action[Action Handler]\n" +" action -->|Response| emitter[SapiEmitter]\n" +" router -->|Response| emitter\n" +" middleware -->|Response| emitter\n" +" app -->|Response| emitter\n" +" emitter --> user\n" +msgstr "" +"flowchart LR\n" +" user[User's client] --> index\n" +" index[index.php] --> DI[Initialize Dependency Container]\n" +" config[configs] -.-> DI\n" +" DI --> RequestFactory[RequestFactory]\n" +" RequestFactory -->|Request| app[Application]\n" +" app -->|Request| middleware[Middleware]\n" +" middleware -->|Request| router[Router]\n" +" router -->|Request| action[Action Handler]\n" +" action -->|Response| emitter[SapiEmitter]\n" +" router -->|Response| emitter\n" +" middleware -->|Response| emitter\n" +" app -->|Response| emitter\n" +" emitter --> user\n" + +#. type: Bullet: '1. ' +#: ../src/guide/start/workflow.md +msgid "A user makes a request to the [entry script](../structure/entry-script.md) `public/index.php`." +msgstr "Um usuário faz uma requisição para o [script de entrada](../structure/entry-script.md) `public/index.php`." + +#. type: Bullet: '2. ' +#: ../src/guide/start/workflow.md +msgid "The entry script with the help of the application runner loads the container [configuration](../concept/configuration.md) and creates an [application](../structure/application.md) instance and services necessary to handle the request." +msgstr "O script de entrada, com a ajuda do application runner, carrega a [configuração](../concept/configuration.md) do container e cria uma instância da [aplicação](../structure/application.md) e os serviços necessários para tratar a requisição." + +#. type: Bullet: '3. ' +#: ../src/guide/start/workflow.md +msgid "Request factory creates a request object based on a raw request that came from a user." +msgstr "A request factory cria um objeto de requisição a partir da requisição bruta que veio do usuário." + +#. type: Bullet: '4. ' +#: ../src/guide/start/workflow.md +msgid "Application passes a request object through a middleware array configured. One of these is typically a router." +msgstr "A aplicação passa o objeto de requisição pelo array de middlewares configurado. Um deles normalmente é o router." + +#. type: Bullet: '5. ' +#: ../src/guide/start/workflow.md +msgid "The Router finds out what handler to execute based on request and configuration." +msgstr "O router descobre qual handler executar com base na requisição e na configuração." + +#. type: Bullet: '6. ' +#: ../src/guide/start/workflow.md +msgid "The handler may load some data, possibly from a database." +msgstr "O handler pode carregar alguns dados, possivelmente de um banco de dados." + +#. type: Bullet: '7. ' +#: ../src/guide/start/workflow.md +msgid "The handler forms a response by using data. Either directly or with the help of the view package." +msgstr "O handler monta uma resposta usando esses dados, diretamente ou com a ajuda do pacote de view." + +#. type: Bullet: '8. ' +#: ../src/guide/start/workflow.md +msgid "Emitter receives the response and takes care of sending the response to the user's browser." +msgstr "O emitter recebe a resposta e cuida de enviá-la para o navegador do usuário." diff --git a/_translations/po/pt-BR/guide_structure_action.md.po b/_translations/po/pt-BR/guide_structure_action.md.po new file mode 100644 index 00000000..5c0c5efb --- /dev/null +++ b/_translations/po/pt-BR/guide_structure_action.md.po @@ -0,0 +1,261 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-05-05 21:53+0000\n" +"PO-Revision-Date: 2026-05-05 21:53+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/intro/upgrade-from-v2.md ../src/guide/structure/action.md +#, no-wrap +msgid "Actions" +msgstr "Actions" + +#. type: Plain text +#: ../src/guide/structure/action.md +msgid "In a web application, the request URL determines what's executed. Matching is made by a router configured with multiple routes. Each route can be attached to a middleware that, given request, produces a response. Since middleware overall could be chained and can pass actual handling to the next middleware, we call the middleware actually doing the job an action." +msgstr "Em uma aplicação web, a URL da requisição determina o que é executado. A correspondência é feita por um router configurado com várias rotas. Cada rota pode ser associada a um middleware que, dada a requisição, produz uma resposta. Como os middlewares podem ser encadeados e podem passar o tratamento efetivo para o próximo middleware, chamamos de action o middleware que realmente faz o trabalho." + +#. type: Plain text +#: ../src/guide/structure/action.md +msgid "There are multiple ways to describe an action. The simplest one is using a closure:" +msgstr "Há várias formas de descrever uma action. A mais simples é usando uma closure:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/action.md +#, no-wrap +msgid "" +"use \\Psr\\Http\\Message\\ServerRequestInterface;\n" +"use \\Psr\\Http\\Message\\ResponseInterface;\n" +"use Yiisoft\\Router\\Route;\n" +"\n" +"Route::get('/')->action(function (ServerRequestInterface $request) use ($responseFactory): ResponseInterface {\n" +" $response = $responseFactory->createResponse();\n" +" $response->getBody()->write('You are at homepage.');\n" +" return $response;\n" +"});\n" +msgstr "" +"use \\Psr\\Http\\Message\\ServerRequestInterface;\n" +"use \\Psr\\Http\\Message\\ResponseInterface;\n" +"use Yiisoft\\Router\\Route;\n" +"\n" +"Route::get('/')->action(function (ServerRequestInterface $request) use ($responseFactory): ResponseInterface {\n" +" $response = $responseFactory->createResponse();\n" +" $response->getBody()->write('You are at homepage.');\n" +" return $response;\n" +"});\n" + +#. type: Plain text +#: ../src/guide/structure/action.md +msgid "It's fine for simple handling since any more complicated one would require getting dependencies, so a good idea would be moving the handling to a class method. Callback middleware could be used for the purpose:" +msgstr "Isso funciona bem para um tratamento simples, já que qualquer coisa mais complicada exigiria obter dependências; então, uma boa ideia é mover o tratamento para um método de classe. Um middleware de callback pode ser usado para isso:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/action.md +#, no-wrap +msgid "" +"use Yiisoft\\Router\\Route;\n" +"\n" +"Route::get('/')->action(FrontPageAction::class),\n" +msgstr "" +"use Yiisoft\\Router\\Route;\n" +"\n" +"Route::get('/')->action(FrontPageAction::class),\n" + +#. type: Plain text +#: ../src/guide/structure/action.md +msgid "The class itself would be like:" +msgstr "A classe em si seria assim:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/action.md +#, no-wrap +msgid "" +"use \\Psr\\Http\\Message\\ServerRequestInterface;\n" +"use \\Psr\\Http\\Message\\ResponseInterface;\n" +"\n" +"final readonly class FrontPageAction\n" +"{\n" +" public function __invoke(ServerRequestInterface $request): ResponseInterface\n" +" {\n" +" // build response for a front page \n" +" }\n" +"}\n" +msgstr "" +"use \\Psr\\Http\\Message\\ServerRequestInterface;\n" +"use \\Psr\\Http\\Message\\ResponseInterface;\n" +"\n" +"final readonly class FrontPageAction\n" +"{\n" +" public function __invoke(ServerRequestInterface $request): ResponseInterface\n" +" {\n" +" // monta a resposta para a página inicial \n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/structure/action.md +msgid "For many cases, it makes sense to group handling for many routes into a single class:" +msgstr "Em muitos casos, faz sentido agrupar o tratamento de várias rotas em uma única classe:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/action.md +#, no-wrap +msgid "" +"use Yiisoft\\Router\\Route;\n" +"\n" +"Route::get('/post/index')->action([PostController::class, 'actionIndex']),\n" +"Route::get('/post/view/{id:\\d+}')->action([PostController::class, 'actionView']),\n" +msgstr "" +"use Yiisoft\\Router\\Route;\n" +"\n" +"Route::get('/post/index')->action([PostController::class, 'actionIndex']),\n" +"Route::get('/post/view/{id:\\d+}')->action([PostController::class, 'actionView']),\n" + +#. type: Plain text +#: ../src/guide/structure/action.md +msgid "The class itself would look like the following:" +msgstr "A classe em si ficaria assim:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/action.md +#, no-wrap +msgid "" +"use \\Psr\\Http\\Message\\ServerRequestInterface;\n" +"use \\Psr\\Http\\Message\\ResponseInterface;\n" +"use Yiisoft\\Router\\HydratorAttribute\\RouteArgument;\n" +"\n" +"final readonly class PostController\n" +"{\n" +" public function actionIndex(ServerRequestInterface $request): ResponseInterface\n" +" {\n" +" // render posts list\n" +" }\n" +" \n" +" \n" +" public function actionView(\n" +" ServerRequestInterface $request,\n" +" #[RouteArgument('id')]\n" +" int $id,\n" +" ): ResponseInterface\n" +" {\n" +" // render a single post by $id\n" +" }\n" +"}\n" +msgstr "" +"use \\Psr\\Http\\Message\\ServerRequestInterface;\n" +"use \\Psr\\Http\\Message\\ResponseInterface;\n" +"use Yiisoft\\Router\\HydratorAttribute\\RouteArgument;\n" +"\n" +"final readonly class PostController\n" +"{\n" +" public function actionIndex(ServerRequestInterface $request): ResponseInterface\n" +" {\n" +" // renderiza a lista de posts\n" +" }\n" +" \n" +" \n" +" public function actionView(\n" +" ServerRequestInterface $request,\n" +" #[RouteArgument('id')]\n" +" int $id,\n" +" ): ResponseInterface\n" +" {\n" +" // renderiza um único post pelo $id\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/structure/action.md +msgid "We usually call such a class \"controller.\"" +msgstr "Normalmente chamamos uma classe assim de \"controller\"." + +#. type: Plain text +#: ../src/guide/structure/action.md +msgid "The `{id}` part of the `/post/view/{id:\\d+}` route is a named route parameter. Route parameters are available from `Yiisoft\\Router\\CurrentRoute`. To receive one as an action argument, add the `RouteArgument` attribute to the corresponding parameter. The attribute name should match the route parameter name." +msgstr "A parte `{id}` da rota `/post/view/{id:\\d+}` é um parâmetro de rota nomeado. Os parâmetros de rota estão disponíveis em `Yiisoft\\Router\\CurrentRoute`. Para recebê-lo como argumento da action, adicione o atributo `RouteArgument` ao parâmetro correspondente. O nome no atributo deve corresponder ao nome do parâmetro de rota." + +#. type: Title ## +#: ../src/guide/structure/action.md +#, no-wrap +msgid "Autowiring" +msgstr "Autowiring" + +#. type: Plain text +#: ../src/guide/structure/action.md +#, no-wrap +msgid "" +"Both constructors of action-classes and action-methods are automatically getting services from\n" +" the dependency injection container:\n" +msgstr "" +"Tanto os construtores das classes de action quanto os métodos de action recebem automaticamente serviços do\n" +" container de injeção de dependência:\n" + +#. type: Fenced code block (php) +#: ../src/guide/structure/action.md +#, no-wrap +msgid "" +"use \\Psr\\Http\\Message\\ServerRequestInterface;\n" +"use \\Psr\\Http\\Message\\ResponseInterface;\n" +"use Psr\\Log\\LoggerInterface;\n" +"\n" +"final readonly class PostController\n" +"{\n" +" public function __construct(\n" +" private PostRepository $postRepository\n" +" )\n" +" {\n" +" }\n" +"\n" +" public function actionIndex(ServerRequestInterface $request, LoggerInterface $logger): ResponseInterface\n" +" {\n" +" $logger->debug('Rendering posts list');\n" +" // render posts list\n" +" }\n" +" \n" +" \n" +" public function actionView(ServerRequestInterface $request): ResponseInterface\n" +" {\n" +" // render a single post \n" +" }\n" +"}\n" +msgstr "" +"use \\Psr\\Http\\Message\\ServerRequestInterface;\n" +"use \\Psr\\Http\\Message\\ResponseInterface;\n" +"use Psr\\Log\\LoggerInterface;\n" +"\n" +"final readonly class PostController\n" +"{\n" +" public function __construct(\n" +" private PostRepository $postRepository\n" +" )\n" +" {\n" +" }\n" +"\n" +" public function actionIndex(ServerRequestInterface $request, LoggerInterface $logger): ResponseInterface\n" +" {\n" +" $logger->debug('Rendering posts list');\n" +" // renderiza a lista de posts\n" +" }\n" +" \n" +" \n" +" public function actionView(ServerRequestInterface $request): ResponseInterface\n" +" {\n" +" // renderiza um único post \n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/structure/action.md +msgid "In the above example `PostRepository` is injected automatically via constructor. That means it is available in every action. Logger is injected into `index` action only." +msgstr "No exemplo acima, `PostRepository` é injetado automaticamente pelo construtor. Isso significa que ele fica disponível em todas as actions. O logger é injetado apenas na action `index`." diff --git a/_translations/po/pt-BR/guide_structure_application.md.po b/_translations/po/pt-BR/guide_structure_application.md.po new file mode 100644 index 00000000..ba8a1c44 --- /dev/null +++ b/_translations/po/pt-BR/guide_structure_application.md.po @@ -0,0 +1,47 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-27 03:24+0000\n" +"PO-Revision-Date: 2025-12-27 03:24+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/structure/application.md +#, no-wrap +msgid "Application" +msgstr "Aplicação" + +#. type: Plain text +#: ../src/guide/structure/application.md +msgid "The primary purpose of the web application and its runner in Yii3 is to process requests to get responses." +msgstr "O principal propósito da aplicação web e do seu runner no Yii3 é processar requisições para obter respostas." + +#. type: Plain text +#: ../src/guide/structure/application.md +msgid "Typically, the runtime consists of:" +msgstr "Normalmente, o ciclo de execução consiste em:" + +#. type: Bullet: '1. ' +#: ../src/guide/structure/application.md +msgid "Startup. Get config, create an instance of container and do additional environment initialization such as registering error handler, so it can handle errors occurring. Fire `ApplicationStartup` event." +msgstr "Inicialização. Obter a configuração, criar uma instância do container e fazer a inicialização adicional do ambiente, como registrar o error handler para que ele possa tratar os erros que ocorrerem. Disparar o evento `ApplicationStartup`." + +#. type: Bullet: '2. ' +#: ../src/guide/structure/application.md +msgid "Handle requests via passing request objects to middleware dispatcher to execute [middleware stack](middleware.md) and get a response object. In usual PHP applications, it's done once. In [environments such as RoadRunner](../tutorial/using-with-event-loop.md), it could be done multiple times with the same application instance. Response object is converted into an actual HTTP response by using emitter. Fire `AfterEmit` event." +msgstr "Tratar requisições passando os objetos de requisição para o dispatcher de middlewares, que executa a [pilha de middlewares](middleware.md) e obtém um objeto de resposta. Em aplicações PHP comuns, isso é feito uma vez. Em [ambientes como o RoadRunner](../tutorial/using-with-event-loop.md), pode ser feito várias vezes com a mesma instância da aplicação. O objeto de resposta é convertido em uma resposta HTTP real usando o emitter. Disparar o evento `AfterEmit`." + +#. type: Bullet: '3. ' +#: ../src/guide/structure/application.md +msgid "Shutdown. Fire `ApplicationShutdown` event." +msgstr "Encerramento. Disparar o evento `ApplicationShutdown`." diff --git a/_translations/po/pt-BR/guide_structure_designing-packages.md.po b/_translations/po/pt-BR/guide_structure_designing-packages.md.po new file mode 100644 index 00000000..86c7d0b0 --- /dev/null +++ b/_translations/po/pt-BR/guide_structure_designing-packages.md.po @@ -0,0 +1,1034 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-06-02 22:29+0000\n" +"PO-Revision-Date: 2026-06-02 22:29+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Fenced code block (sh) +#: ../src/cookbook/using-yii-in-third-party-apps.md ../src/guide/structure/designing-packages.md ../src/guide/structure/module.md ../src/guide/structure/package.md ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "composer yii-config-rebuild\n" +msgstr "composer yii-config-rebuild\n" + +#. type: Title ## +#: ../src/guide/concept/configuration.md ../src/guide/structure/designing-packages.md ../src/guide/structure/module.md +#, no-wrap +msgid "Routes" +msgstr "Rotas" + +#. type: Title ## +#: ../src/guide/concept/configuration.md ../src/guide/concept/events.md ../src/guide/structure/designing-packages.md ../src/internals/022-config-groups.md +#, no-wrap +msgid "Events" +msgstr "Eventos" + +#. type: Title ## +#: ../src/guide/concept/configuration.md ../src/guide/structure/designing-packages.md ../src/internals/022-config-groups.md +#, no-wrap +msgid "Parameters" +msgstr "Parâmetros" + +#. type: Title ## +#: ../src/guide/databases/db-migrations.md ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "Migrations" +msgstr "Migrations" + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v2.md ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "Console commands" +msgstr "Comandos de console" + +#. type: Title # +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "Designing packages for Yii applications" +msgstr "Projetando pacotes para aplicações Yii" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "This page describes how to design a Composer package that adds behavior to a Yii application through configuration. Use it when your package needs to register services, routes, events, commands, assets, migrations, translations, or a theme." +msgstr "Esta página descreve como projetar um pacote Composer que acrescenta comportamento a uma aplicação Yii por meio de configuração. Use-a quando o seu pacote precisar registrar serviços, rotas, eventos, comandos, assets, migrations, traduções ou um tema." + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "For installing and updating packages in an application, see [Using packages](package.md)." +msgstr "Para instalar e atualizar pacotes em uma aplicação, veja [Usando pacotes](package.md)." + +#. type: Title ## +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "Composer metadata" +msgstr "Metadados do Composer" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Each package must have a `composer.json` file in its root directory. At minimum, define a package name, dependencies, autoloading, and Yii config metadata when the package integrates with a Yii application." +msgstr "Todo pacote precisa ter um arquivo `composer.json` na pasta raiz. No mínimo, defina o nome do pacote, as dependências, o autoload e os metadados de configuração do Yii quando o pacote se integra a uma aplicação Yii." + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Use a package name in the `vendor-name/project-name` format:" +msgstr "Use um nome de pacote no formato `vendor-name/project-name`:" + +#. type: Fenced code block (json) +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "" +"{\n" +" \"name\": \"vendor/blog\",\n" +" \"type\": \"library\",\n" +" \"description\": \"Blog integration for Yii applications\",\n" +" \"require\": {\n" +" \"php\": \">=8.2\",\n" +" \"yiisoft/router\": \"^4.0\"\n" +" },\n" +" \"autoload\": {\n" +" \"psr-4\": {\n" +" \"Vendor\\\\Blog\\\\\": \"src/\"\n" +" }\n" +" }\n" +"}\n" +msgstr "" +"{\n" +" \"name\": \"vendor/blog\",\n" +" \"type\": \"library\",\n" +" \"description\": \"Blog integration for Yii applications\",\n" +" \"require\": {\n" +" \"php\": \">=8.2\",\n" +" \"yiisoft/router\": \"^4.0\"\n" +" },\n" +" \"autoload\": {\n" +" \"psr-4\": {\n" +" \"Vendor\\\\Blog\\\\\": \"src/\"\n" +" }\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Use stable dependency constraints for stable releases. Avoid using `yiisoft` as your vendor name because it is reserved for Yii packages." +msgstr "Use restrições de dependência estáveis em releases estáveis. Evite usar `yiisoft` como nome de vendor, porque ele é reservado para os pacotes do Yii." + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "If your package requires a Yii application, prefixing the project name with `yii-` can make that clear on Packagist." +msgstr "Se o seu pacote exige uma aplicação Yii, prefixar o nome do projeto com `yii-` pode deixar isso claro no Packagist." + +#. type: Title ## +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "Package layout" +msgstr "Estrutura do pacote" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "A Yii-aware package is a regular Composer package with PHP classes, optional resource files, and optional config files. Keep the configuration in a predictable directory and make the public API explicit:" +msgstr "Um pacote compatível com o Yii é um pacote Composer comum, com classes PHP, arquivos de recursos opcionais e arquivos de configuração opcionais. Mantenha a configuração em uma pasta previsível e deixe a API pública explícita:" + +#. type: Fenced code block +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "" +"composer.json\n" +"config/\n" +" params.php\n" +" di.php\n" +" di-providers.php\n" +" routes.php\n" +" events.php\n" +" params-web.php\n" +" params-console.php\n" +" di-console.php\n" +"src/\n" +" ...\n" +"assets/\n" +" ...\n" +"migrations/\n" +" ...\n" +"messages/\n" +" ...\n" +"views/\n" +" ...\n" +msgstr "" +"composer.json\n" +"config/\n" +" params.php\n" +" di.php\n" +" di-providers.php\n" +" routes.php\n" +" events.php\n" +" params-web.php\n" +" params-console.php\n" +" di-console.php\n" +"src/\n" +" ...\n" +"assets/\n" +" ...\n" +"migrations/\n" +" ...\n" +"messages/\n" +" ...\n" +"views/\n" +" ...\n" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Use only the files your package needs. For example, a package with console commands but no web routes does not need `routes.php`." +msgstr "Use apenas os arquivos de que o seu pacote precisa. Por exemplo, um pacote com comandos de console, mas sem rotas web, não precisa de `routes.php`." + +#. type: Title ## +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "Config plugin metadata" +msgstr "Metadados do plugin de configuração" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Yii applications use [yiisoft/config](https://github.com/yiisoft/config) to discover package configuration. Declare package config files in the `extra.config-plugin` section of `composer.json`:" +msgstr "Aplicações Yii usam o [yiisoft/config](https://github.com/yiisoft/config) para descobrir a configuração dos pacotes. Declare os arquivos de configuração do pacote na seção `extra.config-plugin` do `composer.json`:" + +#. type: Fenced code block (json) +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "" +"{\n" +" \"name\": \"vendor/blog\",\n" +" \"type\": \"library\",\n" +" \"autoload\": {\n" +" \"psr-4\": {\n" +" \"Vendor\\\\Blog\\\\\": \"src/\"\n" +" }\n" +" },\n" +" \"extra\": {\n" +" \"config-plugin\": {\n" +" \"params\": \"config/params.php\",\n" +" \"di\": \"config/di.php\",\n" +" \"di-providers\": \"config/di-providers.php\",\n" +" \"routes\": \"config/routes.php\",\n" +" \"events\": \"config/events.php\",\n" +" \"params-web\": \"config/params-web.php\",\n" +" \"params-console\": \"config/params-console.php\",\n" +" \"di-console\": \"config/di-console.php\"\n" +" }\n" +" }\n" +"}\n" +msgstr "" +"{\n" +" \"name\": \"vendor/blog\",\n" +" \"type\": \"library\",\n" +" \"autoload\": {\n" +" \"psr-4\": {\n" +" \"Vendor\\\\Blog\\\\\": \"src/\"\n" +" }\n" +" },\n" +" \"extra\": {\n" +" \"config-plugin\": {\n" +" \"params\": \"config/params.php\",\n" +" \"di\": \"config/di.php\",\n" +" \"di-providers\": \"config/di-providers.php\",\n" +" \"routes\": \"config/routes.php\",\n" +" \"events\": \"config/events.php\",\n" +" \"params-web\": \"config/params-web.php\",\n" +" \"params-console\": \"config/params-console.php\",\n" +" \"di-console\": \"config/di-console.php\"\n" +" }\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Each `config-plugin` key is a config group name and each value is a path relative to the package root." +msgstr "Cada chave de `config-plugin` é o nome de um grupo de configuração, e cada valor é um caminho relativo à raiz do pacote." + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Use the common, web, and console groups consistently:" +msgstr "Use os grupos comuns, web e de console de forma consistente:" + +#. type: Bullet: '- ' +#: ../src/guide/structure/designing-packages.md +msgid "`params`, `di`, `di-providers`, `di-delegates`, `events`, and `bootstrap` apply to both web and console entry points." +msgstr "`params`, `di`, `di-providers`, `di-delegates`, `events` e `bootstrap` valem para os pontos de entrada web e de console." + +#. type: Bullet: '- ' +#: ../src/guide/structure/designing-packages.md +msgid "`params-web`, `di-web`, `di-providers-web`, `events-web`, `bootstrap-web`, and `routes` apply to web entry points." +msgstr "`params-web`, `di-web`, `di-providers-web`, `events-web`, `bootstrap-web` e `routes` valem para os pontos de entrada web." + +#. type: Bullet: '- ' +#: ../src/guide/structure/designing-packages.md +msgid "`params-console`, `di-console`, `di-providers-console`, `events-console`, and `bootstrap-console` apply to console entry points." +msgstr "`params-console`, `di-console`, `di-providers-console`, `events-console` e `bootstrap-console` valem para os pontos de entrada de console." + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "If your package defines a new config group, document how an application should load that group. Prefer the standard groups when you integrate with Yii services because application templates and Yii packages already use these names." +msgstr "Se o seu pacote define um novo grupo de configuração, documente como a aplicação deve carregar esse grupo. Prefira os grupos padrão ao se integrar com serviços do Yii, porque os templates de aplicação e os pacotes do Yii já usam esses nomes." + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "After users install, update, remove, or dump Composer autoload files, the config plugin rebuilds the merge plan that Yii reads at runtime. If users edit their root package configuration manually, ask them to run:" +msgstr "Depois que os usuários instalam, atualizam, removem ou fazem dump dos arquivos de autoload do Composer, o plugin de configuração reconstrói o merge plan que o Yii lê em tempo de execução. Se os usuários editarem manualmente a configuração do pacote raiz, peça que executem:" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Put default options in `config/params.php`. Group package parameters under the Composer package name to avoid collisions:" +msgstr "Coloque as opções padrão em `config/params.php`. Agrupe os parâmetros do pacote sob o nome do pacote no Composer para evitar colisões:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "" +" [\n" +" 'postsPerPage' => 20,\n" +" 'cacheTtl' => 3600,\n" +" ],\n" +"];\n" +msgstr "" +" [\n" +" 'postsPerPage' => 20,\n" +" 'cacheTtl' => 3600,\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Application developers can override these values in their own `config/common/params.php`, `config/web/params.php`, `config/console/params.php`, or environment-specific parameter files." +msgstr "Os desenvolvedores da aplicação podem sobrescrever esses valores nos próprios `config/common/params.php`, `config/web/params.php`, `config/console/params.php` ou nos arquivos de parâmetros específicos de cada ambiente." + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Do not read environment variables or global state from package code when a parameter can express the choice. Use parameters to configure services through DI definitions or service providers." +msgstr "Não leia variáveis de ambiente nem estado global no código do pacote quando um parâmetro puder expressar a escolha. Use parâmetros para configurar serviços por meio de definições de DI ou service providers." + +#. type: Title ## +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "DI definitions" +msgstr "Definições de DI" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Use `config/di.php`, `config/di-web.php`, or `config/di-console.php` for direct container definitions:" +msgstr "Use `config/di.php`, `config/di-web.php` ou `config/di-console.php` para definições diretas do container:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "" +" [\n" +" 'class' => PostRepository::class,\n" +" '__construct()' => [\n" +" 'cacheTtl' => $params['vendor/blog']['cacheTtl'],\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +" [\n" +" 'class' => PostRepository::class,\n" +" '__construct()' => [\n" +" 'cacheTtl' => $params['vendor/blog']['cacheTtl'],\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Prefer direct DI definitions when the configuration describes one service clearly." +msgstr "Prefira definições de DI diretas quando a configuração descreve um serviço de forma clara." + +#. type: Title ## +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "DI service providers" +msgstr "Service providers de DI" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Use a DI provider when registration belongs together as a reusable unit: several related services, aliases, factory definitions, or extensions." +msgstr "Use um provider de DI quando o registro forma uma unidade reutilizável: vários serviços relacionados, aliases, definições de factory ou extensões." + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Register providers in `config/di-providers.php`:" +msgstr "Registre os providers em `config/di-providers.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "" +" BlogProvider::class,\n" +"];\n" +msgstr "" +" BlogProvider::class,\n" +"];\n" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Declare the group in `composer.json`:" +msgstr "Declare o grupo no `composer.json`:" + +#. type: Fenced code block (json) +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "" +"\"extra\": {\n" +" \"config-plugin\": {\n" +" \"di-providers\": \"config/di-providers.php\"\n" +" }\n" +"}\n" +msgstr "" +"\"extra\": {\n" +" \"config-plugin\": {\n" +" \"di-providers\": \"config/di-providers.php\"\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "A provider can return several service definitions and extensions. Place the provider class in `src/Provider/BlogProvider.php`:" +msgstr "Um provider pode retornar várias definições de serviços e extensões. Coloque a classe do provider em `src/Provider/BlogProvider.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "" +" PostRepository::class,\n" +" PostRepositoryInterface::class => static fn (\n" +" ContainerInterface $container\n" +" ): CachedPostRepository => new CachedPostRepository(\n" +" $container->get(PostRepository::class),\n" +" $container->get(LoggerInterface::class),\n" +" ),\n" +" ];\n" +" }\n" +"\n" +" public function getExtensions(): array\n" +" {\n" +" return [];\n" +" }\n" +"}\n" +msgstr "" +" PostRepository::class,\n" +" PostRepositoryInterface::class => static fn (\n" +" ContainerInterface $container\n" +" ): CachedPostRepository => new CachedPostRepository(\n" +" $container->get(PostRepository::class),\n" +" $container->get(LoggerInterface::class),\n" +" ),\n" +" ];\n" +" }\n" +"\n" +" public function getExtensions(): array\n" +" {\n" +" return [];\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Web packages can add routes through `config/routes.php`, declared as the `routes` group:" +msgstr "Pacotes web podem adicionar rotas por meio de `config/routes.php`, declarado como o grupo `routes`:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "" +"routes(\n" +" Route::get('')\n" +" ->action(IndexAction::class)\n" +" ->name('vendor/blog/index'),\n" +" ),\n" +"];\n" +msgstr "" +"routes(\n" +" Route::get('')\n" +" ->action(IndexAction::class)\n" +" ->name('vendor/blog/index'),\n" +" ),\n" +"];\n" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Route names should be package-prefixed. This avoids collisions with application routes and with routes from other packages." +msgstr "Os nomes das rotas devem ter o prefixo do pacote. Isso evita colisões com as rotas da aplicação e com as rotas de outros pacotes." + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Keep package routes small and overridable. If an application needs full control over URLs, document the actions and let the application define its own routes." +msgstr "Mantenha as rotas do pacote pequenas e fáceis de sobrescrever. Se uma aplicação precisar de controle total sobre as URLs, documente as actions e deixe a aplicação definir as próprias rotas." + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Use `config/events.php`, `config/events-web.php`, or `config/events-console.php` to attach package handlers to events:" +msgstr "Use `config/events.php`, `config/events-web.php` ou `config/events-console.php` para associar handlers do pacote a eventos:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "" +" [\n" +" ClearPostListCache::class,\n" +" ],\n" +"];\n" +msgstr "" +" [\n" +" ClearPostListCache::class,\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Handlers can be closures, callables, invokable objects, invokable class names, or DI aliases supported by the event dispatcher configuration. Prefer class names for package handlers because applications can override their dependencies through the container." +msgstr "Os handlers podem ser closures, callables, objetos invocáveis, nomes de classes invocáveis ou aliases de DI suportados pela configuração do event dispatcher. Prefira nomes de classes para os handlers do pacote, porque as aplicações podem sobrescrever as dependências deles pelo container." + +#. type: Title # +#: ../src/guide/structure/designing-packages.md ../src/guide/views/asset.md +#, no-wrap +msgid "Assets" +msgstr "Assets" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "If your package ships CSS, JavaScript, images, or fonts, define asset bundles as PHP classes. For example, place this class in `src/Asset/BlogAsset.php`:" +msgstr "Se o seu pacote traz CSS, JavaScript, imagens ou fontes, defina asset bundles como classes PHP. Por exemplo, coloque esta classe em `src/Asset/BlogAsset.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "" +"register(BlogAsset::class);\n" +msgstr "$assetManager->register(BlogAsset::class);\n" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Use `$sourcePath` for files shipped inside the package. Use `$basePath` and `$baseUrl` as the public target where the asset manager publishes them." +msgstr "Use `$sourcePath` para os arquivos que vêm dentro do pacote. Use `$basePath` e `$baseUrl` como o destino público onde o asset manager os publica." + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Packages that need database schema changes should ship migrations and add their namespace or path to `yiisoft/db-migration` parameters." +msgstr "Pacotes que precisam de mudanças no esquema do banco de dados devem trazer migrations e adicionar o namespace ou o caminho delas aos parâmetros do `yiisoft/db-migration`." + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "For namespaced migrations:" +msgstr "Para migrations com namespace:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "" +" [\n" +" 'sourceNamespaces' => [\n" +" 'Vendor\\\\Blog\\\\Migration',\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +" [\n" +" 'sourceNamespaces' => [\n" +" 'Vendor\\\\Blog\\\\Migration',\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "For path-based migrations:" +msgstr "Para migrations baseadas em caminho:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "" +" [\n" +" 'sourcePaths' => [\n" +" __DIR__ . '/../migrations',\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +" [\n" +" 'sourcePaths' => [\n" +" __DIR__ . '/../migrations',\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Put this in `config/params-console.php` and declare it as `params-console` in `composer.json`." +msgstr "Coloque isso em `config/params-console.php` e declare-o como `params-console` no `composer.json`." + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "This only contributes package migration locations. The application still needs `yiisoft/db-migration` installed and a database connection configured before migration commands can run." +msgstr "Isso apenas informa os locais das migrations do pacote. A aplicação ainda precisa ter o `yiisoft/db-migration` instalado e uma conexão com o banco de dados configurada antes que os comandos de migration possam rodar." + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Package migrations must be stable after release. Do not edit a migration that users may already have applied. Add a new migration instead." +msgstr "As migrations do pacote devem ficar estáveis depois do release. Não edite uma migration que os usuários talvez já tenham aplicado. Em vez disso, adicione uma nova migration." + +#. type: Title ## +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "Translations" +msgstr "Traduções" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "If the package has user-facing messages, give it a dedicated translation category and register a category source in `config/di.php`:" +msgstr "Se o pacote tem mensagens exibidas ao usuário, dê a ele uma categoria de tradução própria e registre uma category source em `config/di.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "" +" [\n" +" 'definition' => static function (): CategorySource {\n" +" $messageSource = new MessageSource(__DIR__ . '/../messages');\n" +"\n" +" return new CategorySource(\n" +" 'vendor-blog',\n" +" $messageSource,\n" +" new IntlMessageFormatter(),\n" +" $messageSource,\n" +" );\n" +" },\n" +" 'tags' => ['translation.categorySource'],\n" +" ],\n" +"];\n" +msgstr "" +" [\n" +" 'definition' => static function (): CategorySource {\n" +" $messageSource = new MessageSource(__DIR__ . '/../messages');\n" +"\n" +" return new CategorySource(\n" +" 'vendor-blog',\n" +" $messageSource,\n" +" new IntlMessageFormatter(),\n" +" $messageSource,\n" +" );\n" +" },\n" +" 'tags' => ['translation.categorySource'],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Store messages by locale and category:" +msgstr "Guarde as mensagens por locale e categoria:" + +#. type: Fenced code block +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "" +"messages/\n" +" en-US/\n" +" vendor-blog.php\n" +" de/\n" +" vendor-blog.php\n" +msgstr "" +"messages/\n" +" en-US/\n" +" vendor-blog.php\n" +" de/\n" +" vendor-blog.php\n" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Use the explicit category when translating:" +msgstr "Use a categoria explícita ao traduzir:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "$translator->translate('post.created', category: 'vendor-blog');\n" +msgstr "$translator->translate('post.created', category: 'vendor-blog');\n" + +#. type: Title ## +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "Themes" +msgstr "Temas" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "A package can ship view files and assets for a theme. Do not activate it from vendor package configuration. Instead, document the root application configuration needed to enable it. For the application template, this belongs in `config/web/params.php`:" +msgstr "Um pacote pode trazer arquivos de view e assets para um tema. Não o ative pela configuração do pacote em vendor. Em vez disso, documente a configuração da aplicação raiz necessária para habilitá-lo. No template de aplicação, isso fica em `config/web/params.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "" +" [\n" +" 'theme' => [\n" +" 'pathMap' => [\n" +" '@views' => '@vendor/vendor/blog/views',\n" +" ],\n" +" 'basePath' => '@vendor/vendor/blog/assets',\n" +" 'baseUrl' => '@assetsUrl/vendor-blog',\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +" [\n" +" 'theme' => [\n" +" 'pathMap' => [\n" +" '@views' => '@vendor/vendor/blog/views',\n" +" ],\n" +" 'basePath' => '@vendor/vendor/blog/assets',\n" +" 'baseUrl' => '@assetsUrl/vendor-blog',\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Themes replace view paths according to a path map. Document which application view paths your theme replaces and which asset URL must be published or exposed by the application." +msgstr "Os temas substituem caminhos de views de acordo com um mapa de caminhos. Documente quais caminhos de views da aplicação o seu tema substitui e qual URL de assets a aplicação precisa publicar ou expor." + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Do not set `yiisoft/view.theme` directly in vendor package configuration. `yiisoft/view` already defines that key, and duplicate keys in the same configuration layer are not allowed." +msgstr "Não defina `yiisoft/view.theme` diretamente na configuração do pacote em vendor. O `yiisoft/view` já define essa chave, e chaves duplicadas na mesma camada de configuração não são permitidas." + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "If your package only provides optional theme files, do not make the theme active by default. Provide the view files, asset bundle, and a documented parameter snippet so the application can opt in." +msgstr "Se o seu pacote fornece apenas arquivos de tema opcionais, não deixe o tema ativo por padrão. Forneça os arquivos de view, o asset bundle e um trecho de parâmetros documentado, para que a aplicação possa optar por usá-lo." + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Console packages can add Symfony Console commands through `config/params-console.php`:" +msgstr "Pacotes de console podem adicionar comandos do Symfony Console por meio de `config/params-console.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "" +" [\n" +" 'commands' => [\n" +" 'blog/reindex' => ReindexCommand::class,\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +" [\n" +" 'commands' => [\n" +" 'blog/reindex' => ReindexCommand::class,\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Command names should be package-prefixed. Keep command dependencies constructor-injected and registered through DI." +msgstr "Os nomes dos comandos devem ter o prefixo do pacote. Mantenha as dependências dos comandos injetadas pelo construtor e registradas via DI." + +#. type: Title ## +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "Application overrides" +msgstr "Sobrescritas pela aplicação" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Package configuration is the default layer. The application can override it in its root package configuration. Design for that:" +msgstr "A configuração do pacote é a camada padrão. A aplicação pode sobrescrevê-la na configuração do pacote raiz. Projete pensando nisso:" + +#. type: Bullet: '- ' +#: ../src/guide/structure/designing-packages.md +msgid "Use package-prefixed parameter keys, route names, event handler IDs, and DI aliases." +msgstr "Use chaves de parâmetros, nomes de rotas, IDs de handlers de eventos e aliases de DI com o prefixo do pacote." + +#. type: Bullet: '- ' +#: ../src/guide/structure/designing-packages.md +msgid "Keep default configuration small and documented." +msgstr "Mantenha a configuração padrão pequena e documentada." + +#. type: Bullet: '- ' +#: ../src/guide/structure/designing-packages.md +msgid "Avoid doing irreversible work during service registration." +msgstr "Evite fazer trabalho irreversível durante o registro de serviços." + +#. type: Bullet: '- ' +#: ../src/guide/structure/designing-packages.md +msgid "Put optional integrations in separate config files or providers when they require optional Composer packages." +msgstr "Coloque integrações opcionais em arquivos de configuração ou providers separados quando elas exigirem pacotes Composer opcionais." + +#. type: Bullet: '- ' +#: ../src/guide/structure/designing-packages.md +msgid "Test the package inside a minimal Yii application so the config plugin, DI container, routes, console commands, migrations, translations, and assets are exercised together." +msgstr "Teste o pacote dentro de uma aplicação Yii mínima, para que o plugin de configuração, o container de DI, as rotas, os comandos de console, as migrations, as traduções e os assets sejam exercitados juntos." + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "When a user needs to customize package configuration, they usually do not need to copy the package config file. They can partially redefine the needed keys in the application configuration." +msgstr "Quando um usuário precisa personalizar a configuração do pacote, normalmente não precisa copiar o arquivo de configuração do pacote. Ele pode redefinir parcialmente as chaves necessárias na configuração da aplicação." + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "After changing config group mappings, they should rebuild the merge plan with:" +msgstr "Depois de alterar os mapeamentos de grupos de configuração, ele deve reconstruir o merge plan com:" + +#. type: Title ## +#: ../src/guide/structure/designing-packages.md +#, no-wrap +msgid "Releasing packages" +msgstr "Publicando pacotes" + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Before tagging a release, test the package by itself and inside a minimal Yii application. Include a `README.md`, `CHANGELOG.md`, and `UPGRADE.md` when behavior or configuration changes require explanation." +msgstr "Antes de criar a tag de um release, teste o pacote isoladamente e dentro de uma aplicação Yii mínima. Inclua `README.md`, `CHANGELOG.md` e `UPGRADE.md` quando mudanças de comportamento ou de configuração precisarem de explicação." + +#. type: Plain text +#: ../src/guide/structure/designing-packages.md +msgid "Use [semantic versioning](https://semver.org) for public releases. After the first release, do not edit migrations that users may already have applied; add new migrations instead." +msgstr "Use [versionamento semântico](https://semver.org) nos releases públicos. Depois do primeiro release, não edite migrations que os usuários talvez já tenham aplicado; adicione novas migrations." diff --git a/_translations/po/pt-BR/guide_structure_entry-script.md.po b/_translations/po/pt-BR/guide_structure_entry-script.md.po new file mode 100644 index 00000000..59b06479 --- /dev/null +++ b/_translations/po/pt-BR/guide_structure_entry-script.md.po @@ -0,0 +1,267 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-10-07 15:22+0000\n" +"PO-Revision-Date: 2026-10-07 15:22+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/structure/entry-script.md +#, no-wrap +msgid "Entry scripts" +msgstr "Scripts de entrada" + +#. type: Plain text +#: ../src/guide/structure/entry-script.md +msgid "Entry scripts are the first step in the application bootstrapping process. An application (either Web application or console application) has a single entry script. End users make requests to entry scripts which instantiate application instances and forward the requests to them." +msgstr "Os scripts de entrada são o primeiro passo no processo de inicialização da aplicação. Uma aplicação (seja web ou de console) tem um único script de entrada. Os usuários finais fazem requisições aos scripts de entrada, que instanciam a aplicação e encaminham as requisições para ela." + +#. type: Plain text +#: ../src/guide/structure/entry-script.md +msgid "Entry scripts for Web applications must be stored under Web-accessible directories so that they can be accessed by end users. They're often named as `index.php`, but can also use any other names, provided Web servers can locate them." +msgstr "Os scripts de entrada de aplicações web devem ficar em pastas acessíveis pela web, para que os usuários finais possam acessá-los. Eles costumam se chamar `index.php`, mas podem ter qualquer outro nome, desde que os servidores web consigam localizá-los." + +#. type: Plain text +#: ../src/guide/structure/entry-script.md +msgid "Entry script for console application is `./yii`." +msgstr "O script de entrada da aplicação de console é `./yii`." + +#. type: Plain text +#: ../src/guide/structure/entry-script.md +msgid "Entry scripts mainly perform the following work with the help of `ApplicationRunner`:" +msgstr "Os scripts de entrada fazem principalmente o seguinte, com a ajuda do `ApplicationRunner`:" + +#. type: Bullet: '* ' +#: ../src/guide/structure/entry-script.md +msgid "Register [Composer autoloader](https://getcomposer.org/doc/01-basic-usage.md#autoloading);" +msgstr "Registram o [autoloader do Composer](https://getcomposer.org/doc/01-basic-usage.md#autoloading);" + +#. type: Bullet: '* ' +#: ../src/guide/structure/entry-script.md +msgid "Obtain configuration;" +msgstr "Obtêm a configuração;" + +#. type: Bullet: '* ' +#: ../src/guide/structure/entry-script.md +msgid "Use configuration to initialize a dependency injection container;" +msgstr "Usam a configuração para inicializar um container de injeção de dependência;" + +#. type: Bullet: '* ' +#: ../src/guide/structure/entry-script.md +msgid "Get an instance of the request." +msgstr "Obtêm uma instância da requisição." + +#. type: Bullet: '* ' +#: ../src/guide/structure/entry-script.md +msgid "Pass it to `Application` to handle and get a response from it." +msgstr "Passam-na para a `Application` tratar e obtêm dela uma resposta." + +#. type: Bullet: '* ' +#: ../src/guide/structure/entry-script.md +msgid "With the help of an emitter that transforms a response object into an actual HTTP response that's sent to the client browser." +msgstr "Com a ajuda de um emitter, transformam o objeto de resposta em uma resposta HTTP real, que é enviada ao navegador do cliente." + +#. type: Title ## +#: ../src/guide/structure/entry-script.md +#, no-wrap +msgid "Web Applications" +msgstr "Aplicações web" + +#. type: Plain text +#: ../src/guide/structure/entry-script.md +msgid "The following is the code in the entry script for the application template:" +msgstr "Este é o código do script de entrada do template de aplicação:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/entry-script.md +#, no-wrap +msgid "" +"debug();\n" +"// Run application:\n" +"$runner->run();\n" +msgstr "" +"debug();\n" +"// Executa a aplicação:\n" +"$runner->run();\n" + +#. type: Title ## +#: ../src/guide/structure/entry-script.md +#, no-wrap +msgid "Console Applications" +msgstr "Aplicações de console" + +#. type: Plain text +#: ../src/guide/structure/entry-script.md +msgid "Similarly, the following is the code for the entry script of a console application:" +msgstr "Da mesma forma, este é o código do script de entrada de uma aplicação de console:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/entry-script.md +#, no-wrap +msgid "" +"#!/usr/bin/env php\n" +"withDefinitions($config->get('console'))\n" +" ->withProviders($config->get('providers-console'));\n" +"$container = new Container($containerConfig);\n" +"\n" +"/** @var ContainerInterface $container */\n" +"$container = $container->get(ContainerInterface::class);\n" +"\n" +"$application = $container->get(Application::class);\n" +"$exitCode = 1;\n" +"\n" +"try {\n" +" $application->start();\n" +" $exitCode = $application->run(null, new ConsoleBufferedOutput());\n" +"} catch (\\Error $error) {\n" +" $application->renderThrowable($error, new ConsoleBufferedOutput());\n" +"} finally {\n" +" $application->shutdown($exitCode);\n" +" exit($exitCode);\n" +"}\n" +msgstr "" +"#!/usr/bin/env php\n" +"withDefinitions($config->get('console'))\n" +" ->withProviders($config->get('providers-console'));\n" +"$container = new Container($containerConfig);\n" +"\n" +"/** @var ContainerInterface $container */\n" +"$container = $container->get(ContainerInterface::class);\n" +"\n" +"$application = $container->get(Application::class);\n" +"$exitCode = 1;\n" +"\n" +"try {\n" +" $application->start();\n" +" $exitCode = $application->run(null, new ConsoleBufferedOutput());\n" +"} catch (\\Error $error) {\n" +" $application->renderThrowable($error, new ConsoleBufferedOutput());\n" +"} finally {\n" +" $application->shutdown($exitCode);\n" +" exit($exitCode);\n" +"}\n" + +#. type: Title ## +#: ../src/guide/structure/entry-script.md +#, no-wrap +msgid "Alternative runtimes" +msgstr "Runtimes alternativos" + +#. type: Plain text +#: ../src/guide/structure/entry-script.md +msgid "For alternative runtimes such as FrankenPHP, Rapira, RoadRunner, or Swoole, special entry scripts should be used. See:" +msgstr "Para runtimes alternativos como FrankenPHP, Rapira, RoadRunner ou Swoole, devem ser usados scripts de entrada especiais. Veja:" + +#. type: Bullet: '- ' +#: ../src/guide/structure/entry-script.md +msgid "[Using Yii with FrankenPHP](../tutorial/using-yii-with-frankenphp.md)" +msgstr "[Usando o Yii com FrankenPHP](../tutorial/using-yii-with-frankenphp.md)" + +#. type: Bullet: '- ' +#: ../src/guide/structure/entry-script.md +msgid "[Using Yii with Rapira](../tutorial/using-yii-with-rapira.md)" +msgstr "[Usando o Yii com Rapira](../tutorial/using-yii-with-rapira.md)" + +#. type: Bullet: '- ' +#: ../src/guide/structure/entry-script.md +msgid "[Using Yii with RoadRunner](../tutorial/using-yii-with-roadrunner.md)" +msgstr "[Usando o Yii com RoadRunner](../tutorial/using-yii-with-roadrunner.md)" + +#. type: Bullet: '- ' +#: ../src/guide/structure/entry-script.md +msgid "[Using Yii with Swoole](../tutorial/using-yii-with-swoole.md)" +msgstr "[Usando o Yii com Swoole](../tutorial/using-yii-with-swoole.md)" diff --git a/_translations/po/pt-BR/guide_structure_middleware.md.po b/_translations/po/pt-BR/guide_structure_middleware.md.po new file mode 100644 index 00000000..1477dc46 --- /dev/null +++ b/_translations/po/pt-BR/guide_structure_middleware.md.po @@ -0,0 +1,402 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-06-29 17:10+0000\n" +"PO-Revision-Date: 2026-06-29 17:10+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "Middleware" +msgstr "Middleware" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "Yii works with HTTP using the abstraction layer built around [PSR-7 HTTP message interfaces](https://www.php-fig.org/psr/psr-7/) and [PSR-15 request handler/middleware interfaces](https://www.php-fig.org/psr/psr-15/)." +msgstr "O Yii trabalha com HTTP usando a camada de abstração construída em torno das [interfaces de mensagens HTTP da PSR-7](https://www.php-fig.org/psr/psr-7/) e das [interfaces de request handler/middleware da PSR-15](https://www.php-fig.org/psr/psr-15/)." + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "The application is composed of one or several middleware. Middleware runs between request and response. When the URL is requested, the request object is passed to the middleware dispatcher that starts executing middleware one after another. Each middleware, given the request, can:" +msgstr "A aplicação é composta por um ou vários middlewares. O middleware roda entre a requisição e a resposta. Quando a URL é requisitada, o objeto de requisição é passado para o dispatcher de middlewares, que começa a executar os middlewares um após o outro. Cada middleware, dada a requisição, pode:" + +#. type: Bullet: '- ' +#: ../src/guide/structure/middleware.md +msgid "Pass the request to the next middleware performing some work before / after it." +msgstr "Passar a requisição para o próximo middleware, fazendo algum trabalho antes / depois dele." + +#. type: Bullet: '- ' +#: ../src/guide/structure/middleware.md +msgid "Form the response and return it." +msgstr "Montar a resposta e devolvê-la." + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "Depending on middleware used, application behavior may vary significantly." +msgstr "Dependendo dos middlewares usados, o comportamento da aplicação pode variar bastante." + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "![Middleware](/images/guide/middleware.svg)" +msgstr "![Middleware](/images/guide/middleware.svg)" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "In the above each next middleware wraps the previous middleware. Alternatively, it could be presented as follows:" +msgstr "Acima, cada middleware seguinte envolve o anterior. Também é possível representar assim:" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "![Middleware](/images/guide/middleware_alternative.svg)" +msgstr "![Middleware](/images/guide/middleware_alternative.svg)" + +#. type: Title ## +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "Using middleware" +msgstr "Usando middlewares" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "Any [PSR-15](https://www.php-fig.org/psr/psr-15/) compatible middleware could be used with Yii, and there are many. Say, you need to add basic authentication to one of the application URLs. URL-dependent middleware is configured using router, so you need to change the router factory." +msgstr "Qualquer middleware compatível com a [PSR-15](https://www.php-fig.org/psr/psr-15/) pode ser usado com o Yii, e existem muitos. Digamos que você precise adicionar autenticação básica a uma das URLs da aplicação. Middlewares que dependem da URL são configurados pelo router, então você precisa alterar a router factory." + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "Authentication middleware is implemented by `middlewares/http-authentication` package so execute `composer require middlewares/http-authentication` in the application root directory." +msgstr "O middleware de autenticação é implementado pelo pacote `middlewares/http-authentication`, então execute `composer require middlewares/http-authentication` na pasta raiz da aplicação." + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "Now register the middleware in DI container configuration `config/web.php`:" +msgstr "Agora registre o middleware na configuração do container de DI, `config/web.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "" +" [\n" +" 'class' => \\Middlewares\\BasicAuthentication::class,\n" +" '__construct()' => [\n" +" 'users' => [\n" +" 'foo' => 'bar',\n" +" ],\n" +" ],\n" +" 'realm()' => ['Access to the staging site via basic auth'],\n" +" 'attribute()' => ['username'],\n" +"],\n" +msgstr "" +" [\n" +" 'class' => \\Middlewares\\BasicAuthentication::class,\n" +" '__construct()' => [\n" +" 'users' => [\n" +" 'foo' => 'bar',\n" +" ],\n" +" ],\n" +" 'realm()' => ['Access to the staging site via basic auth'],\n" +" 'attribute()' => ['username'],\n" +"],\n" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "In the `config/routes.php`, add new route:" +msgstr "No `config/routes.php`, adicione uma nova rota:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "" +"action([SiteController::class, 'auth'])\n" +" ->name('site/auth')\n" +" ->prependMiddleware(BasicAuthentication::class)\n" +"];\n" +msgstr "" +"action([SiteController::class, 'auth'])\n" +" ->name('site/auth')\n" +" ->prependMiddleware(BasicAuthentication::class)\n" +"];\n" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "When configuring routing, you're binding `/basic-auth` URL to a chain of middleware consisting of basic authentication, and the action itself. A chain is a special middleware that executes all the middleware it's configured with." +msgstr "Ao configurar o roteamento, você está associando a URL `/basic-auth` a uma cadeia de middlewares formada pela autenticação básica e pela própria action. Uma cadeia é um middleware especial que executa todos os middlewares com que foi configurada." + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "The action itself could be the following:" +msgstr "A action em si poderia ser a seguinte:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "" +"public function auth(ServerRequestInterface $request): ResponseInterface\n" +"{\n" +" $response = $this->responseFactory->createResponse();\n" +" $response->getBody()->write('Hi ' . $request->getAttribute('username'));\n" +" return $response;\n" +"}\n" +msgstr "" +"public function auth(ServerRequestInterface $request): ResponseInterface\n" +"{\n" +" $response = $this->responseFactory->createResponse();\n" +" $response->getBody()->write('Hi ' . $request->getAttribute('username'));\n" +" return $response;\n" +"}\n" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "Basic authentication middleware wrote to request `username` attribute, so you can access the data if needed." +msgstr "O middleware de autenticação básica gravou o atributo `username` na requisição, então você pode acessar esse dado se precisar." + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "To apply middleware to application overall regardless of URL, adjust `config/application.php`:" +msgstr "Para aplicar um middleware à aplicação como um todo, independentemente da URL, ajuste o `config/application.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "" +"return [\n" +" Yiisoft\\Yii\\Http\\Application::class => [\n" +" '__construct()' => [\n" +" 'dispatcher' => DynamicReference::to(static function (Injector $injector) {\n" +" return ($injector->make(MiddlewareDispatcher::class))\n" +" ->withMiddlewares(\n" +" [\n" +" ErrorCatcher::class,\n" +" BasicAuthentication::class,\n" +" SessionMiddleware::class,\n" +" CsrfTokenMiddleware::class,\n" +" Router::class,\n" +" ]\n" +" );\n" +" }),\n" +" 'fallbackHandler' => Reference::to(NotFoundHandler::class),\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +"return [\n" +" Yiisoft\\Yii\\Http\\Application::class => [\n" +" '__construct()' => [\n" +" 'dispatcher' => DynamicReference::to(static function (Injector $injector) {\n" +" return ($injector->make(MiddlewareDispatcher::class))\n" +" ->withMiddlewares(\n" +" [\n" +" ErrorCatcher::class,\n" +" BasicAuthentication::class,\n" +" SessionMiddleware::class,\n" +" CsrfTokenMiddleware::class,\n" +" Router::class,\n" +" ]\n" +" );\n" +" }),\n" +" 'fallbackHandler' => Reference::to(NotFoundHandler::class),\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Title ## +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "Creating your own middleware" +msgstr "Criando o seu próprio middleware" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "To create middleware, you need to implement a single `process` method of `Psr\\Http\\Server\\MiddlewareInterface`:" +msgstr "Para criar um middleware, você precisa implementar um único método, `process`, da `Psr\\Http\\Server\\MiddlewareInterface`:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface;\n" +msgstr "public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface;\n" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "There are multiple ways to handle a request, and choosing one depends on what the middleware should achieve." +msgstr "Há várias formas de tratar uma requisição, e a escolha depende do que o middleware deve fazer." + +#. type: Title ### +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "Forming a response directly" +msgstr "Montando uma resposta diretamente" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "To respond directly, one needs a response factory passed via constructor:" +msgstr "Para responder diretamente, é preciso uma response factory passada pelo construtor:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "" +"responseFactory->createResponse();\n" +" $response->getBody()->write('Hello!');\n" +" return $response;\n" +" }\n" +"}\n" +msgstr "" +"responseFactory->createResponse();\n" +" $response->getBody()->write('Hello!');\n" +" return $response;\n" +" }\n" +"}\n" + +#. type: Title ### +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "Delegating handling to the next middleware" +msgstr "Delegando o tratamento para o próximo middleware" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "" +"If middleware either isn't intended to form a response or change the request or can't do anything this time,\n" +"handling could be left to the next middleware in the stack: \n" +msgstr "" +"Se o middleware não tem a intenção de montar uma resposta nem de alterar a requisição, ou se não pode fazer nada desta vez,\n" +"o tratamento pode ficar para o próximo middleware da pilha: \n" + +#. type: Fenced code block (php) +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "" +"public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface\n" +"{\n" +" return $handler->handle($request); \n" +"}\n" +msgstr "" +"public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface\n" +"{\n" +" return $handler->handle($request); \n" +"}\n" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "In case you need to pass data to the next middleware, you can use request attributes:" +msgstr "Se você precisar passar dados para o próximo middleware, pode usar atributos da requisição:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "" +"$request = $request->withAttribute('answer', 42);\n" +"return $handler->handle($request);\n" +msgstr "" +"$request = $request->withAttribute('answer', 42);\n" +"return $handler->handle($request);\n" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "To get it in the next middleware:" +msgstr "Para obtê-los no próximo middleware:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "$answer = $request->getAttribute('answer');\n" +msgstr "$answer = $request->getAttribute('answer');\n" + +#. type: Title ### +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "Capturing response to manipulate it" +msgstr "Capturando a resposta para manipulá-la" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "You may want to capture the response to manipulate it. It could be useful for adding CORS headers, gzipping content, etc." +msgstr "Você pode querer capturar a resposta para manipulá-la. Isso pode ser útil para adicionar headers CORS, compactar o conteúdo com gzip etc." + +#. type: Fenced code block (php) +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "" +"$response = $handler->handle($request);\n" +"// extra handing\n" +"return $response;\n" +msgstr "" +"$response = $handler->handle($request);\n" +"// tratamento extra\n" +"return $response;\n" diff --git a/_translations/po/pt-BR/guide_structure_module.md.po b/_translations/po/pt-BR/guide_structure_module.md.po new file mode 100644 index 00000000..8b0fecbe --- /dev/null +++ b/_translations/po/pt-BR/guide_structure_module.md.po @@ -0,0 +1,563 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-06-02 22:29+0000\n" +"PO-Revision-Date: 2026-06-02 22:29+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Fenced code block (sh) +#: ../src/cookbook/using-yii-in-third-party-apps.md ../src/guide/structure/designing-packages.md ../src/guide/structure/module.md ../src/guide/structure/package.md ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "composer yii-config-rebuild\n" +msgstr "composer yii-config-rebuild\n" + +#. type: Title ## +#: ../src/guide/concept/configuration.md ../src/guide/structure/designing-packages.md ../src/guide/structure/module.md +#, no-wrap +msgid "Routes" +msgstr "Rotas" + +#. type: Title # +#: ../src/guide/structure/module.md +#, no-wrap +msgid "Modules" +msgstr "Módulos" + +#. type: Plain text +#: ../src/guide/structure/module.md +msgid "A module is an application part grouped around a business context or a reusable feature. In Yii, this is a design boundary, not a required base class. A module can be:" +msgstr "Um módulo é uma parte da aplicação agrupada em torno de um contexto de negócio ou de um recurso reutilizável. No Yii, isso é uma fronteira de design, não uma classe base obrigatória. Um módulo pode ser:" + +#. type: Bullet: '- ' +#: ../src/guide/structure/module.md +msgid "application code under the `App\\` namespace;" +msgstr "código da aplicação no namespace `App\\`;" + +#. type: Bullet: '- ' +#: ../src/guide/structure/module.md +msgid "a [Composer package](package.md) installed into `vendor/`;" +msgstr "um [pacote Composer](package.md) instalado em `vendor/`;" + +#. type: Bullet: '- ' +#: ../src/guide/structure/module.md +msgid "code that starts in the application and is later extracted into a package." +msgstr "código que começa na aplicação e depois é extraído para um pacote." + +#. type: Plain text +#: ../src/guide/structure/module.md +msgid "Use a module when a group of actions, domain services, repositories, event handlers, views, assets, commands, and related configuration changes together and has a name that makes sense to the business." +msgstr "Use um módulo quando um grupo de actions, serviços de domínio, repositórios, handlers de eventos, views, assets, comandos e a configuração relacionada mudam juntos e têm um nome que faz sentido para o negócio." + +#. type: Plain text +#: ../src/guide/structure/module.md +msgid "For example, a blog module can live in an application as:" +msgstr "Por exemplo, um módulo de blog pode ficar na aplicação assim:" + +#. type: Fenced code block +#: ../src/guide/structure/module.md +#, no-wrap +msgid "" +"src/\n" +" Blog/\n" +" Post/\n" +" Post.php\n" +" PostRepositoryInterface.php\n" +" InMemoryPostRepository.php\n" +" Web/\n" +" IndexAction.php\n" +" index.php\n" +msgstr "" +"src/\n" +" Blog/\n" +" Post/\n" +" Post.php\n" +" PostRepositoryInterface.php\n" +" InMemoryPostRepository.php\n" +" Web/\n" +" IndexAction.php\n" +" index.php\n" + +#. type: Plain text +#: ../src/guide/structure/module.md +msgid "The same structure can later become a Composer package by changing the namespace and adding package metadata and configuration files. See [Designing packages](designing-packages.md) for package-specific details." +msgstr "A mesma estrutura pode virar um pacote Composer mais tarde, mudando o namespace e adicionando os metadados e os arquivos de configuração do pacote. Veja [Projetando pacotes](designing-packages.md) para os detalhes específicos de pacotes." + +#. type: Title ## +#: ../src/guide/structure/module.md +#, no-wrap +msgid "Module boundaries" +msgstr "Fronteiras de módulos" + +#. type: Plain text +#: ../src/guide/structure/module.md +msgid "Keep module code together by context first and by technical type second. This is close to the [vertical slices](../../cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md) approach, but at a larger application-structure boundary. Prefer `App\\Blog\\Post\\PostRepositoryInterface` over a global `App\\Repository\\PostRepositoryInterface` when the repository belongs to blog posts only." +msgstr "Mantenha o código do módulo agrupado primeiro por contexto e depois por tipo técnico. Isso se aproxima da abordagem de [vertical slices](../../cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md), mas numa fronteira maior da estrutura da aplicação. Prefira `App\\Blog\\Post\\PostRepositoryInterface` a um `App\\Repository\\PostRepositoryInterface` global quando o repositório pertence apenas aos posts do blog." + +#. type: Plain text +#: ../src/guide/structure/module.md +msgid "Treat module classes as a public API only when another module is expected to use them. Good public API classes are usually:" +msgstr "Trate as classes de um módulo como API pública apenas quando se espera que outro módulo as use. Boas classes de API pública normalmente são:" + +#. type: Bullet: '- ' +#: ../src/guide/structure/module.md +msgid "commands or queries that express a use case;" +msgstr "comandos ou queries que expressam um caso de uso;" + +#. type: Bullet: '- ' +#: ../src/guide/structure/module.md +msgid "DTOs or value objects passed between modules;" +msgstr "DTOs ou value objects trocados entre módulos;" + +#. type: Bullet: '- ' +#: ../src/guide/structure/module.md +msgid "interfaces for services another module may call;" +msgstr "interfaces de serviços que outro módulo pode chamar;" + +#. type: Bullet: '- ' +#: ../src/guide/structure/module.md +msgid "events emitted by the module." +msgstr "eventos emitidos pelo módulo." + +#. type: Plain text +#: ../src/guide/structure/module.md +msgid "Keep implementation classes private to the module namespace. Other modules should not depend on `App\\Blog\\Post\\InMemoryPostRepository` or a controller action directly. They should depend on an interface, a use case class, or an event." +msgstr "Mantenha as classes de implementação privadas ao namespace do módulo. Outros módulos não devem depender diretamente de `App\\Blog\\Post\\InMemoryPostRepository` ou de uma action de controller. Eles devem depender de uma interface, de uma classe de caso de uso ou de um evento." + +#. type: Title ## +#: ../src/guide/structure/module.md +#, no-wrap +msgid "Interfaces between modules" +msgstr "Interfaces entre módulos" + +#. type: Plain text +#: ../src/guide/structure/module.md +msgid "Put an interface where the contract belongs:" +msgstr "Coloque a interface onde o contrato pertence:" + +#. type: Bullet: '- ' +#: ../src/guide/structure/module.md +msgid "If the interface describes a capability provided by a module, place it in that module. For example, `App\\Blog\\Post\\PostRepositoryInterface` belongs to the blog module because it describes how blog posts are read." +msgstr "Se a interface descreve uma capacidade fornecida por um módulo, coloque-a nesse módulo. Por exemplo, `App\\Blog\\Post\\PostRepositoryInterface` pertence ao módulo de blog porque descreve como os posts do blog são lidos." + +#. type: Bullet: '- ' +#: ../src/guide/structure/module.md +msgid "If the interface describes what a module needs from the outside world, place it in the consuming module. For example, `App\\Order\\Customer\\CustomerVerifierInterface` belongs to the order module if orders only need a yes-or-no customer check. The customer module, an application adapter, or a package can provide the implementation." +msgstr "Se a interface descreve o que um módulo precisa do mundo externo, coloque-a no módulo consumidor. Por exemplo, `App\\Order\\Customer\\CustomerVerifierInterface` pertence ao módulo de pedidos se os pedidos só precisam de uma verificação de cliente do tipo sim ou não. O módulo de clientes, um adaptador da aplicação ou um pacote pode fornecer a implementação." + +#. type: Plain text +#: ../src/guide/structure/module.md +msgid "This keeps dependencies explicit. A module can depend on another module's public contract, but it should not reach into another module's internal implementation classes." +msgstr "Isso mantém as dependências explícitas. Um módulo pode depender do contrato público de outro módulo, mas não deve acessar as classes de implementação internas de outro módulo." + +#. type: Plain text +#: ../src/guide/structure/module.md +msgid "First, define the interface in the module:" +msgstr "Primeiro, defina a interface no módulo:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/module.md +#, no-wrap +msgid "" +"\n" +" */\n" +" public function findLatest(): array;\n" +"}\n" +msgstr "" +"\n" +" */\n" +" public function findLatest(): array;\n" +"}\n" + +#. type: Plain text +#: ../src/guide/structure/module.md +msgid "Put the implementation in the same module and bind the interface to it:" +msgstr "Coloque a implementação no mesmo módulo e associe a interface a ela:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/module.md +#, no-wrap +msgid "" +" InMemoryPostRepository::class,\n" +"];\n" +msgstr "" +" InMemoryPostRepository::class,\n" +"];\n" + +#. type: Plain text +#: ../src/guide/structure/module.md +msgid "In the default application template, put this file under `config/common/di/`, for example `config/common/di/blog.php`. The template loads `config/common/di/*.php` into the shared `di` configuration group, so the binding is available to web and console entry points." +msgstr "No template de aplicação padrão, coloque esse arquivo em `config/common/di/`, por exemplo `config/common/di/blog.php`. O template carrega `config/common/di/*.php` no grupo de configuração compartilhado `di`, então a associação fica disponível para os pontos de entrada web e de console." + +#. type: Title ## +#: ../src/guide/structure/module.md +#, no-wrap +msgid "Web actions" +msgstr "Actions web" + +#. type: Plain text +#: ../src/guide/structure/module.md +msgid "Actions belong to the module when they are the web entry point for module behavior:" +msgstr "As actions pertencem ao módulo quando são o ponto de entrada web do comportamento do módulo:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/module.md +#, no-wrap +msgid "" +"viewRenderer->render(__DIR__ . '/index', [\n" +" 'posts' => $this->posts->findLatest(),\n" +" ]);\n" +" }\n" +"}\n" +msgstr "" +"viewRenderer->render(__DIR__ . '/index', [\n" +" 'posts' => $this->posts->findLatest(),\n" +" ]);\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/structure/module.md +msgid "Keep request parsing and response creation in the action. Keep business decisions in the module's domain classes or use case services." +msgstr "Mantenha a leitura da requisição e a criação da resposta na action. Mantenha as decisões de negócio nas classes de domínio do módulo ou em serviços de caso de uso." + +#. type: Plain text +#: ../src/guide/structure/module.md +msgid "For a small application, add module routes directly to `config/common/routes.php`:" +msgstr "Em uma aplicação pequena, adicione as rotas do módulo diretamente em `config/common/routes.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/module.md +#, no-wrap +msgid "" +"routes(\n" +" Route::get('/')\n" +" ->action(Web\\HomePage\\Action::class)\n" +" ->name('home'),\n" +" ),\n" +"\n" +" Group::create('/blog')\n" +" ->routes(\n" +" Route::get('')\n" +" ->action(IndexAction::class)\n" +" ->name('blog/index'),\n" +" ),\n" +"];\n" +msgstr "" +"routes(\n" +" Route::get('/')\n" +" ->action(Web\\HomePage\\Action::class)\n" +" ->name('home'),\n" +" ),\n" +"\n" +" Group::create('/blog')\n" +" ->routes(\n" +" Route::get('')\n" +" ->action(IndexAction::class)\n" +" ->name('blog/index'),\n" +" ),\n" +"];\n" + +#. type: Plain text +#: ../src/guide/structure/module.md +msgid "Use module-prefixed route names, such as `blog/index`, to avoid collisions." +msgstr "Use nomes de rota com o prefixo do módulo, como `blog/index`, para evitar colisões." + +#. type: Plain text +#: ../src/guide/structure/module.md +msgid "If the application has many modules, you can give each module its own route config file. Change the `routes` group in `config/configuration.php`:" +msgstr "Se a aplicação tem muitos módulos, você pode dar a cada módulo o seu próprio arquivo de configuração de rotas. Altere o grupo `routes` em `config/configuration.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/module.md +#, no-wrap +msgid "" +"'routes' => [\n" +" 'common/routes.php',\n" +" 'common/routes/*.php',\n" +"],\n" +msgstr "" +"'routes' => [\n" +" 'common/routes.php',\n" +" 'common/routes/*.php',\n" +"],\n" + +#. type: Plain text +#: ../src/guide/structure/module.md +msgid "Then create `config/common/routes/blog.php`:" +msgstr "Depois crie `config/common/routes/blog.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/structure/module.md +#, no-wrap +msgid "" +"routes(\n" +" Route::get('')\n" +" ->action(IndexAction::class)\n" +" ->name('blog/index'),\n" +" ),\n" +"];\n" +msgstr "" +"routes(\n" +" Route::get('')\n" +" ->action(IndexAction::class)\n" +" ->name('blog/index'),\n" +" ),\n" +"];\n" + +#. type: Plain text +#: ../src/guide/structure/module.md +msgid "After changing `config/configuration.php` or adding files matched by a config wildcard, rebuild the merge plan:" +msgstr "Depois de alterar `config/configuration.php` ou de adicionar arquivos que casam com um curinga da configuração, reconstrua o merge plan:" + +#. type: Title ## +#: ../src/guide/structure/module.md +#, no-wrap +msgid "Module configuration" +msgstr "Configuração de módulos" + +#. type: Plain text +#: ../src/guide/structure/module.md +msgid "Application modules use the same configuration groups as packages. The difference is where the configuration lives:" +msgstr "Os módulos da aplicação usam os mesmos grupos de configuração que os pacotes. A diferença é onde a configuração fica:" + +#. type: Bullet: '- ' +#: ../src/guide/structure/module.md +msgid "application module configuration lives in the root application under `config/`;" +msgstr "a configuração de um módulo da aplicação fica na aplicação raiz, em `config/`;" + +#. type: Bullet: '- ' +#: ../src/guide/structure/module.md +msgid "package module configuration lives in the package and is declared in `extra.config-plugin`." +msgstr "a configuração de um módulo em pacote fica no pacote e é declarada em `extra.config-plugin`." + +#. type: Plain text +#: ../src/guide/structure/module.md +msgid "Common locations for application module configuration are:" +msgstr "Locais comuns para a configuração de módulos da aplicação são:" + +#. type: Fenced code block +#: ../src/guide/structure/module.md +#, no-wrap +msgid "" +"config/\n" +" common/\n" +" di/\n" +" blog.php\n" +" routes/\n" +" blog.php\n" +" params.php\n" +" console/\n" +" params.php\n" +" web/\n" +" params.php\n" +msgstr "" +"config/\n" +" common/\n" +" di/\n" +" blog.php\n" +" routes/\n" +" blog.php\n" +" params.php\n" +" console/\n" +" params.php\n" +" web/\n" +" params.php\n" + +#. type: Plain text +#: ../src/guide/structure/module.md +msgid "Put shared service definitions in `common/di/`. Put web-only definitions in `web/di/`. Put console-only parameters or command registrations in `console/params.php`." +msgstr "Coloque as definições de serviços compartilhadas em `common/di/`. Coloque as definições exclusivas da web em `web/di/`. Coloque os parâmetros ou registros de comandos exclusivos do console em `console/params.php`." + +#. type: Plain text +#: ../src/guide/structure/module.md +msgid "When a module grows enough to become reusable, move its PHP classes to a Composer package, move its configuration files to the package `config/` directory, and declare them in the package `composer.json`:" +msgstr "Quando um módulo cresce a ponto de se tornar reutilizável, mova as classes PHP para um pacote Composer, mova os arquivos de configuração para a pasta `config/` do pacote e declare-os no `composer.json` do pacote:" + +#. type: Fenced code block (json) +#: ../src/guide/structure/module.md +#, no-wrap +msgid "" +"{\n" +" \"extra\": {\n" +" \"config-plugin\": {\n" +" \"di\": \"config/di.php\",\n" +" \"routes\": \"config/routes.php\"\n" +" }\n" +" }\n" +"}\n" +msgstr "" +"{\n" +" \"extra\": {\n" +" \"config-plugin\": {\n" +" \"di\": \"config/di.php\",\n" +" \"routes\": \"config/routes.php\"\n" +" }\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/structure/module.md +msgid "The application can then override package defaults in its own config files." +msgstr "A aplicação pode, então, sobrescrever os padrões do pacote nos próprios arquivos de configuração." + +#. type: Title ## +#: ../src/guide/structure/module.md +#, no-wrap +msgid "Cross-module communication" +msgstr "Comunicação entre módulos" + +#. type: Plain text +#: ../src/guide/structure/module.md +msgid "Choose the smallest coupling that supports the behavior:" +msgstr "Escolha o menor acoplamento que atenda ao comportamento:" + +#. type: Bullet: '- ' +#: ../src/guide/structure/module.md +msgid "Use constructor injection with an interface for a direct synchronous call." +msgstr "Use injeção pelo construtor com uma interface para uma chamada síncrona direta." + +#. type: Bullet: '- ' +#: ../src/guide/structure/module.md +msgid "Use an event when the producer should not know who reacts to something that happened." +msgstr "Use um evento quando quem produz não deve saber quem reage a algo que aconteceu." + +#. type: Bullet: '- ' +#: ../src/guide/structure/module.md +msgid "Use an application service or use case class when orchestration belongs outside both modules." +msgstr "Use um serviço de aplicação ou uma classe de caso de uso quando a orquestração pertence a um lugar fora dos dois módulos." + +#. type: Bullet: '- ' +#: ../src/guide/structure/module.md +msgid "Use a package when the module must be reused by more than one application." +msgstr "Use um pacote quando o módulo precisa ser reutilizado por mais de uma aplicação." + +#. type: Plain text +#: ../src/guide/structure/module.md +msgid "Avoid service locator calls and global state inside module classes. Let actions, commands, and services receive their dependencies through constructors so module boundaries stay visible in code and testable in isolation." +msgstr "Evite chamadas a service locator e estado global dentro das classes do módulo. Deixe que actions, comandos e serviços recebam as suas dependências pelos construtores, para que as fronteiras dos módulos fiquem visíveis no código e possam ser testadas isoladamente." diff --git a/_translations/po/pt-BR/guide_structure_overview.md.po b/_translations/po/pt-BR/guide_structure_overview.md.po new file mode 100644 index 00000000..3f996de9 --- /dev/null +++ b/_translations/po/pt-BR/guide_structure_overview.md.po @@ -0,0 +1,175 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 08:02+0000\n" +"PO-Revision-Date: 2025-12-24 08:02+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/en/guide/structure/overview.md ../src/en/guide/views/script-style-meta.md +#, no-wrap +msgid "Overview" +msgstr "Visão geral" + +#. type: Plain text +#: ../src/en/guide/structure/overview.md +msgid "Yii applications code is typically grouped into modules by context. In each module there could be grouping by type." +msgstr "O código de aplicações Yii normalmente é agrupado em módulos por contexto. Dentro de cada módulo, pode haver um agrupamento por tipo." + +#. type: Plain text +#: ../src/en/guide/structure/overview.md +msgid "For example, if the application is an online store, the context could be:" +msgstr "Por exemplo, se a aplicação for uma loja online, os contextos poderiam ser:" + +#. type: Bullet: '- ' +#: ../src/en/guide/structure/overview.md +msgid "Customer" +msgstr "Cliente" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Profile" +msgstr "Perfil" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Products list" +msgstr "Lista de produtos" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Checkout" +msgstr "Checkout" + +#. type: Bullet: '- ' +#: ../src/en/guide/structure/overview.md +msgid "Logistics" +msgstr "Logística" + +#. type: Bullet: '- ' +#: ../src/en/guide/structure/overview.md +msgid "Delivery" +msgstr "Entrega" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Addresses" +msgstr "Endereços" + +#. type: Bullet: '- ' +#: ../src/en/guide/structure/overview.md +msgid "Helpdesk" +msgstr "Helpdesk" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Support" +msgstr "Suporte" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Claims" +msgstr "Reclamações" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Returns" +msgstr "Devoluções" + +#. type: Bullet: '- ' +#: ../src/en/guide/structure/overview.md +msgid "Accounting" +msgstr "Contabilidade" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Transactions" +msgstr "Transações" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Taxes" +msgstr "Impostos" + +#. type: Plain text +#: ../src/en/guide/structure/overview.md +msgid "For a \"Customer\" context, residing under `App\\Customer` namespace, structure would be:" +msgstr "Para um contexto \"Customer\", localizado no namespace `App\\Customer`, a estrutura seria:" + +#. type: Fenced code block +#: ../src/en/guide/structure/overview.md +#, no-wrap +msgid "" +"App/\n" +" Customer/ <-- module namespace\n" +" Entity/\n" +" Customer.php <-- entity shared by \"Profile\" and \"Checkout\"\n" +" Profile/\n" +" Widget/\n" +" Gravatar.php\n" +" ProfileRepository.php <-- repository is usually specific to context\n" +" ProfileController.php <-- \"Customer\\Profile\" entry point\n" +" ProductList/ <-- module namespace \n" +" Entity/ <-- entities specific to \"Customer\\ProductList\"\n" +" Category.php\n" +" Product.php\n" +" ProductsListController.php <-- \"Customer\\ProductList\" entry point\n" +" Checkout/ <-- module namespace\n" +" CheckoutController.php\n" +msgstr "" +"App/\n" +" Customer/ <-- namespace do módulo\n" +" Entity/\n" +" Customer.php <-- entidade compartilhada por \"Profile\" e \"Checkout\"\n" +" Profile/\n" +" Widget/\n" +" Gravatar.php\n" +" ProfileRepository.php <-- o repositório geralmente é específico do contexto\n" +" ProfileController.php <-- ponto de entrada de \"Customer\\Profile\"\n" +" ProductList/ <-- namespace do módulo \n" +" Entity/ <-- entidades específicas de \"Customer\\ProductList\"\n" +" Category.php\n" +" Product.php\n" +" ProductsListController.php <-- ponto de entrada de \"Customer\\ProductList\"\n" +" Checkout/ <-- namespace do módulo\n" +" CheckoutController.php\n" + +#. type: Plain text +#: ../src/en/guide/structure/overview.md +msgid "A context may include sub-contexts. If a class is shared by multiple contexts, it's moved to the ancestor of both contexts." +msgstr "Um contexto pode incluir subcontextos. Se uma classe é compartilhada por vários contextos, ela é movida para o ancestral comum desses contextos." + +#. type: Plain text +#: ../src/en/guide/structure/overview.md +msgid "A context may have [an entry point known as \"action\" or \"controller\"](action.md). Its job is to take [a request instance](../runtime/request.md), pass it to [domain layer](../../cookbook/organizing-code/domain.md) in a suitable format, and create [a response](../runtime/response.md) based on domain layer return." +msgstr "Um contexto pode ter [um ponto de entrada conhecido como \"action\" ou \"controller\"](action.md). A função dele é receber [uma instância de requisição](../runtime/request.md), passá-la para a [camada de domínio](../../cookbook/organizing-code/domain.md) em um formato adequado e criar [uma resposta](../runtime/response.md) com base no retorno da camada de domínio." + +#. type: Plain text +#: ../src/en/guide/structure/overview.md +msgid "Besides, Yii applications also have the following:" +msgstr "Além disso, aplicações Yii também têm o seguinte:" + +#. type: Bullet: '* ' +#: ../src/en/guide/structure/overview.md +msgid "[entry scripts](entry-script.md): they're PHP scripts that are directly accessible by end users. They're responsible for starting a request handling cycle. Typically, a single entry script is handling the whole application." +msgstr "[scripts de entrada](entry-script.md): são scripts PHP acessíveis diretamente pelos usuários finais. Eles são responsáveis por iniciar um ciclo de tratamento de requisição. Normalmente, um único script de entrada atende a aplicação inteira." + +#. type: Bullet: '* ' +#: ../src/en/guide/structure/overview.md +msgid "[services](../../cookbook/organizing-code/service.md): they're typically stateless objects registered within dependency container and provide various action methods." +msgstr "[serviços](../../cookbook/organizing-code/service.md): normalmente são objetos sem estado registrados no container de dependências que fornecem diversos métodos de ação." + +#. type: Bullet: '* ' +#: ../src/en/guide/structure/overview.md +msgid "[middleware](middleware.md): they represent a code that needs to be invoked before and after the actual handling of each request by action handlers." +msgstr "[middleware](middleware.md): representam código que precisa ser executado antes e depois do tratamento efetivo de cada requisição pelos handlers de action." diff --git a/_translations/po/pt-BR/guide_structure_package.md.po b/_translations/po/pt-BR/guide_structure_package.md.po new file mode 100644 index 00000000..da36f8ee --- /dev/null +++ b/_translations/po/pt-BR/guide_structure_package.md.po @@ -0,0 +1,247 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-06-05 20:33+0000\n" +"PO-Revision-Date: 2026-06-05 20:33+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Fenced code block (sh) +#: ../src/cookbook/using-yii-in-third-party-apps.md ../src/guide/structure/designing-packages.md ../src/guide/structure/module.md ../src/guide/structure/package.md ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "composer yii-config-rebuild\n" +msgstr "composer yii-config-rebuild\n" + +#. type: Title # +#: ../src/guide/structure/package.md +#, no-wrap +msgid "Using packages" +msgstr "Usando pacotes" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "Reusable code is distributed as [Composer packages](https://getcomposer.org/doc/05-repositories.md#package). A package can be an infrastructure library, a Yii integration, a reusable feature, or a module representing an application context." +msgstr "Código reutilizável é distribuído como [pacotes Composer](https://getcomposer.org/doc/05-repositories.md#package). Um pacote pode ser uma biblioteca de infraestrutura, uma integração com o Yii, um recurso reutilizável ou um módulo que representa um contexto da aplicação." + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "This page explains how to use packages in an application. To create a Yii-aware package, see [Designing packages for Yii applications](designing-packages.md)." +msgstr "Esta página explica como usar pacotes em uma aplicação. Para criar um pacote compatível com o Yii, veja [Projetando pacotes para aplicações Yii](designing-packages.md)." + +#. type: Title ## +#: ../src/guide/structure/package.md +#, no-wrap +msgid "Installing packages" +msgstr "Instalando pacotes" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "By default, Composer installs packages registered on [Packagist](https://packagist.org/), the main repository for open source PHP packages." +msgstr "Por padrão, o Composer instala pacotes registrados no [Packagist](https://packagist.org/), o principal repositório de pacotes PHP de código aberto." + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "Install a package with:" +msgstr "Instale um pacote com:" + +#. type: Fenced code block (sh) +#: ../src/guide/structure/package.md +#, no-wrap +msgid "composer require vendor-name/package-name\n" +msgstr "composer require vendor-name/package-name\n" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "Composer updates two files:" +msgstr "O Composer atualiza dois arquivos:" + +#. type: Bullet: '- ' +#: ../src/guide/structure/package.md +msgid "`composer.json` stores the package name and version constraint." +msgstr "`composer.json` armazena o nome do pacote e a restrição de versão." + +#. type: Bullet: '- ' +#: ../src/guide/structure/package.md +msgid "`composer.lock` stores the exact versions installed." +msgstr "`composer.lock` armazena as versões exatas instaladas." + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "Commit both files so other environments install the same dependency versions." +msgstr "Faça commit dos dois arquivos para que outros ambientes instalem as mesmas versões das dependências." + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "Installed packages are stored in the application `vendor/` directory." +msgstr "Os pacotes instalados ficam na pasta `vendor/` da aplicação." + +#. type: Plain text +#: ../src/guide/structure/package.md +#, no-wrap +msgid "" +"> [!WARNING]\n" +"> Never edit files in `vendor/` directly. Change application configuration, extend classes, decorate services, or\n" +"> contribute fixes to the package instead.\n" +msgstr "" +"> [!WARNING]\n" +"> Nunca edite arquivos em `vendor/` diretamente. Em vez disso, altere a configuração da aplicação, estenda classes, decore serviços ou\n" +"> contribua com correções para o pacote.\n" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "Package classes are available through Composer autoloading after installation. See [Autoloading](../concept/autoloading.md) for details." +msgstr "As classes dos pacotes ficam disponíveis pelo autoload do Composer após a instalação. Veja [Autoload](../concept/autoloading.md) para mais detalhes." + +#. type: Title ## +#: ../src/guide/structure/package.md +#, no-wrap +msgid "Updating packages" +msgstr "Atualizando pacotes" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "Update a package within the version constraint recorded in `composer.json`:" +msgstr "Atualize um pacote dentro da restrição de versão registrada no `composer.json`:" + +#. type: Fenced code block (sh) +#: ../src/guide/structure/package.md +#, no-wrap +msgid "composer update vendor-name/package-name\n" +msgstr "composer update vendor-name/package-name\n" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "Change the accepted version constraint with `composer require`:" +msgstr "Altere a restrição de versão aceita com `composer require`:" + +#. type: Fenced code block (sh) +#: ../src/guide/structure/package.md +#, no-wrap +msgid "composer require vendor-name/package-name:^2.0\n" +msgstr "composer require vendor-name/package-name:^2.0\n" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "After updating a Yii-aware package, Composer rebuilds Yii's configuration merge plan. If you changed configuration group mappings manually, rebuild it explicitly:" +msgstr "Depois de atualizar um pacote compatível com o Yii, o Composer reconstrói o merge plan de configuração do Yii. Se você alterou manualmente os mapeamentos de grupos de configuração, reconstrua-o explicitamente:" + +#. type: Title ## +#: ../src/guide/structure/package.md +#, no-wrap +msgid "Removing packages" +msgstr "Removendo pacotes" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "Remove a package with:" +msgstr "Remova um pacote com:" + +#. type: Fenced code block (sh) +#: ../src/guide/structure/package.md +#, no-wrap +msgid "composer remove vendor-name/package-name\n" +msgstr "composer remove vendor-name/package-name\n" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "Then remove application code and configuration that referenced classes, services, routes, commands, assets, migrations, or translations from that package." +msgstr "Em seguida, remova o código e a configuração da aplicação que referenciavam classes, serviços, rotas, comandos, assets, migrations ou traduções desse pacote." + +#. type: Title ## +#: ../src/guide/structure/package.md +#, no-wrap +msgid "Private packages" +msgstr "Pacotes privados" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "For private code, configure Composer repositories in the application `composer.json`. Common options are:" +msgstr "Para código privado, configure repositórios do Composer no `composer.json` da aplicação. As opções mais comuns são:" + +#. type: Bullet: '- ' +#: ../src/guide/structure/package.md +msgid "`vcs` for a Git repository." +msgstr "`vcs` para um repositório Git." + +#. type: Bullet: '- ' +#: ../src/guide/structure/package.md +msgid "`path` for a local package during development." +msgstr "`path` para um pacote local durante o desenvolvimento." + +#. type: Bullet: '- ' +#: ../src/guide/structure/package.md +msgid "`composer` for a private Composer repository." +msgstr "`composer` para um repositório Composer privado." + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "For example, to work with a package located next to the application:" +msgstr "Por exemplo, para trabalhar com um pacote localizado ao lado da aplicação:" + +#. type: Fenced code block (json) +#: ../src/guide/structure/package.md +#, no-wrap +msgid "" +"{\n" +" \"repositories\": [\n" +" {\n" +" \"type\": \"path\",\n" +" \"url\": \"../packages/blog\"\n" +" }\n" +" ]\n" +"}\n" +msgstr "" +"{\n" +" \"repositories\": [\n" +" {\n" +" \"type\": \"path\",\n" +" \"url\": \"../packages/blog\"\n" +" }\n" +" ]\n" +"}\n" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "Then install it normally:" +msgstr "Depois, instale-o normalmente:" + +#. type: Fenced code block (sh) +#: ../src/guide/structure/package.md +#, no-wrap +msgid "composer require vendor/blog\n" +msgstr "composer require vendor/blog\n" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "Read more in the [Composer repository documentation](https://getcomposer.org/doc/05-repositories.md)." +msgstr "Leia mais na [documentação de repositórios do Composer](https://getcomposer.org/doc/05-repositories.md)." + +#. type: Title ## +#: ../src/guide/structure/package.md +#, no-wrap +msgid "Package configuration" +msgstr "Configuração de pacotes" + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "Some Yii packages provide default configuration through [yiisoft/config](https://github.com/yiisoft/config). After installation, the package configuration becomes part of the vendor layer and the application can override it in the root package configuration." +msgstr "Alguns pacotes Yii fornecem configuração padrão por meio do [yiisoft/config](https://github.com/yiisoft/config). Após a instalação, a configuração do pacote passa a fazer parte da camada vendor, e a aplicação pode sobrescrevê-la na configuração do pacote raiz." + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "Prefer partial overrides in application config files over copying whole package config files. For example, override only the parameter or service definition you need." +msgstr "Prefira sobrescritas parciais nos arquivos de configuração da aplicação em vez de copiar arquivos de configuração inteiros do pacote. Por exemplo, sobrescreva apenas o parâmetro ou a definição de serviço de que você precisa." + +#. type: Plain text +#: ../src/guide/structure/package.md +msgid "For more details, see [Configuration](../concept/configuration.md) and [Designing packages for Yii applications](designing-packages.md)." +msgstr "Para mais detalhes, veja [Configuração](../concept/configuration.md) e [Projetando pacotes para aplicações Yii](designing-packages.md)." diff --git a/_translations/po/pt-BR/guide_testing_end-to-end.md.po b/_translations/po/pt-BR/guide_testing_end-to-end.md.po new file mode 100644 index 00000000..513fa885 --- /dev/null +++ b/_translations/po/pt-BR/guide_testing_end-to-end.md.po @@ -0,0 +1,297 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-05-08 08:49+0000\n" +"PO-Revision-Date: 2026-05-08 08:49+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md ../src/guide/testing/end-to-end.md ../src/guide/testing/environment-setup.md ../src/guide/testing/quality-tools.md +msgid "With Docker:" +msgstr "Com Docker:" + +#. type: Title # +#: ../src/guide/testing/end-to-end.md +#, no-wrap +msgid "End-to-end tests" +msgstr "Testes end-to-end" + +#. type: Plain text +#: ../src/guide/testing/end-to-end.md +msgid "The Yii application template uses the `Web` Codeception suite for tests that go through an HTTP server. These tests live in `tests/Web` and use `App\\Tests\\Support\\WebTester`." +msgstr "O template de aplicação Yii usa a suíte `Web` do Codeception para testes que passam por um servidor HTTP. Esses testes ficam em `tests/Web` e usam `App\\Tests\\Support\\WebTester`." + +#. type: Plain text +#: ../src/guide/testing/end-to-end.md +msgid "Use web tests for user-visible HTTP behavior: pages, links, forms, redirects, cookies, and error pages." +msgstr "Use testes web para o comportamento HTTP visível ao usuário: páginas, links, formulários, redirecionamentos, cookies e páginas de erro." + +#. type: Title ## +#: ../src/guide/testing/end-to-end.md +#, no-wrap +msgid "Web suite" +msgstr "Suíte Web" + +#. type: Plain text +#: ../src/guide/testing/end-to-end.md +msgid "The template configures `tests/Web.suite.yml` like this:" +msgstr "O template configura `tests/Web.suite.yml` assim:" + +#. type: Fenced code block (yaml) +#: ../src/guide/testing/end-to-end.md ../src/guide/testing/environment-setup.md +#, no-wrap +msgid "" +"actor: WebTester\n" +"extensions:\n" +" enabled:\n" +" - Codeception\\Extension\\RunProcess:\n" +" 0: composer serve\n" +" sleep: 3\n" +"modules:\n" +" enabled:\n" +" - PhpBrowser:\n" +" url: http://127.0.0.1:8080\n" +msgstr "" +"actor: WebTester\n" +"extensions:\n" +" enabled:\n" +" - Codeception\\Extension\\RunProcess:\n" +" 0: composer serve\n" +" sleep: 3\n" +"modules:\n" +" enabled:\n" +" - PhpBrowser:\n" +" url: http://127.0.0.1:8080\n" + +#. type: Plain text +#: ../src/guide/testing/end-to-end.md +msgid "`RunProcess` starts the application with the Composer `serve` script. `PhpBrowser` sends HTTP requests to the server." +msgstr "`RunProcess` inicia a aplicação com o script `serve` do Composer. `PhpBrowser` envia requisições HTTP ao servidor." + +#. type: Title ## +#: ../src/guide/testing/end-to-end.md ../src/guide/testing/functional.md +#, no-wrap +msgid "Test a page" +msgstr "Testar uma página" + +#. type: Plain text +#: ../src/guide/testing/end-to-end.md +msgid "The template includes `tests/Web/HomePageCest.php`:" +msgstr "O template inclui `tests/Web/HomePageCest.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/testing/end-to-end.md +#, no-wrap +msgid "" +"wantTo('home page works.');\n" +" $I->amOnPage('/');\n" +" $I->expectTo('see page home.');\n" +" $I->see('Hello!');\n" +" }\n" +"}\n" +msgstr "" +"wantTo('home page works.');\n" +" $I->amOnPage('/');\n" +" $I->expectTo('see page home.');\n" +" $I->see('Hello!');\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/testing/end-to-end.md +msgid "Run the web suite locally:" +msgstr "Execute a suíte web localmente:" + +#. type: Fenced code block (shell) +#: ../src/guide/testing/end-to-end.md +#, no-wrap +msgid "APP_ENV=test vendor/bin/codecept run Web\n" +msgstr "APP_ENV=test vendor/bin/codecept run Web\n" + +#. type: Plain text +#: ../src/guide/testing/end-to-end.md ../src/guide/testing/unit.md +msgid "Run only this test:" +msgstr "Execute apenas este teste:" + +#. type: Fenced code block (shell) +#: ../src/guide/testing/end-to-end.md +#, no-wrap +msgid "APP_ENV=test vendor/bin/codecept run Web HomePageCest\n" +msgstr "APP_ENV=test vendor/bin/codecept run Web HomePageCest\n" + +#. type: Fenced code block (shell) +#: ../src/guide/testing/end-to-end.md +#, no-wrap +msgid "make test Web\n" +msgstr "make test Web\n" + +#. type: Title ## +#: ../src/guide/testing/end-to-end.md +#, no-wrap +msgid "Test links and error pages" +msgstr "Testar links e páginas de erro" + +#. type: Plain text +#: ../src/guide/testing/end-to-end.md +msgid "Use the same actor methods for navigation and response assertions:" +msgstr "Use os mesmos métodos do actor para navegação e asserções sobre a resposta:" + +#. type: Fenced code block (php) +#: ../src/guide/testing/end-to-end.md +#, no-wrap +msgid "" +"wantTo('see 404 page.');\n" +" $I->amOnPage('/non-existent-page');\n" +" $I->canSeeResponseCodeIs(404);\n" +" $I->see('404');\n" +" $I->see('The page /non-existent-page not found.');\n" +" }\n" +"}\n" +msgstr "" +"wantTo('see 404 page.');\n" +" $I->amOnPage('/non-existent-page');\n" +" $I->canSeeResponseCodeIs(404);\n" +" $I->see('404');\n" +" $I->see('The page /non-existent-page not found.');\n" +" }\n" +"}\n" + +#. type: Title ## +#: ../src/guide/testing/end-to-end.md +#, no-wrap +msgid "Smoke test with curl" +msgstr "Smoke test com curl" + +#. type: Plain text +#: ../src/guide/testing/end-to-end.md +msgid "For a deployment smoke test, start the application and check one URL:" +msgstr "Para um smoke test de deploy, inicie a aplicação e verifique uma URL:" + +#. type: Fenced code block (shell) +#: ../src/guide/testing/end-to-end.md +#, no-wrap +msgid "APP_ENV=test ./yii serve --port=8080\n" +msgstr "APP_ENV=test ./yii serve --port=8080\n" + +#. type: Plain text +#: ../src/guide/testing/end-to-end.md +msgid "In another terminal:" +msgstr "Em outro terminal:" + +#. type: Fenced code block (shell) +#: ../src/guide/testing/end-to-end.md +#, no-wrap +msgid "" +"curl -fsS http://127.0.0.1:8080/ > /tmp/home.html\n" +"grep -q \"Hello!\" /tmp/home.html\n" +msgstr "" +"curl -fsS http://127.0.0.1:8080/ > /tmp/home.html\n" +"grep -q \"Hello!\" /tmp/home.html\n" + +#. type: Title ## +#: ../src/guide/testing/end-to-end.md ../src/guide/testing/functional.md +#, no-wrap +msgid "Reset state" +msgstr "Redefinir o estado" + +#. type: Plain text +#: ../src/guide/testing/end-to-end.md +msgid "Web tests use real infrastructure, so reset state before each scenario:" +msgstr "Testes web usam infraestrutura real, então redefina o estado antes de cada cenário:" + +#. type: Bullet: '- ' +#: ../src/guide/testing/end-to-end.md +msgid "Load only the records required by the scenario." +msgstr "Carregue apenas os registros exigidos pelo cenário." + +#. type: Bullet: '- ' +#: ../src/guide/testing/end-to-end.md +msgid "Clear session and cookie storage." +msgstr "Limpe o armazenamento de sessão e de cookies." + +#. type: Bullet: '- ' +#: ../src/guide/testing/end-to-end.md +msgid "Clear generated files and outgoing messages." +msgstr "Limpe arquivos gerados e mensagens de saída." + +#. type: Bullet: '- ' +#: ../src/guide/testing/end-to-end.md +msgid "Stop background workers, or make their effects deterministic." +msgstr "Pare os workers em segundo plano ou torne seus efeitos determinísticos." + +#. type: Plain text +#: ../src/guide/testing/end-to-end.md +msgid "If the scenario changes a database, reset it in the Cest `_before()` hook or in a project-specific helper:" +msgstr "Se o cenário altera um banco de dados, redefina-o no hook `_before()` do Cest ou em um helper específico do projeto:" + +#. type: Fenced code block (php) +#: ../src/guide/testing/end-to-end.md +#, no-wrap +msgid "" +"public function _before(WebTester $I): void\n" +"{\n" +" // Reset database tables, files, queues, and outgoing messages.\n" +"}\n" +msgstr "" +"public function _before(WebTester $I): void\n" +"{\n" +" // Redefina tabelas do banco de dados, arquivos, filas e mensagens de saída.\n" +"}\n" diff --git a/_translations/po/pt-BR/guide_testing_environment-setup.md.po b/_translations/po/pt-BR/guide_testing_environment-setup.md.po new file mode 100644 index 00000000..3a2739fa --- /dev/null +++ b/_translations/po/pt-BR/guide_testing_environment-setup.md.po @@ -0,0 +1,435 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-05-08 08:49+0000\n" +"PO-Revision-Date: 2026-05-08 08:49+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md ../src/guide/testing/end-to-end.md ../src/guide/testing/environment-setup.md ../src/guide/testing/quality-tools.md +msgid "With Docker:" +msgstr "Com Docker:" + +#. type: Fenced code block (yaml) +#: ../src/guide/testing/end-to-end.md ../src/guide/testing/environment-setup.md +#, no-wrap +msgid "" +"actor: WebTester\n" +"extensions:\n" +" enabled:\n" +" - Codeception\\Extension\\RunProcess:\n" +" 0: composer serve\n" +" sleep: 3\n" +"modules:\n" +" enabled:\n" +" - PhpBrowser:\n" +" url: http://127.0.0.1:8080\n" +msgstr "" +"actor: WebTester\n" +"extensions:\n" +" enabled:\n" +" - Codeception\\Extension\\RunProcess:\n" +" 0: composer serve\n" +" sleep: 3\n" +"modules:\n" +" enabled:\n" +" - PhpBrowser:\n" +" url: http://127.0.0.1:8080\n" + +#. type: Title # +#: ../src/guide/testing/environment-setup.md +#, no-wrap +msgid "Testing environment setup" +msgstr "Configuração do ambiente de testes" + +#. type: Plain text +#: ../src/guide/testing/environment-setup.md +msgid "The Yii application template has the test environment configured. Use this page when creating a new project from the template, restoring removed test files, or adding a new suite." +msgstr "O template de aplicação Yii já vem com o ambiente de testes configurado. Use esta página ao criar um novo projeto a partir do template, restaurar arquivos de teste removidos ou adicionar uma nova suíte." + +#. type: Title ## +#: ../src/guide/testing/environment-setup.md +#, no-wrap +msgid "Composer configuration" +msgstr "Configuração do Composer" + +#. type: Plain text +#: ../src/guide/testing/environment-setup.md +msgid "The template requires Codeception, PHPUnit, and the modules used by the suites:" +msgstr "O template exige o Codeception, o PHPUnit e os módulos usados pelas suítes:" + +#. type: Fenced code block (json) +#: ../src/guide/testing/environment-setup.md +#, no-wrap +msgid "" +"{\n" +" \"require-dev\": {\n" +" \"codeception/codeception\": \"^5.3\",\n" +" \"codeception/module-asserts\": \"^3.2\",\n" +" \"codeception/module-cli\": \"^2.0\",\n" +" \"codeception/module-phpbrowser\": \"^3.0\",\n" +" \"phpunit/phpunit\": \"^11.5\"\n" +" },\n" +" \"autoload-dev\": {\n" +" \"psr-4\": {\n" +" \"App\\\\Tests\\\\\": \"tests\"\n" +" }\n" +" },\n" +" \"scripts\": {\n" +" \"test\": \"codecept run\"\n" +" }\n" +"}\n" +msgstr "" +"{\n" +" \"require-dev\": {\n" +" \"codeception/codeception\": \"^5.3\",\n" +" \"codeception/module-asserts\": \"^3.2\",\n" +" \"codeception/module-cli\": \"^2.0\",\n" +" \"codeception/module-phpbrowser\": \"^3.0\",\n" +" \"phpunit/phpunit\": \"^11.5\"\n" +" },\n" +" \"autoload-dev\": {\n" +" \"psr-4\": {\n" +" \"App\\\\Tests\\\\\": \"tests\"\n" +" }\n" +" },\n" +" \"scripts\": {\n" +" \"test\": \"codecept run\"\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/testing/environment-setup.md +msgid "If these entries are already in your project, keep the installed versions from `composer.lock`." +msgstr "Se essas entradas já estiverem no seu projeto, mantenha as versões instaladas do `composer.lock`." + +#. type: Title ## +#: ../src/guide/testing/environment-setup.md +#, no-wrap +msgid "Main Codeception file" +msgstr "Arquivo principal do Codeception" + +#. type: Plain text +#: ../src/guide/testing/environment-setup.md +msgid "The root `codeception.yml` defines the test namespace, paths, bootstrap file, and coverage source:" +msgstr "O `codeception.yml` na raiz define o namespace dos testes, os caminhos, o arquivo de bootstrap e a origem da cobertura:" + +#. type: Fenced code block (yaml) +#: ../src/guide/testing/environment-setup.md +#, no-wrap +msgid "" +"namespace: App\\Tests\n" +"support_namespace: Support\n" +"bootstrap: bootstrap.php\n" +"\n" +"settings:\n" +" shuffle: true\n" +" colors: true\n" +"\n" +"paths:\n" +" tests: tests\n" +" output: tests/_output\n" +" data: tests/Support/Data\n" +" support: tests/Support\n" +"\n" +"coverage:\n" +" enabled: true\n" +" show_uncovered: true\n" +" show_only_summary: true\n" +" include:\n" +" - src/*\n" +" - public/index.php\n" +" - yii\n" +"\n" +"extensions:\n" +" enabled:\n" +" - Codeception\\Extension\\RunFailed\n" +msgstr "" +"namespace: App\\Tests\n" +"support_namespace: Support\n" +"bootstrap: bootstrap.php\n" +"\n" +"settings:\n" +" shuffle: true\n" +" colors: true\n" +"\n" +"paths:\n" +" tests: tests\n" +" output: tests/_output\n" +" data: tests/Support/Data\n" +" support: tests/Support\n" +"\n" +"coverage:\n" +" enabled: true\n" +" show_uncovered: true\n" +" show_only_summary: true\n" +" include:\n" +" - src/*\n" +" - public/index.php\n" +" - yii\n" +"\n" +"extensions:\n" +" enabled:\n" +" - Codeception\\Extension\\RunFailed\n" + +#. type: Plain text +#: ../src/guide/testing/environment-setup.md +msgid "`tests/bootstrap.php` prepares the application environment for every suite:" +msgstr "`tests/bootstrap.php` prepara o ambiente da aplicação para todas as suítes:" + +#. type: Fenced code block (php) +#: ../src/guide/testing/environment-setup.md +#, no-wrap +msgid "" +"\n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/guide/testing/end-to-end.md ../src/guide/testing/functional.md +#, no-wrap +msgid "Test a page" +msgstr "Testar uma página" + +#. type: Title ## +#: ../src/guide/testing/end-to-end.md ../src/guide/testing/functional.md +#, no-wrap +msgid "Reset state" +msgstr "Redefinir o estado" + +#. type: Title # +#: ../src/guide/testing/functional.md +#, no-wrap +msgid "Functional tests" +msgstr "Testes funcionais" + +#. type: Plain text +#: ../src/guide/testing/functional.md +msgid "Functional tests run application code in the same PHP process. In the Yii application template they live in `tests/Functional` and use `App\\Tests\\Support\\FunctionalTester`." +msgstr "Testes funcionais executam o código da aplicação no mesmo processo PHP. No template de aplicação Yii eles ficam em `tests/Functional` e usam `App\\Tests\\Support\\FunctionalTester`." + +#. type: Plain text +#: ../src/guide/testing/functional.md +msgid "Use them for routing, middleware, action handlers, views, container configuration, headers, cookies, and sessions." +msgstr "Use-os para roteamento, middlewares, action handlers, views, configuração do container, headers, cookies e sessões." + +#. type: Title ## +#: ../src/guide/testing/functional.md +#, no-wrap +msgid "Functional tester" +msgstr "Functional tester" + +#. type: Plain text +#: ../src/guide/testing/functional.md +msgid "The template already has a helper method for sending PSR-7 requests:" +msgstr "O template já tem um método helper para enviar requisições PSR-7:" + +#. type: Fenced code block (php) +#: ../src/guide/testing/functional.md +#, no-wrap +msgid "" +"runAndGetResponse($request);\n" +" $body = $response->getBody();\n" +" if ($body->isSeekable()) {\n" +" $body->rewind();\n" +" }\n" +"\n" +" return $response;\n" +" }\n" +"}\n" +msgstr "" +"runAndGetResponse($request);\n" +" $body = $response->getBody();\n" +" if ($body->isSeekable()) {\n" +" $body->rewind();\n" +" }\n" +"\n" +" return $response;\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/testing/functional.md +msgid "The template includes `tests/Functional/HomePageCest.php`:" +msgstr "O template inclui `tests/Functional/HomePageCest.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/testing/functional.md +#, no-wrap +msgid "" +"sendRequest(\n" +" new ServerRequest(uri: '/'),\n" +" );\n" +"\n" +" assertSame(200, $response->getStatusCode());\n" +" assertStringContainsString(\n" +" 'Don\\'t forget to check the guide',\n" +" $response->getBody()->getContents(),\n" +" );\n" +" }\n" +"}\n" +msgstr "" +"sendRequest(\n" +" new ServerRequest(uri: '/'),\n" +" );\n" +"\n" +" assertSame(200, $response->getStatusCode());\n" +" assertStringContainsString(\n" +" 'Don\\'t forget to check the guide',\n" +" $response->getBody()->getContents(),\n" +" );\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/testing/functional.md ../src/guide/testing/unit.md +msgid "Run it:" +msgstr "Execute-o:" + +#. type: Fenced code block (shell) +#: ../src/guide/testing/functional.md +#, no-wrap +msgid "" +"APP_ENV=test vendor/bin/codecept run Functional\n" +"APP_ENV=test vendor/bin/codecept run Functional HomePageCest\n" +msgstr "" +"APP_ENV=test vendor/bin/codecept run Functional\n" +"APP_ENV=test vendor/bin/codecept run Functional HomePageCest\n" + +#. type: Title ## +#: ../src/guide/testing/functional.md +#, no-wrap +msgid "Send request data" +msgstr "Enviar dados na requisição" + +#. type: Plain text +#: ../src/guide/testing/functional.md +msgid "Use PSR-7 methods to model the request:" +msgstr "Use os métodos PSR-7 para modelar a requisição:" + +#. type: Fenced code block (php) +#: ../src/guide/testing/functional.md +#, no-wrap +msgid "" +"$request = (new ServerRequest(uri: '/contact', method: 'POST'))\n" +" ->withHeader('Content-Type', 'application/x-www-form-urlencoded')\n" +" ->withParsedBody([\n" +" 'ContactForm' => [\n" +" 'name' => 'Sam',\n" +" 'email' => 'sam@example.test',\n" +" 'body' => 'Hello.',\n" +" ],\n" +" ]);\n" +"\n" +"$response = $tester->sendRequest($request);\n" +"\n" +"assertSame(302, $response->getStatusCode());\n" +"assertSame('/contact/sent', $response->getHeaderLine('Location'));\n" +msgstr "" +"$request = (new ServerRequest(uri: '/contact', method: 'POST'))\n" +" ->withHeader('Content-Type', 'application/x-www-form-urlencoded')\n" +" ->withParsedBody([\n" +" 'ContactForm' => [\n" +" 'name' => 'Sam',\n" +" 'email' => 'sam@example.test',\n" +" 'body' => 'Hello.',\n" +" ],\n" +" ]);\n" +"\n" +"$response = $tester->sendRequest($request);\n" +"\n" +"assertSame(302, $response->getStatusCode());\n" +"assertSame('/contact/sent', $response->getHeaderLine('Location'));\n" + +#. type: Plain text +#: ../src/guide/testing/functional.md +msgid "For JSON APIs, write the JSON body into a PSR-7 stream and set `Content-Type: application/json`." +msgstr "Para APIs JSON, escreva o corpo JSON em um stream PSR-7 e defina `Content-Type: application/json`." + +#. type: Plain text +#: ../src/guide/testing/functional.md +msgid "Functional tests often touch runtime files, sessions, cache, and a database. Reset changed state in the Cest `_before()` hook or in a project helper:" +msgstr "Testes funcionais costumam mexer em arquivos de runtime, sessões, cache e banco de dados. Redefina o estado alterado no hook `_before()` do Cest ou em um helper do projeto:" + +#. type: Fenced code block (php) +#: ../src/guide/testing/functional.md +#, no-wrap +msgid "" +"public function _before(FunctionalTester $tester): void\n" +"{\n" +" // Reset database tables, cache pools, queues, and outgoing messages.\n" +"}\n" +msgstr "" +"public function _before(FunctionalTester $tester): void\n" +"{\n" +" // Redefina tabelas do banco de dados, pools de cache, filas e mensagens de saída.\n" +"}\n" + +#. type: Plain text +#: ../src/guide/testing/functional.md +msgid "Keep pure domain rules in unit tests. Put request and response behavior in functional tests." +msgstr "Mantenha as regras de domínio puras nos testes unitários. Coloque o comportamento de requisição e resposta nos testes funcionais." diff --git a/_translations/po/pt-BR/guide_testing_overview.md.po b/_translations/po/pt-BR/guide_testing_overview.md.po new file mode 100644 index 00000000..747eb305 --- /dev/null +++ b/_translations/po/pt-BR/guide_testing_overview.md.po @@ -0,0 +1,238 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-05-08 08:49+0000\n" +"PO-Revision-Date: 2026-05-08 08:49+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ### +#: ../src/cookbook/making-http-requests.md ../src/guide/index.md ../src/guide/testing/overview.md ../src/guide/tutorial/docker.md +#, no-wrap +msgid "Testing" +msgstr "Testes" + +#. type: Fenced code block (shell) +#: ../src/guide/testing/environment-setup.md ../src/guide/testing/overview.md +#, no-wrap +msgid "APP_ENV=test vendor/bin/codecept run\n" +msgstr "APP_ENV=test vendor/bin/codecept run\n" + +#. type: Fenced code block (shell) +#: ../src/guide/testing/environment-setup.md ../src/guide/testing/overview.md +#, no-wrap +msgid "vendor/bin/codecept build\n" +msgstr "vendor/bin/codecept build\n" + +#. type: Fenced code block (shell) +#: ../src/guide/testing/environment-setup.md ../src/guide/testing/overview.md +#, no-wrap +msgid "make codecept build\n" +msgstr "make codecept build\n" + +#. type: Plain text +#: ../src/guide/testing/overview.md +msgid "The Yii application template includes a ready test setup. It uses Codeception with PHPUnit assertions and has four suites:" +msgstr "O template de aplicação Yii inclui uma configuração de testes pronta. Ele usa o Codeception com asserções do PHPUnit e tem quatro suítes:" + +#. type: Bullet: '- ' +#: ../src/guide/testing/overview.md +msgid "`Unit` for isolated PHP classes." +msgstr "`Unit` para classes PHP isoladas." + +#. type: Bullet: '- ' +#: ../src/guide/testing/overview.md +msgid "`Functional` for application code called in the same PHP process." +msgstr "`Functional` para código da aplicação chamado no mesmo processo PHP." + +#. type: Bullet: '- ' +#: ../src/guide/testing/overview.md +msgid "`Web` for requests sent through an HTTP server." +msgstr "`Web` para requisições enviadas por um servidor HTTP." + +#. type: Bullet: '- ' +#: ../src/guide/testing/overview.md +msgid "`Console` for console commands." +msgstr "`Console` para comandos de console." + +#. type: Plain text +#: ../src/guide/testing/overview.md +msgid "The main files are:" +msgstr "Os arquivos principais são:" + +#. type: Bullet: '- ' +#: ../src/guide/testing/overview.md +msgid "`codeception.yml`." +msgstr "`codeception.yml`." + +#. type: Bullet: '- ' +#: ../src/guide/testing/overview.md +msgid "`tests/bootstrap.php`." +msgstr "`tests/bootstrap.php`." + +#. type: Bullet: '- ' +#: ../src/guide/testing/overview.md +msgid "`tests/Unit.suite.yml`." +msgstr "`tests/Unit.suite.yml`." + +#. type: Bullet: '- ' +#: ../src/guide/testing/overview.md +msgid "`tests/Functional.suite.yml`." +msgstr "`tests/Functional.suite.yml`." + +#. type: Bullet: '- ' +#: ../src/guide/testing/overview.md +msgid "`tests/Web.suite.yml`." +msgstr "`tests/Web.suite.yml`." + +#. type: Bullet: '- ' +#: ../src/guide/testing/overview.md +msgid "`tests/Console.suite.yml`." +msgstr "`tests/Console.suite.yml`." + +#. type: Bullet: '- ' +#: ../src/guide/testing/overview.md +msgid "`tests/Support/*Tester.php`." +msgstr "`tests/Support/*Tester.php`." + +#. type: Title ## +#: ../src/guide/testing/overview.md +#, no-wrap +msgid "Run tests locally" +msgstr "Executar testes localmente" + +#. type: Plain text +#: ../src/guide/testing/overview.md +msgid "Build actor classes after installing dependencies or changing a suite:" +msgstr "Gere as classes de actor depois de instalar as dependências ou alterar uma suíte:" + +#. type: Plain text +#: ../src/guide/testing/overview.md +msgid "Run all tests:" +msgstr "Execute todos os testes:" + +#. type: Plain text +#: ../src/guide/testing/overview.md +msgid "The template also defines a Composer script:" +msgstr "O template também define um script do Composer:" + +#. type: Fenced code block (shell) +#: ../src/guide/testing/overview.md +#, no-wrap +msgid "APP_ENV=test composer test\n" +msgstr "APP_ENV=test composer test\n" + +#. type: Plain text +#: ../src/guide/testing/overview.md +msgid "Run one suite:" +msgstr "Execute uma suíte:" + +#. type: Fenced code block (shell) +#: ../src/guide/testing/overview.md +#, no-wrap +msgid "" +"APP_ENV=test vendor/bin/codecept run Unit\n" +"APP_ENV=test vendor/bin/codecept run Functional\n" +"APP_ENV=test vendor/bin/codecept run Web\n" +"APP_ENV=test vendor/bin/codecept run Console\n" +msgstr "" +"APP_ENV=test vendor/bin/codecept run Unit\n" +"APP_ENV=test vendor/bin/codecept run Functional\n" +"APP_ENV=test vendor/bin/codecept run Web\n" +"APP_ENV=test vendor/bin/codecept run Console\n" + +#. type: Plain text +#: ../src/guide/testing/overview.md +msgid "Run one test class or method:" +msgstr "Execute uma classe ou um método de teste:" + +#. type: Fenced code block (shell) +#: ../src/guide/testing/overview.md +#, no-wrap +msgid "" +"APP_ENV=test vendor/bin/codecept run Functional HomePageCest\n" +"APP_ENV=test vendor/bin/codecept run Functional HomePageCest:base\n" +msgstr "" +"APP_ENV=test vendor/bin/codecept run Functional HomePageCest\n" +"APP_ENV=test vendor/bin/codecept run Functional HomePageCest:base\n" + +#. type: Plain text +#: ../src/guide/testing/overview.md +msgid "`APP_ENV=test` is required for local commands because `tests/bootstrap.php` prepares the application environment before tests run." +msgstr "`APP_ENV=test` é obrigatório nos comandos locais porque `tests/bootstrap.php` prepara o ambiente da aplicação antes da execução dos testes." + +#. type: Title ## +#: ../src/guide/testing/overview.md +#, no-wrap +msgid "Run tests in Docker" +msgstr "Executar testes no Docker" + +#. type: Plain text +#: ../src/guide/testing/overview.md +msgid "Build actor classes:" +msgstr "Gere as classes de actor:" + +#. type: Fenced code block (shell) +#: ../src/guide/testing/overview.md +#, no-wrap +msgid "make test\n" +msgstr "make test\n" + +#. type: Fenced code block (shell) +#: ../src/guide/testing/overview.md +#, no-wrap +msgid "" +"make test Unit\n" +"make test Functional\n" +"make test Web\n" +"make test Console\n" +msgstr "" +"make test Unit\n" +"make test Functional\n" +"make test Web\n" +"make test Console\n" + +#. type: Plain text +#: ../src/guide/testing/overview.md +msgid "The Docker test environment reads `docker/test/.env`, where `APP_ENV=test` is already set." +msgstr "O ambiente de testes do Docker lê `docker/test/.env`, onde `APP_ENV=test` já está definido." + +#. type: Title ## +#: ../src/guide/testing/overview.md +#, no-wrap +msgid "Choose a suite" +msgstr "Escolher uma suíte" + +#. type: Plain text +#: ../src/guide/testing/overview.md +msgid "Start with unit tests for code that has no framework boundary: value objects, validators, domain services, and transformers." +msgstr "Comece com testes unitários para código que não tem fronteira com o framework: value objects, validadores, serviços de domínio e transformadores." + +#. type: Plain text +#: ../src/guide/testing/overview.md +msgid "Use functional tests when code needs Yii configuration, dependency injection, routing, middleware, request handling, or template rendering." +msgstr "Use testes funcionais quando o código precisa da configuração do Yii, injeção de dependência, roteamento, middlewares, tratamento de requisições ou renderização de templates." + +#. type: Plain text +#: ../src/guide/testing/overview.md +msgid "Use web tests for behavior that must go through an HTTP server: status codes, links, redirects, cookies, and rendered pages as seen by a client." +msgstr "Use testes web para comportamentos que precisam passar por um servidor HTTP: códigos de status, links, redirecionamentos, cookies e páginas renderizadas como o cliente as vê." + +#. type: Plain text +#: ../src/guide/testing/overview.md +msgid "Use console tests for commands in `src/Console`." +msgstr "Use testes de console para os comandos em `src/Console`." + +#. type: Plain text +#: ../src/guide/testing/overview.md +msgid "Run static analysis in CI and before changing shared contracts." +msgstr "Execute a análise estática no CI e antes de alterar contratos compartilhados." diff --git a/_translations/po/pt-BR/guide_testing_quality-tools.md.po b/_translations/po/pt-BR/guide_testing_quality-tools.md.po new file mode 100644 index 00000000..5d858394 --- /dev/null +++ b/_translations/po/pt-BR/guide_testing_quality-tools.md.po @@ -0,0 +1,223 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-05-08 08:49+0000\n" +"PO-Revision-Date: 2026-05-08 08:49+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Plain text +#: ../src/cookbook/configuring-xdebug.md ../src/guide/testing/end-to-end.md ../src/guide/testing/environment-setup.md ../src/guide/testing/quality-tools.md +msgid "With Docker:" +msgstr "Com Docker:" + +#. type: Title # +#: ../src/guide/testing/quality-tools.md +#, no-wrap +msgid "Static analysis and code quality" +msgstr "Análise estática e qualidade de código" + +#. type: Plain text +#: ../src/guide/testing/quality-tools.md +msgid "The Yii application template includes static analysis and code quality tools alongside the test suite." +msgstr "O template de aplicação Yii inclui ferramentas de análise estática e de qualidade de código junto com a suíte de testes." + +#. type: Title ## +#: ../src/guide/testing/quality-tools.md +#, no-wrap +msgid "Psalm" +msgstr "Psalm" + +#. type: Plain text +#: ../src/guide/testing/quality-tools.md +msgid "Run Psalm locally:" +msgstr "Execute o Psalm localmente:" + +#. type: Fenced code block (shell) +#: ../src/guide/testing/quality-tools.md +#, no-wrap +msgid "vendor/bin/psalm\n" +msgstr "vendor/bin/psalm\n" + +#. type: Plain text +#: ../src/guide/testing/quality-tools.md +msgid "Run Psalm in Docker:" +msgstr "Execute o Psalm no Docker:" + +#. type: Fenced code block (shell) +#: ../src/guide/testing/quality-tools.md +#, no-wrap +msgid "make psalm\n" +msgstr "make psalm\n" + +#. type: Plain text +#: ../src/guide/testing/quality-tools.md +msgid "The template stores Psalm configuration in `psalm.xml`. The GitHub Actions workflow runs Psalm for supported PHP versions." +msgstr "O template guarda a configuração do Psalm em `psalm.xml`. O workflow do GitHub Actions executa o Psalm nas versões de PHP suportadas." + +#. type: Plain text +#: ../src/guide/testing/quality-tools.md +msgid "When Psalm reports an issue, fix the code or add a precise type annotation. Keep suppressions narrow and local to the line or method that needs them." +msgstr "Quando o Psalm reportar um problema, corrija o código ou adicione uma anotação de tipo precisa. Mantenha as supressões restritas e locais à linha ou ao método que precisa delas." + +#. type: Title ## +#: ../src/guide/testing/quality-tools.md +#, no-wrap +msgid "Composer Dependency Analyser" +msgstr "Composer Dependency Analyser" + +#. type: Plain text +#: ../src/guide/testing/quality-tools.md +msgid "Composer Dependency Analyser checks that `composer.json` matches the classes used by the application." +msgstr "O Composer Dependency Analyser verifica se o `composer.json` corresponde às classes usadas pela aplicação." + +#. type: Plain text +#: ../src/guide/testing/quality-tools.md +msgid "Run it locally:" +msgstr "Execute-o localmente:" + +#. type: Fenced code block (shell) +#: ../src/guide/testing/quality-tools.md +#, no-wrap +msgid "vendor/bin/composer-dependency-analyser --config=composer-dependency-analyser.php\n" +msgstr "vendor/bin/composer-dependency-analyser --config=composer-dependency-analyser.php\n" + +#. type: Plain text +#: ../src/guide/testing/quality-tools.md +msgid "Run it in Docker:" +msgstr "Execute-o no Docker:" + +#. type: Fenced code block (shell) +#: ../src/guide/testing/quality-tools.md +#, no-wrap +msgid "make composer-dependency-analyser\n" +msgstr "make composer-dependency-analyser\n" + +#. type: Plain text +#: ../src/guide/testing/quality-tools.md +msgid "Use this check after adding or removing package usage in `src`, `config`, or `tests`." +msgstr "Use essa verificação depois de adicionar ou remover o uso de pacotes em `src`, `config` ou `tests`." + +#. type: Title ## +#: ../src/guide/testing/quality-tools.md +#, no-wrap +msgid "PHP CS Fixer" +msgstr "PHP CS Fixer" + +#. type: Plain text +#: ../src/guide/testing/quality-tools.md +msgid "PHP CS Fixer applies the project coding style from `.php-cs-fixer.php`." +msgstr "O PHP CS Fixer aplica o estilo de código do projeto definido em `.php-cs-fixer.php`." + +#. type: Fenced code block (shell) +#: ../src/guide/testing/quality-tools.md +#, no-wrap +msgid "vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.php --diff\n" +msgstr "vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.php --diff\n" + +#. type: Fenced code block (shell) +#: ../src/guide/testing/quality-tools.md +#, no-wrap +msgid "make cs-fix\n" +msgstr "make cs-fix\n" + +#. type: Plain text +#: ../src/guide/testing/quality-tools.md +msgid "Commit formatting changes together with the code that needs them." +msgstr "Faça o commit das mudanças de formatação junto com o código que as exige." + +#. type: Title ## +#: ../src/guide/testing/quality-tools.md +#, no-wrap +msgid "Rector" +msgstr "Rector" + +#. type: Plain text +#: ../src/guide/testing/quality-tools.md +msgid "Rector applies configured code upgrades and refactorings from `rector.php`." +msgstr "O Rector aplica as atualizações e refatorações de código configuradas em `rector.php`." + +#. type: Plain text +#: ../src/guide/testing/quality-tools.md +msgid "Preview changes locally:" +msgstr "Visualize as mudanças localmente:" + +#. type: Fenced code block (shell) +#: ../src/guide/testing/quality-tools.md +#, no-wrap +msgid "vendor/bin/rector --dry-run\n" +msgstr "vendor/bin/rector --dry-run\n" + +#. type: Plain text +#: ../src/guide/testing/quality-tools.md +msgid "Apply changes locally:" +msgstr "Aplique as mudanças localmente:" + +#. type: Fenced code block (shell) +#: ../src/guide/testing/quality-tools.md +#, no-wrap +msgid "vendor/bin/rector\n" +msgstr "vendor/bin/rector\n" + +#. type: Fenced code block (shell) +#: ../src/guide/testing/quality-tools.md +#, no-wrap +msgid "make rector\n" +msgstr "make rector\n" + +#. type: Plain text +#: ../src/guide/testing/quality-tools.md +msgid "Review Rector changes before committing them. Automated refactoring can change behavior when custom rules or broad paths are configured." +msgstr "Revise as mudanças do Rector antes de fazer o commit. A refatoração automatizada pode alterar o comportamento quando regras personalizadas ou caminhos amplos estão configurados." + +#. type: Title ## +#: ../src/guide/testing/quality-tools.md +#, no-wrap +msgid "Pull request checks" +msgstr "Verificações de pull request" + +#. type: Plain text +#: ../src/guide/testing/quality-tools.md +msgid "A practical local check before opening a pull request is:" +msgstr "Uma verificação local prática antes de abrir um pull request é:" + +#. type: Fenced code block (shell) +#: ../src/guide/testing/quality-tools.md +#, no-wrap +msgid "" +"APP_ENV=test vendor/bin/codecept build\n" +"APP_ENV=test vendor/bin/codecept run\n" +"vendor/bin/psalm\n" +"vendor/bin/composer-dependency-analyser --config=composer-dependency-analyser.php\n" +"vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.php --diff\n" +msgstr "" +"APP_ENV=test vendor/bin/codecept build\n" +"APP_ENV=test vendor/bin/codecept run\n" +"vendor/bin/psalm\n" +"vendor/bin/composer-dependency-analyser --config=composer-dependency-analyser.php\n" +"vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.php --diff\n" + +#. type: Fenced code block (shell) +#: ../src/guide/testing/quality-tools.md +#, no-wrap +msgid "" +"make codecept build\n" +"make test\n" +"make psalm\n" +"make composer-dependency-analyser\n" +"make cs-fix\n" +msgstr "" +"make codecept build\n" +"make test\n" +"make psalm\n" +"make composer-dependency-analyser\n" +"make cs-fix\n" diff --git a/_translations/po/pt-BR/guide_testing_unit.md.po b/_translations/po/pt-BR/guide_testing_unit.md.po new file mode 100644 index 00000000..923ef5a8 --- /dev/null +++ b/_translations/po/pt-BR/guide_testing_unit.md.po @@ -0,0 +1,443 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-05-08 08:49+0000\n" +"PO-Revision-Date: 2026-05-08 08:49+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Plain text +#: ../src/guide/testing/end-to-end.md ../src/guide/testing/unit.md +msgid "Run only this test:" +msgstr "Execute apenas este teste:" + +#. type: Plain text +#: ../src/guide/testing/functional.md ../src/guide/testing/unit.md +msgid "Run it:" +msgstr "Execute-o:" + +#. type: Title # +#: ../src/guide/testing/unit.md +#, no-wrap +msgid "Unit tests" +msgstr "Testes unitários" + +#. type: Plain text +#: ../src/guide/testing/unit.md +msgid "Unit tests check a small piece of PHP code directly. In the Yii application template they live in `tests/Unit` and run through the `Unit` Codeception suite." +msgstr "Testes unitários verificam diretamente um pequeno trecho de código PHP. No template de aplicação Yii eles ficam em `tests/Unit` e são executados pela suíte `Unit` do Codeception." + +#. type: Plain text +#: ../src/guide/testing/unit.md +msgid "The template includes `tests/Unit/EnvironmentTest.php`:" +msgstr "O template inclui `tests/Unit/EnvironmentTest.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/testing/unit.md +#, no-wrap +msgid "" +"generate('Hello, Yii3!');\n" +"\n" +" assertSame('hello-yii3', $slug);\n" +" }\n" +"}\n" +msgstr "" +"generate('Hello, Yii3!');\n" +"\n" +" assertSame('hello-yii3', $slug);\n" +" }\n" +"}\n" + +#. type: Fenced code block (shell) +#: ../src/guide/testing/unit.md +#, no-wrap +msgid "APP_ENV=test vendor/bin/codecept run Unit SlugGeneratorTest\n" +msgstr "APP_ENV=test vendor/bin/codecept run Unit SlugGeneratorTest\n" + +#. type: Title ## +#: ../src/guide/testing/unit.md +#, no-wrap +msgid "Test services with dependencies" +msgstr "Testar serviços com dependências" + +#. type: Plain text +#: ../src/guide/testing/unit.md +msgid "Pass dependencies through the constructor and use test doubles for I/O." +msgstr "Passe as dependências pelo construtor e use test doubles para I/O." + +#. type: Plain text +#: ../src/guide/testing/unit.md +msgid "Create `src/Clock/ClockInterface.php`:" +msgstr "Crie `src/Clock/ClockInterface.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/testing/unit.md +#, no-wrap +msgid "" +"clock->now());\n" +" }\n" +"}\n" +msgstr "" +"clock->now());\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/testing/unit.md +msgid "Create `tests/Unit/PublishPostTest.php`:" +msgstr "Crie `tests/Unit/PublishPostTest.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/testing/unit.md +#, no-wrap +msgid "" +"publish('Testing Yii');\n" +"\n" +" assertSame('Testing Yii', $post->title);\n" +" assertSame('2026-05-07 10:00:00', $post->publishedAt->format('Y-m-d H:i:s'));\n" +" }\n" +"}\n" +msgstr "" +"publish('Testing Yii');\n" +"\n" +" assertSame('Testing Yii', $post->title);\n" +" assertSame('2026-05-07 10:00:00', $post->publishedAt->format('Y-m-d H:i:s'));\n" +" }\n" +"}\n" + +#. type: Fenced code block (shell) +#: ../src/guide/testing/unit.md +#, no-wrap +msgid "APP_ENV=test vendor/bin/codecept run Unit PublishPostTest\n" +msgstr "APP_ENV=test vendor/bin/codecept run Unit PublishPostTest\n" + +#. type: Plain text +#: ../src/guide/testing/unit.md +msgid "Keep unit tests focused on one class or one small collaboration. Use functional tests when the behavior depends on Yii configuration, dependency injection, routing, or middleware." +msgstr "Mantenha os testes unitários focados em uma classe ou em uma pequena colaboração. Use testes funcionais quando o comportamento depende da configuração do Yii, injeção de dependência, roteamento ou middlewares." diff --git a/_translations/po/pt-BR/guide_tutorial_console-applications.md.po b/_translations/po/pt-BR/guide_tutorial_console-applications.md.po new file mode 100644 index 00000000..9352da81 --- /dev/null +++ b/_translations/po/pt-BR/guide_tutorial_console-applications.md.po @@ -0,0 +1,191 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-03-30 08:11+0000\n" +"PO-Revision-Date: 2026-03-30 08:11+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md ../src/guide/concept/autoloading.md ../src/guide/security/best-practices.md ../src/guide/structure/domain.md ../src/guide/tutorial/console-applications.md ../src/internals/004-namespaces.md ../src/internals/007-exceptions.md ../src/internals/008-interfaces.md +#, no-wrap +msgid "References" +msgstr "Referências" + +#. type: Title ## +#: ../src/guide/index.md ../src/guide/tutorial/console-applications.md +#, no-wrap +msgid "Getting started" +msgstr "Primeiros passos" + +#. type: Title # +#: ../src/guide/tutorial/console-applications.md +#, no-wrap +msgid "Console applications" +msgstr "Aplicações de console" + +#. type: Plain text +#: ../src/guide/tutorial/console-applications.md +msgid "Console applications are mainly used to create utility, background processing and maintenance tasks." +msgstr "Aplicações de console são usadas principalmente para criar utilitários, processamento em segundo plano e tarefas de manutenção." + +#. type: Plain text +#: ../src/guide/tutorial/console-applications.md +msgid "If you're using [yiisoft/app](https://github.com/yiisoft/app) or [yiisoft/app-api](https://github.com/yiisoft/app-api), console support is already included. You can access the entry point as:" +msgstr "Se você usa [yiisoft/app](https://github.com/yiisoft/app) ou [yiisoft/app-api](https://github.com/yiisoft/app-api), o suporte a console já vem incluído. Você pode acessar o ponto de entrada assim:" + +#. type: Fenced code block +#: ../src/guide/tutorial/console-applications.md +#, no-wrap +msgid "./yii\n" +msgstr "./yii\n" + +#. type: Plain text +#: ../src/guide/tutorial/console-applications.md +msgid "If you want a standalone console-only application, use the [yiisoft/app-console](https://github.com/yiisoft/app-console) project template:" +msgstr "Se você quer uma aplicação somente de console, use o template de projeto [yiisoft/app-console](https://github.com/yiisoft/app-console):" + +#. type: Fenced code block (sh) +#: ../src/guide/tutorial/console-applications.md +#, no-wrap +msgid "composer create-project yiisoft/app-console your-project\n" +msgstr "composer create-project yiisoft/app-console your-project\n" + +#. type: Plain text +#: ../src/guide/tutorial/console-applications.md +msgid "To add console support to an existing project from scratch, refer to the [yiisoft/yii-console package documentation](https://github.com/yiisoft/yii-console)." +msgstr "Para adicionar suporte a console a um projeto existente do zero, consulte a [documentação do pacote yiisoft/yii-console](https://github.com/yiisoft/yii-console)." + +#. type: Plain text +#: ../src/guide/tutorial/console-applications.md +msgid "Out of the box only `serve` command is available. It's starting PHP built-in web server to serve the application locally." +msgstr "De início, apenas o comando `serve` está disponível. Ele inicia o servidor web embutido do PHP para servir a aplicação localmente." + +#. type: Plain text +#: ../src/guide/tutorial/console-applications.md +msgid "Commands are executed with `symfony/console`. To create your own console command, you need to define a command:" +msgstr "Os comandos são executados com `symfony/console`. Para criar seu próprio comando de console, você precisa definir um comando:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/console-applications.md +#, no-wrap +msgid "" +"setHelp('This command serves for demo purpose')\n" +" ->addArgument('name', InputArgument::OPTIONAL, 'Name to greet', 'anonymous');\n" +" }\n" +"\n" +" protected function execute(InputInterface $input, OutputInterface $output): int\n" +" {\n" +" $io = new SymfonyStyle($input, $output);\n" +"\n" +" $name = $input->getArgument('name');\n" +" $io->success(\"Hello, $name!\");\n" +" return ExitCode::OK;\n" +" }\n" +"}\n" +msgstr "" +"setHelp('This command serves for demo purpose')\n" +" ->addArgument('name', InputArgument::OPTIONAL, 'Name to greet', 'anonymous');\n" +" }\n" +"\n" +" protected function execute(InputInterface $input, OutputInterface $output): int\n" +" {\n" +" $io = new SymfonyStyle($input, $output);\n" +"\n" +" $name = $input->getArgument('name');\n" +" $io->success(\"Hello, $name!\");\n" +" return ExitCode::OK;\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/tutorial/console-applications.md +msgid "Now register the command in `config/params.php`:" +msgstr "Agora registre o comando em `config/params.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/console-applications.md +#, no-wrap +msgid "" +"return [\n" +" 'yiisoft/yii-console' => [\n" +" 'commands' => [\n" +" 'demo:hello' => App\\Demo\\HelloCommand::class,\n" +" ],\n" +" ], \n" +"];\n" +msgstr "" +"return [\n" +" 'yiisoft/yii-console' => [\n" +" 'commands' => [\n" +" 'demo:hello' => App\\Demo\\HelloCommand::class,\n" +" ],\n" +" ], \n" +"];\n" + +#. type: Plain text +#: ../src/guide/tutorial/console-applications.md +msgid "After it's done, the command could be executed as" +msgstr "Feito isso, o comando pode ser executado assim" + +#. type: Fenced code block +#: ../src/guide/tutorial/console-applications.md +#, no-wrap +msgid "./yii demo:hello Alice\n" +msgstr "./yii demo:hello Alice\n" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/console-applications.md +msgid "[Symfony Console component guide](https://symfony.com/doc/current/components/console.html)" +msgstr "[Guia do componente Symfony Console](https://symfony.com/doc/current/components/console.html)" diff --git a/_translations/po/pt-BR/guide_tutorial_docker.md.po b/_translations/po/pt-BR/guide_tutorial_docker.md.po new file mode 100644 index 00000000..b36b6268 --- /dev/null +++ b/_translations/po/pt-BR/guide_tutorial_docker.md.po @@ -0,0 +1,962 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-04-07 16:34+0000\n" +"PO-Revision-Date: 2026-04-07 16:34+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ### +#: ../src/guide/index.md ../src/guide/tutorial/docker.md +#, no-wrap +msgid "Testing" +msgstr "Testes" + +#. type: Title # +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "Docker in Application Templates" +msgstr "Docker nos templates de aplicação" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "Both [yiisoft/app](https://github.com/yiisoft/app) and [yiisoft/app-api](https://github.com/yiisoft/app-api) come with a ready-to-use Docker setup based on [FrankenPHP](https://frankenphp.dev/) with Caddy as the built-in web server. The setup covers local development, testing, and production deployment through a set of environment files, Docker Compose configurations, a multi-stage Dockerfile, and a `Makefile` that wraps common operations." +msgstr "Tanto o [yiisoft/app](https://github.com/yiisoft/app) quanto o [yiisoft/app-api](https://github.com/yiisoft/app-api) vêm com uma configuração Docker pronta para uso, baseada em [FrankenPHP](https://frankenphp.dev/) com Caddy como servidor web embutido. A configuração cobre desenvolvimento local, testes e deploy em produção por meio de um conjunto de arquivos de ambiente, configurações do Docker Compose, um Dockerfile multi-stage e um `Makefile` que encapsula as operações mais comuns." + +#. type: Title ## +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "Docker directory overview" +msgstr "Visão geral do diretório docker" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "All Docker-related files live under the `docker/` directory:" +msgstr "Todos os arquivos relacionados ao Docker ficam no diretório `docker/`:" + +#. type: Fenced code block +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "" +"docker/\n" +"├── .env # Compose-level variables (stack name, ports, image names)\n" +"├── Dockerfile # Multi-stage image definition\n" +"├── compose.yml # Base Compose file (shared anchor for all environments)\n" +"├── dev/\n" +"│ ├── .env # Application environment variables for development\n" +"│ ├── .gitignore # Excludes override.env from version control\n" +"│ ├── compose.yml # Development-specific Compose overrides\n" +"│ └── override.env.example # Optional developer-local overrides template\n" +"├── test/\n" +"│ ├── .env # Application environment variables for testing\n" +"│ ├── .gitignore # Excludes override.env from version control\n" +"│ └── compose.yml # Test-specific Compose overrides\n" +"└── prod/\n" +" ├── .env # Application environment variables for production\n" +" ├── .gitignore # Excludes override.env from version control\n" +" └── compose.yml # Production-specific Compose overrides (Docker Swarm)\n" +msgstr "" +"docker/\n" +"├── .env # Variáveis do Compose (nome da stack, portas, nomes de imagens)\n" +"├── Dockerfile # Definição de imagem multi-stage\n" +"├── compose.yml # Arquivo Compose base (âncora compartilhada por todos os ambientes)\n" +"├── dev/\n" +"│ ├── .env # Variáveis de ambiente da aplicação para desenvolvimento\n" +"│ ├── .gitignore # Exclui override.env do controle de versão\n" +"│ ├── compose.yml # Overrides do Compose específicos de desenvolvimento\n" +"│ └── override.env.example # Template opcional de overrides locais do desenvolvedor\n" +"├── test/\n" +"│ ├── .env # Variáveis de ambiente da aplicação para testes\n" +"│ ├── .gitignore # Exclui override.env do controle de versão\n" +"│ └── compose.yml # Overrides do Compose específicos de testes\n" +"└── prod/\n" +" ├── .env # Variáveis de ambiente da aplicação para produção\n" +" ├── .gitignore # Exclui override.env do controle de versão\n" +" └── compose.yml # Overrides do Compose específicos de produção (Docker Swarm)\n" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "Each subdirectory (`dev/`, `test/`, `prod/`) corresponds to an environment stage and contains its own `.env` file with application-level configuration and a `compose.yml` that extends the base `docker/compose.yml`." +msgstr "Cada subdiretório (`dev/`, `test/`, `prod/`) corresponde a um estágio de ambiente e contém seu próprio arquivo `.env` com a configuração da aplicação e um `compose.yml` que estende o `docker/compose.yml` base." + +#. type: Title ## +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "Environment files" +msgstr "Arquivos de ambiente" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "The templates use two separate environment systems that serve different purposes and different runtimes." +msgstr "Os templates usam dois sistemas de ambiente separados, com propósitos e runtimes diferentes." + +#. type: Title ### +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid ".env.example (project root)" +msgstr ".env.example (raiz do projeto)" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "The project root contains a `.env.example` file that serves as a template for local development **without Docker**:" +msgstr "A raiz do projeto contém um arquivo `.env.example` que serve de template para desenvolvimento local **sem Docker**:" + +#. type: Fenced code block (ini) +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "" +"# Local environment configuration.\n" +"# Copy this file to .env and adjust as needed.\n" +"# In production, set environment variables via server or container configuration instead.\n" +"APP_ENV=dev\n" +"APP_DEBUG=true\n" +msgstr "" +"# Configuração do ambiente local.\n" +"# Copie este arquivo para .env e ajuste conforme necessário.\n" +"# Em produção, defina as variáveis de ambiente pela configuração do servidor ou do container.\n" +"APP_ENV=dev\n" +"APP_DEBUG=true\n" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "Copy it to create your local configuration file:" +msgstr "Copie-o para criar seu arquivo de configuração local:" + +#. type: Fenced code block (sh) +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "cp .env.example .env\n" +msgstr "cp .env.example .env\n" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "The `.env` file is loaded automatically by `src/bootstrap.php` using [phpdotenv](https://github.com/vlucas/phpdotenv) only when `APP_ENV` is not already present in the process environment. This means **Docker-provided environment variables always take precedence** over the root `.env` file — both workflows can coexist safely in the same project directory." +msgstr "O arquivo `.env` é carregado automaticamente por `src/bootstrap.php` usando o [phpdotenv](https://github.com/vlucas/phpdotenv) somente quando `APP_ENV` ainda não está presente no ambiente do processo. Isso significa que **as variáveis de ambiente fornecidas pelo Docker sempre têm precedência** sobre o arquivo `.env` da raiz — os dois fluxos de trabalho podem coexistir com segurança no mesmo diretório do projeto." + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "" +"> [!NOTE]\n" +"> `phpdotenv` is a development dependency and is not installed in production\n" +"> (`composer install --no-dev`), so the root `.env` file has no effect on production containers.\n" +msgstr "" +"> [!NOTE]\n" +"> `phpdotenv` é uma dependência de desenvolvimento e não é instalado em produção\n" +"> (`composer install --no-dev`), então o arquivo `.env` da raiz não tem efeito nos containers de produção.\n" + +#. type: Title ### +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "docker/.env" +msgstr "docker/.env" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "This file contains variables used by the Compose files themselves — they are **not** passed into the running application container:" +msgstr "Este arquivo contém variáveis usadas pelos próprios arquivos Compose — elas **não** são repassadas ao container da aplicação em execução:" + +#. type: Fenced code block (ini) +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "" +"# Variables for compose.yml files. Not available in the app.\n" +"\n" +"STACK_NAME=app\n" +"\n" +"# Development\n" +"\n" +"DEV_PORT=80\n" +"\n" +"# Production\n" +"\n" +"PROD_HOST=app.example.com\n" +"PROD_SSH=\"ssh://docker-web\"\n" +"\n" +"IMAGE=app\n" +"IMAGE_TAG=latest\n" +msgstr "" +"# Variáveis para os arquivos compose.yml. Não disponíveis na aplicação.\n" +"\n" +"STACK_NAME=app\n" +"\n" +"# Desenvolvimento\n" +"\n" +"DEV_PORT=80\n" +"\n" +"# Produção\n" +"\n" +"PROD_HOST=app.example.com\n" +"PROD_SSH=\"ssh://docker-web\"\n" +"\n" +"IMAGE=app\n" +"IMAGE_TAG=latest\n" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "" +"| Variable | Purpose |\n" +"|--------------|-------------------------------------------------------------------------|\n" +"| `STACK_NAME` | Docker Compose project name and Docker Swarm stack name. |\n" +"| `DEV_PORT` | Host port to expose the application on in development (`make up`). |\n" +"| `PROD_HOST` | Hostname used by Caddy labels for automatic HTTPS in production. |\n" +"| `PROD_SSH` | Remote Docker host for deploying to a Swarm node via SSH. |\n" +"| `IMAGE` | Docker image name used during build and push. |\n" +"| `IMAGE_TAG` | Docker image tag (`latest` by default; use a version string in CI/CD). |\n" +msgstr "" +"| Variável | Finalidade |\n" +"|--------------|-------------------------------------------------------------------------|\n" +"| `STACK_NAME` | Nome do projeto Docker Compose e nome da stack do Docker Swarm. |\n" +"| `DEV_PORT` | Porta do host onde a aplicação é exposta em desenvolvimento (`make up`). |\n" +"| `PROD_HOST` | Hostname usado pelos labels do Caddy para HTTPS automático em produção. |\n" +"| `PROD_SSH` | Host Docker remoto para deploy em um nó Swarm via SSH. |\n" +"| `IMAGE` | Nome da imagem Docker usada no build e no push. |\n" +"| `IMAGE_TAG` | Tag da imagem Docker (`latest` por padrão; use uma versão no CI/CD). |\n" + +#. type: Title ### +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "docker/dev/.env" +msgstr "docker/dev/.env" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "Contains application environment variables injected into the development container at runtime:" +msgstr "Contém as variáveis de ambiente da aplicação injetadas no container de desenvolvimento em tempo de execução:" + +#. type: Fenced code block (ini) +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "" +"# App dev environment.\n" +"# Note that variables are available in the app only, not in compose.yml.\n" +"\n" +"APP_ENV=dev\n" +"APP_DEBUG=true\n" +"SERVER_NAME=:80\n" +"XDEBUG_MODE=develop\n" +"COMPOSER_CACHE_DIR=/app/runtime/cache/composer\n" +msgstr "" +"# Ambiente dev da aplicação.\n" +"# Note que as variáveis ficam disponíveis apenas na aplicação, não no compose.yml.\n" +"\n" +"APP_ENV=dev\n" +"APP_DEBUG=true\n" +"SERVER_NAME=:80\n" +"XDEBUG_MODE=develop\n" +"COMPOSER_CACHE_DIR=/app/runtime/cache/composer\n" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "" +"| Variable | Purpose |\n" +"|-----------------------|--------------------------------------------------------------------------------------|\n" +"| `APP_ENV` | Application environment. `dev` enables developer-friendly behavior. |\n" +"| `APP_DEBUG` | Enables detailed error output and debug panels. |\n" +"| `SERVER_NAME` | Caddy server address — `:80` means listen on all interfaces on port 80. |\n" +"| `XDEBUG_MODE` | Xdebug mode. Use `develop` for helpers and `debug` to enable step debugging. |\n" +"| `COMPOSER_CACHE_DIR` | Moves Composer's cache into the mounted volume so it persists between runs. |\n" +msgstr "" +"| Variável | Finalidade |\n" +"|-----------------------|--------------------------------------------------------------------------------------|\n" +"| `APP_ENV` | Ambiente da aplicação. `dev` ativa um comportamento amigável para o desenvolvedor. |\n" +"| `APP_DEBUG` | Ativa saída de erros detalhada e painéis de debug. |\n" +"| `SERVER_NAME` | Endereço do servidor Caddy — `:80` significa escutar em todas as interfaces na porta 80. |\n" +"| `XDEBUG_MODE` | Modo do Xdebug. Use `develop` para helpers e `debug` para ativar a depuração passo a passo. |\n" +"| `COMPOSER_CACHE_DIR` | Move o cache do Composer para o volume montado, para que persista entre execuções. |\n" + +#. type: Title ### +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "docker/test/.env" +msgstr "docker/test/.env" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "Contains application environment variables for the test container:" +msgstr "Contém as variáveis de ambiente da aplicação para o container de testes:" + +#. type: Fenced code block (ini) +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "" +"# App test environment.\n" +"# Note that variables are available in the app only, not in compose.yml.\n" +"\n" +"APP_ENV=test\n" +"APP_DEBUG=false\n" +"APP_C3=true\n" +"SERVER_NAME=:80\n" +"XDEBUG_MODE=coverage\n" +"COMPOSER_CACHE_DIR=/app/runtime/cache/composer\n" +msgstr "" +"# Ambiente test da aplicação.\n" +"# Note que as variáveis ficam disponíveis apenas na aplicação, não no compose.yml.\n" +"\n" +"APP_ENV=test\n" +"APP_DEBUG=false\n" +"APP_C3=true\n" +"SERVER_NAME=:80\n" +"XDEBUG_MODE=coverage\n" +"COMPOSER_CACHE_DIR=/app/runtime/cache/composer\n" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "" +"| Variable | Purpose |\n" +"|----------------------|-----------------------------------------------------------------------------------------------|\n" +"| `APP_ENV` | Sets the environment to `test` so the application loads test-specific configuration. |\n" +"| `APP_DEBUG` | Disabled in tests to match a realistic execution context. |\n" +"| `APP_C3` | Enables [c3](https://github.com/Codeception/c3) remote code coverage collection. |\n" +"| `SERVER_NAME` | Caddy server address. |\n" +"| `XDEBUG_MODE` | `coverage` activates Xdebug's code coverage driver required for coverage reports. |\n" +"| `COMPOSER_CACHE_DIR` | Persistent Composer cache inside the volume. |\n" +msgstr "" +"| Variável | Finalidade |\n" +"|----------------------|-----------------------------------------------------------------------------------------------|\n" +"| `APP_ENV` | Define o ambiente como `test` para que a aplicação carregue a configuração específica de testes. |\n" +"| `APP_DEBUG` | Desativado nos testes para corresponder a um contexto de execução realista. |\n" +"| `APP_C3` | Ativa a coleta remota de cobertura de código com [c3](https://github.com/Codeception/c3). |\n" +"| `SERVER_NAME` | Endereço do servidor Caddy. |\n" +"| `XDEBUG_MODE` | `coverage` ativa o driver de cobertura de código do Xdebug, necessário para os relatórios de cobertura. |\n" +"| `COMPOSER_CACHE_DIR` | Cache persistente do Composer dentro do volume. |\n" + +#. type: Title ### +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "docker/prod/.env" +msgstr "docker/prod/.env" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "Contains application environment variables for the production container:" +msgstr "Contém as variáveis de ambiente da aplicação para o container de produção:" + +#. type: Fenced code block (ini) +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "" +"# App prod environment.\n" +"# Note that variables are available in the app only, not in compose.yml.\n" +"\n" +"APP_ENV=prod\n" +"APP_DEBUG=false\n" +"SERVER_NAME=:80\n" +msgstr "" +"# Ambiente prod da aplicação.\n" +"# Note que as variáveis ficam disponíveis apenas na aplicação, não no compose.yml.\n" +"\n" +"APP_ENV=prod\n" +"APP_DEBUG=false\n" +"SERVER_NAME=:80\n" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "The production environment intentionally uses a minimal configuration. Secrets and host-specific overrides should be managed through deployment tooling and never committed to version control." +msgstr "O ambiente de produção usa intencionalmente uma configuração mínima. Segredos e overrides específicos de host devem ser gerenciados pelas ferramentas de deploy e nunca commitados no controle de versão." + +#. type: Title ### +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "Override env files" +msgstr "Arquivos env de override" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "Each environment directory contains a `.gitignore` that excludes an `override.env` file. This file is optional and, when present, is merged on top of the main `.env` for that environment:" +msgstr "Cada diretório de ambiente contém um `.gitignore` que exclui um arquivo `override.env`. Esse arquivo é opcional e, quando presente, é mesclado por cima do `.env` principal daquele ambiente:" + +#. type: Fenced code block +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "" +"# docker/dev/override.env.example\n" +"APP_HOST_PATH=/projects/yiisoft/app\n" +msgstr "" +"# docker/dev/override.env.example\n" +"APP_HOST_PATH=/projects/yiisoft/app\n" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "Copy the example file to create your local overrides:" +msgstr "Copie o arquivo de exemplo para criar seus overrides locais:" + +#. type: Fenced code block (sh) +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "cp docker/dev/override.env.example docker/dev/override.env\n" +msgstr "cp docker/dev/override.env.example docker/dev/override.env\n" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "Use override files for developer-specific settings such as Xdebug IDE keys or local bind paths that should not be shared with the team." +msgstr "Use arquivos de override para configurações específicas do desenvolvedor, como chaves de IDE do Xdebug ou caminhos locais de bind, que não devem ser compartilhados com o time." + +#. type: Title ## +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "Compose files" +msgstr "Arquivos Compose" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "The Compose configuration is split across multiple files that Docker Compose merges at runtime. This approach avoids duplicating shared settings and keeps each environment's file focused and small." +msgstr "A configuração do Compose é dividida em vários arquivos que o Docker Compose mescla em tempo de execução. Essa abordagem evita duplicar configurações compartilhadas e mantém o arquivo de cada ambiente pequeno e focado." + +#. type: Title ### +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "docker/compose.yml (base)" +msgstr "docker/compose.yml (base)" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "The base file defines shared settings inherited by all environments:" +msgstr "O arquivo base define configurações compartilhadas herdadas por todos os ambientes:" + +#. type: Fenced code block (yaml) +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "" +"services:\n" +" app: &appconfig\n" +" extra_hosts:\n" +" - \"host.docker.internal:host-gateway\"\n" +"\n" +"volumes:\n" +" caddy_data:\n" +" caddy_config:\n" +msgstr "" +"services:\n" +" app: &appconfig\n" +" extra_hosts:\n" +" - \"host.docker.internal:host-gateway\"\n" +"\n" +"volumes:\n" +" caddy_data:\n" +" caddy_config:\n" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "The `&appconfig` YAML anchor lets environment files reference and extend this service definition. The `host.docker.internal` entry maps to the Docker host so containers can reach services running on the host machine (for example, a local database)." +msgstr "A âncora YAML `&appconfig` permite que os arquivos de ambiente referenciem e estendam essa definição de serviço. A entrada `host.docker.internal` aponta para o host Docker, para que os containers alcancem serviços rodando na máquina host (por exemplo, um banco de dados local)." + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "The two named volumes (`caddy_data` and `caddy_config`) persist Caddy's certificate storage and configuration across container restarts." +msgstr "Os dois volumes nomeados (`caddy_data` e `caddy_config`) persistem o armazenamento de certificados e a configuração do Caddy entre reinicializações do container." + +#. type: Title ### +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "docker/dev/compose.yml" +msgstr "docker/dev/compose.yml" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "Extends the base file for local development:" +msgstr "Estende o arquivo base para desenvolvimento local:" + +#. type: Fenced code block (yaml) +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "" +"services:\n" +" app:\n" +" build:\n" +" dockerfile: docker/Dockerfile\n" +" context: ..\n" +" target: dev\n" +" args:\n" +" USER_ID: ${UID}\n" +" GROUP_ID: ${GID}\n" +" env_file:\n" +" - path: ./dev/.env\n" +" - path: ./dev/override.env\n" +" required: false\n" +" ports:\n" +" - \"${DEV_PORT:-80}:80\"\n" +" volumes:\n" +" - ../:/app\n" +" - ../runtime:/app/runtime\n" +" - caddy_data:/data\n" +" - caddy_config:/config\n" +" tty: true\n" +msgstr "" +"services:\n" +" app:\n" +" build:\n" +" dockerfile: docker/Dockerfile\n" +" context: ..\n" +" target: dev\n" +" args:\n" +" USER_ID: ${UID}\n" +" GROUP_ID: ${GID}\n" +" env_file:\n" +" - path: ./dev/.env\n" +" - path: ./dev/override.env\n" +" required: false\n" +" ports:\n" +" - \"${DEV_PORT:-80}:80\"\n" +" volumes:\n" +" - ../:/app\n" +" - ../runtime:/app/runtime\n" +" - caddy_data:/data\n" +" - caddy_config:/config\n" +" tty: true\n" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "Key points:" +msgstr "Pontos principais:" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/docker.md +msgid "**`target: dev`** — Selects the `dev` stage from the multi-stage Dockerfile." +msgstr "**`target: dev`** — Seleciona o estágio `dev` do Dockerfile multi-stage." + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/docker.md +msgid "**`USER_ID` / `GROUP_ID`** — Passed as build arguments so the container user matches the host user, preventing file permission issues on Linux." +msgstr "**`USER_ID` / `GROUP_ID`** — Passados como argumentos de build para que o usuário do container corresponda ao usuário do host, evitando problemas de permissão de arquivos no Linux." + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/docker.md +msgid "**`env_file`** — Loads `docker/dev/.env` and, optionally, the developer's local `override.env`." +msgstr "**`env_file`** — Carrega `docker/dev/.env` e, opcionalmente, o `override.env` local do desenvolvedor." + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/docker.md +msgid "**`ports`** — Exposes port 80 (or `DEV_PORT` from `docker/.env`) on the host." +msgstr "**`ports`** — Expõe a porta 80 (ou `DEV_PORT` de `docker/.env`) no host." + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/docker.md +msgid "**`volumes`** — Mounts the entire project into `/app` so code changes are reflected immediately without rebuilding the image." +msgstr "**`volumes`** — Monta o projeto inteiro em `/app` para que mudanças no código sejam refletidas imediatamente, sem rebuild da imagem." + +#. type: Title ### +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "docker/test/compose.yml" +msgstr "docker/test/compose.yml" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "Identical in structure to the dev file but loads `docker/test/.env` and does not expose ports to the host, since tests run entirely inside the container network." +msgstr "Tem a mesma estrutura do arquivo dev, mas carrega `docker/test/.env` e não expõe portas para o host, já que os testes rodam inteiramente dentro da rede de containers." + +#. type: Title ### +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "docker/prod/compose.yml" +msgstr "docker/prod/compose.yml" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "Targets production deployments using Docker Swarm:" +msgstr "Voltado a deploys em produção usando Docker Swarm:" + +#. type: Fenced code block (yaml) +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "" +"services:\n" +" app:\n" +" image: ${IMAGE}:${IMAGE_TAG}\n" +" networks:\n" +" - caddy_public\n" +" volumes:\n" +" - runtime:/app/runtime\n" +" - caddy_data:/data\n" +" - caddy_config:/config\n" +" env_file:\n" +" - path: ./prod/.env\n" +" - path: ./prod/override.env\n" +" required: false\n" +" deploy:\n" +" replicas: 2\n" +" update_config:\n" +" delay: 10s\n" +" parallelism: 1\n" +" order: start-first\n" +" failure_action: rollback\n" +" monitor: 10s\n" +" rollback_config:\n" +" parallelism: 0\n" +" order: stop-first\n" +" restart_policy:\n" +" condition: on-failure\n" +" delay: 5s\n" +" max_attempts: 3\n" +" window: 120s\n" +" labels:\n" +" caddy: ${PROD_HOST:-app.example.com}\n" +" caddy.reverse_proxy: \"{{upstreams 80}}\"\n" +"\n" +"volumes:\n" +" runtime:\n" +"\n" +"networks:\n" +" caddy_public:\n" +" external: true\n" +msgstr "" +"services:\n" +" app:\n" +" image: ${IMAGE}:${IMAGE_TAG}\n" +" networks:\n" +" - caddy_public\n" +" volumes:\n" +" - runtime:/app/runtime\n" +" - caddy_data:/data\n" +" - caddy_config:/config\n" +" env_file:\n" +" - path: ./prod/.env\n" +" - path: ./prod/override.env\n" +" required: false\n" +" deploy:\n" +" replicas: 2\n" +" update_config:\n" +" delay: 10s\n" +" parallelism: 1\n" +" order: start-first\n" +" failure_action: rollback\n" +" monitor: 10s\n" +" rollback_config:\n" +" parallelism: 0\n" +" order: stop-first\n" +" restart_policy:\n" +" condition: on-failure\n" +" delay: 5s\n" +" max_attempts: 3\n" +" window: 120s\n" +" labels:\n" +" caddy: ${PROD_HOST:-app.example.com}\n" +" caddy.reverse_proxy: \"{{upstreams 80}}\"\n" +"\n" +"volumes:\n" +" runtime:\n" +"\n" +"networks:\n" +" caddy_public:\n" +" external: true\n" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "Instead of building an image, the production file references a pre-built image (`${IMAGE}:${IMAGE_TAG}`). The `deploy` block configures Docker Swarm behaviour: two replicas with a rolling `start-first` update strategy and automatic rollback on failure. The `caddy` labels are picked up by a [Caddy Docker Proxy](https://github.com/lucaslorentz/caddy-docker-proxy) running in the same Swarm to configure automatic HTTPS routing." +msgstr "Em vez de fazer build de uma imagem, o arquivo de produção referencia uma imagem pré-construída (`${IMAGE}:${IMAGE_TAG}`). O bloco `deploy` configura o comportamento do Docker Swarm: duas réplicas com estratégia de atualização gradual `start-first` e rollback automático em caso de falha. Os labels `caddy` são lidos por um [Caddy Docker Proxy](https://github.com/lucaslorentz/caddy-docker-proxy) rodando no mesmo Swarm para configurar o roteamento HTTPS automático." + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "" +"> [!NOTE]\n" +"> The `caddy_public` network must already exist on the Swarm before deploying.\n" +"> See the [Docker Swarm deployment guide](../../cookbook/deployment/docker-swarm.md) for full setup instructions.\n" +msgstr "" +"> [!NOTE]\n" +"> A rede `caddy_public` precisa existir no Swarm antes do deploy.\n" +"> Veja o [guia de deploy com Docker Swarm](../../cookbook/deployment/docker-swarm.md) para instruções completas de configuração.\n" + +#. type: Title ## +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "Multi-stage Dockerfile" +msgstr "Dockerfile multi-stage" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "The `docker/Dockerfile` uses [multi-stage builds](https://docs.docker.com/build/building/multi-stage/) to produce lean images for each purpose from a single file, avoiding duplication of the base setup:" +msgstr "O `docker/Dockerfile` usa [builds multi-stage](https://docs.docker.com/build/building/multi-stage/) para produzir imagens enxutas para cada finalidade a partir de um único arquivo, evitando duplicar a configuração base:" + +#. type: Fenced code block (dockerfile) +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "" +"FROM composer/composer:2-bin AS composer\n" +"\n" +"FROM dunglas/frankenphp:1-php8.2-bookworm AS base\n" +"\n" +"RUN apt update && apt -y install \\\n" +" unzip\n" +"\n" +"RUN install-php-extensions \\\n" +" opcache mbstring intl dom ctype curl phar openssl xml xmlwriter simplexml pdo\n" +"\n" +"ENV LC_ALL=C.UTF-8\n" +"\n" +"#\n" +"# Development\n" +"#\n" +"\n" +"FROM base AS dev\n" +"ARG USER_ID=10001\n" +"ARG GROUP_ID=10001\n" +"ARG USER_NAME=appuser\n" +"ARG GROUP_NAME=appuser\n" +"\n" +"RUN install-php-extensions xdebug\n" +"\n" +"COPY --from=composer /composer /usr/bin/composer\n" +"\n" +"RUN \\\n" +" groupadd --gid ${GROUP_ID} ${GROUP_NAME}; \\\n" +" useradd --gid ${GROUP_ID} --uid ${USER_ID} ${GROUP_NAME}; \\\n" +" setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/frankenphp; \\\n" +" chown -R ${USER_NAME}:${GROUP_NAME} /data/caddy && \\\n" +" chown -R ${USER_NAME}:${GROUP_NAME} /config/caddy\n" +"USER ${USER_NAME}\n" +"\n" +"#\n" +"# Production\n" +"#\n" +"\n" +"FROM base AS prod-builder\n" +"COPY --from=composer /composer /usr/bin/composer\n" +"COPY .. /app\n" +"RUN --mount=type=cache,target=/tmp/cache \\\n" +" composer install --no-dev --no-progress --no-interaction --classmap-authoritative && \\\n" +" rm composer.lock composer.json\n" +"\n" +"FROM base AS prod\n" +"ENV APP_ENV=prod\n" +"COPY --from=prod-builder --chown=www-data:www-data /app /app\n" +"USER www-data\n" +msgstr "" +"FROM composer/composer:2-bin AS composer\n" +"\n" +"FROM dunglas/frankenphp:1-php8.2-bookworm AS base\n" +"\n" +"RUN apt update && apt -y install \\\n" +" unzip\n" +"\n" +"RUN install-php-extensions \\\n" +" opcache mbstring intl dom ctype curl phar openssl xml xmlwriter simplexml pdo\n" +"\n" +"ENV LC_ALL=C.UTF-8\n" +"\n" +"#\n" +"# Development\n" +"#\n" +"\n" +"FROM base AS dev\n" +"ARG USER_ID=10001\n" +"ARG GROUP_ID=10001\n" +"ARG USER_NAME=appuser\n" +"ARG GROUP_NAME=appuser\n" +"\n" +"RUN install-php-extensions xdebug\n" +"\n" +"COPY --from=composer /composer /usr/bin/composer\n" +"\n" +"RUN \\\n" +" groupadd --gid ${GROUP_ID} ${GROUP_NAME}; \\\n" +" useradd --gid ${GROUP_ID} --uid ${USER_ID} ${GROUP_NAME}; \\\n" +" setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/frankenphp; \\\n" +" chown -R ${USER_NAME}:${GROUP_NAME} /data/caddy && \\\n" +" chown -R ${USER_NAME}:${GROUP_NAME} /config/caddy\n" +"USER ${USER_NAME}\n" +"\n" +"#\n" +"# Production\n" +"#\n" +"\n" +"FROM base AS prod-builder\n" +"COPY --from=composer /composer /usr/bin/composer\n" +"COPY .. /app\n" +"RUN --mount=type=cache,target=/tmp/cache \\\n" +" composer install --no-dev --no-progress --no-interaction --classmap-authoritative && \\\n" +" rm composer.lock composer.json\n" +"\n" +"FROM base AS prod\n" +"ENV APP_ENV=prod\n" +"COPY --from=prod-builder --chown=www-data:www-data /app /app\n" +"USER www-data\n" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "The Dockerfile defines four stages:" +msgstr "O Dockerfile define quatro estágios:" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "" +"| Stage | Purpose |\n" +"|----------------|--------------------------------------------------------------------------------------------------|\n" +"| `composer` | Copies the Composer binary from the official image to avoid installing it in other stages. |\n" +"| `base` | Installs FrankenPHP, common PHP extensions, and system packages shared by all environments. |\n" +"| `dev` | Extends `base` with Xdebug and Composer. Creates a non-root user matching the host user's UID/GID to prevent permission issues with mounted volumes. |\n" +"| `prod-builder` | Extends `base`, copies the application source, and runs `composer install --no-dev` using a build cache. Removes `composer.lock` and `composer.json` afterwards to keep the final image clean. |\n" +"| `prod` | Copies only the built application from `prod-builder` into a clean `base` image. This produces a small final image because the Composer binary and intermediate files are not included. |\n" +msgstr "" +"| Estágio | Finalidade |\n" +"|----------------|--------------------------------------------------------------------------------------------------|\n" +"| `composer` | Copia o binário do Composer da imagem oficial para evitar instalá-lo nos outros estágios. |\n" +"| `base` | Instala o FrankenPHP, extensões PHP comuns e pacotes de sistema compartilhados por todos os ambientes. |\n" +"| `dev` | Estende `base` com Xdebug e Composer. Cria um usuário não root com o mesmo UID/GID do usuário do host para evitar problemas de permissão com volumes montados. |\n" +"| `prod-builder` | Estende `base`, copia o código-fonte da aplicação e executa `composer install --no-dev` usando um cache de build. Remove `composer.lock` e `composer.json` em seguida para manter a imagem final limpa. |\n" +"| `prod` | Copia apenas a aplicação construída de `prod-builder` para uma imagem `base` limpa. Isso gera uma imagem final pequena, porque o binário do Composer e os arquivos intermediários não são incluídos. |\n" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "" +"> [!TIP]\n" +"> When building the production image you select a specific stage with `--target prod`. The `prod-builder`\n" +"> stage is an intermediate step and is never pushed to a registry.\n" +msgstr "" +"> [!TIP]\n" +"> Ao construir a imagem de produção, você seleciona um estágio específico com `--target prod`. O estágio `prod-builder`\n" +"> é um passo intermediário e nunca é enviado para um registry.\n" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "The `dev` target is selected when running `make up` or `make build`, while `make prod-build` targets `prod`." +msgstr "O alvo `dev` é selecionado ao executar `make up` ou `make build`, enquanto `make prod-build` usa o alvo `prod`." + +#. type: Title ## +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "make commands" +msgstr "Comandos make" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "The `Makefile` provides a convenient interface for all common Docker operations. Run `make` or `make help` to list available targets with their descriptions." +msgstr "O `Makefile` oferece uma interface prática para todas as operações Docker comuns. Execute `make` ou `make help` para listar os alvos disponíveis com suas descrições." + +#. type: Title ### +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "Development" +msgstr "Desenvolvimento" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "" +"| Command | Description |\n" +"|---------------|----------------------------------------------------------------|\n" +"| `make build` | Build (or rebuild) the development Docker image. |\n" +"| `make up` | Start the development environment in detached mode. |\n" +"| `make down` | Stop and remove containers, networks, and orphaned services. |\n" +"| `make stop` | Stop running containers without removing them. |\n" +"| `make clear` | Remove all development containers, networks, and volumes. |\n" +"| `make shell` | Open an interactive Bash shell inside the running `app` container. |\n" +msgstr "" +"| Comando | Descrição |\n" +"|---------------|----------------------------------------------------------------|\n" +"| `make build` | Faz o build (ou rebuild) da imagem Docker de desenvolvimento. |\n" +"| `make up` | Inicia o ambiente de desenvolvimento em modo detached. |\n" +"| `make down` | Para e remove containers, redes e serviços órfãos. |\n" +"| `make stop` | Para os containers em execução sem removê-los. |\n" +"| `make clear` | Remove todos os containers, redes e volumes de desenvolvimento. |\n" +"| `make shell` | Abre um shell Bash interativo dentro do container `app` em execução. |\n" + +#. type: Title ### +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "Running tools" +msgstr "Executando ferramentas" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +msgid "Commands in this group run inside the development container using `docker compose run --rm`, so they work even when the container is not currently running:" +msgstr "Os comandos deste grupo rodam dentro do container de desenvolvimento usando `docker compose run --rm`, então funcionam mesmo quando o container não está em execução:" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "" +"| Command | Description |\n" +"|--------------------------------------|-------------------------------------------------|\n" +"| `make yii ` | Run a `./yii` console command. |\n" +"| `make composer ` | Run Composer. |\n" +"| `make rector` | Run [Rector](https://getrector.com/) for automated PHP refactoring and code quality improvements. |\n" +"| `make cs-fix` | Run [PHP CS Fixer](https://cs.symfony.com/). |\n" +"| `make psalm` | Run [Psalm](https://psalm.dev/) static analysis. |\n" +"| `make composer-dependency-analyser` | Run [Composer Dependency Analyser](https://github.com/shipmonk-rnd/composer-dependency-analyser). |\n" +msgstr "" +"| Comando | Descrição |\n" +"|--------------------------------------|-------------------------------------------------|\n" +"| `make yii ` | Executa um comando de console `./yii`. |\n" +"| `make composer ` | Executa o Composer. |\n" +"| `make rector` | Executa o [Rector](https://getrector.com/) para refatoração automatizada de PHP e melhorias de qualidade de código. |\n" +"| `make cs-fix` | Executa o [PHP CS Fixer](https://cs.symfony.com/). |\n" +"| `make psalm` | Executa a análise estática do [Psalm](https://psalm.dev/). |\n" +"| `make composer-dependency-analyser` | Executa o [Composer Dependency Analyser](https://github.com/shipmonk-rnd/composer-dependency-analyser). |\n" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "" +"| Command | Description |\n" +"|------------------------|-----------------------------------------------------------|\n" +"| `make test` | Run the full test suite with Codeception. |\n" +"| `make test-coverage` | Run tests and generate an HTML coverage report. |\n" +"| `make codecept ` | Run any Codeception command with custom arguments. |\n" +msgstr "" +"| Comando | Descrição |\n" +"|------------------------|-----------------------------------------------------------|\n" +"| `make test` | Executa a suíte de testes completa com Codeception. |\n" +"| `make test-coverage` | Executa os testes e gera um relatório de cobertura em HTML. |\n" +"| `make codecept ` | Executa qualquer comando do Codeception com argumentos personalizados. |\n" + +#. type: Title ### +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "Production" +msgstr "Produção" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "" +"| Command | Description |\n" +"|----------------------|-------------------------------------------------------------------------------------|\n" +"| `make prod-build` | Build the production Docker image locally (`--target prod`). |\n" +"| `make prod-push` | Push the built image to the registry defined by `IMAGE` and `IMAGE_TAG`. |\n" +"| `make prod-deploy` | Deploy the stack to a remote Docker Swarm node defined by `PROD_SSH`. |\n" +msgstr "" +"| Comando | Descrição |\n" +"|----------------------|-------------------------------------------------------------------------------------|\n" +"| `make prod-build` | Faz o build local da imagem Docker de produção (`--target prod`). |\n" +"| `make prod-push` | Envia a imagem construída para o registry definido por `IMAGE` e `IMAGE_TAG`. |\n" +"| `make prod-deploy` | Faz o deploy da stack em um nó Docker Swarm remoto definido por `PROD_SSH`. |\n" + +#. type: Plain text +#: ../src/guide/tutorial/docker.md +#, no-wrap +msgid "" +"> [!TIP]\n" +"> Most commands accept additional arguments. For example, to install a specific package:\n" +"> ```sh\n" +"> make composer require yiisoft/yii-db-mysql\n" +"> ```\n" +"> To run a single test suite:\n" +"> ```sh\n" +"> make test -- Unit\n" +"> ```\n" +msgstr "" +"> [!TIP]\n" +"> A maioria dos comandos aceita argumentos adicionais. Por exemplo, para instalar um pacote específico:\n" +"> ```sh\n" +"> make composer require yiisoft/yii-db-mysql\n" +"> ```\n" +"> Para executar uma única suíte de testes:\n" +"> ```sh\n" +"> make test -- Unit\n" +"> ```\n" diff --git a/_translations/po/pt-BR/guide_tutorial_i18n.md.po b/_translations/po/pt-BR/guide_tutorial_i18n.md.po new file mode 100644 index 00000000..eb19ba66 --- /dev/null +++ b/_translations/po/pt-BR/guide_tutorial_i18n.md.po @@ -0,0 +1,917 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-06-02 22:29+0000\n" +"PO-Revision-Date: 2026-06-02 22:29+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Fenced code block (sh) +#: ../src/cookbook/using-yii-in-third-party-apps.md ../src/guide/structure/designing-packages.md ../src/guide/structure/module.md ../src/guide/structure/package.md ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "composer yii-config-rebuild\n" +msgstr "composer yii-config-rebuild\n" + +#. type: Title # +#: ../src/guide/intro/upgrade-from-v1.md ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "Internationalization" +msgstr "Internacionalização" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "Internationalization prepares an application for more than one locale. Localization is the locale-specific part: translated text, plural forms, date and number formats, and view templates for a locale such as `en-US` or `de`." +msgstr "A internacionalização prepara uma aplicação para mais de um locale. A localização é a parte específica de cada locale: textos traduzidos, formas de plural, formatos de data e número e templates de view para um locale como `en-US` ou `de`." + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "In a Yii application, the usual parts are:" +msgstr "Numa aplicação Yii, as partes habituais são:" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/i18n.md +msgid "locale selection for the current request;" +msgstr "a escolha do idioma da requisição atual;" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/i18n.md +msgid "translated application messages;" +msgstr "as mensagens traduzidas da aplicação;" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/i18n.md +msgid "plural and parameter formatting;" +msgstr "a formatação de plurais e parâmetros;" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/i18n.md +msgid "localized view templates for pages that need different markup." +msgstr "templates de view localizados para páginas que precisam de marcação diferente." + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "This tutorial assumes a new [yiisoft/app](https://github.com/yiisoft/app) project." +msgstr "Este tutorial parte de um projeto novo do [yiisoft/app](https://github.com/yiisoft/app)." + +#. type: Title ## +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "Install packages" +msgstr "Instalando os pacotes" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "`yiisoft/app` already includes `yiisoft/i18n` and `yiisoft/translator`. Install PHP-file message storage:" +msgstr "O `yiisoft/app` já inclui `yiisoft/i18n` e `yiisoft/translator`. Instale o armazenamento de mensagens em arquivos PHP:" + +#. type: Fenced code block (sh) +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "composer require yiisoft/translator-message-php\n" +msgstr "composer require yiisoft/translator-message-php\n" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "Install the extractor as a development dependency:" +msgstr "Instale o extrator como dependência de desenvolvimento:" + +#. type: Fenced code block (sh) +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "composer require --dev yiisoft/translator-extractor\n" +msgstr "composer require --dev yiisoft/translator-extractor\n" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "The examples use ICU message formatting for plural forms. Make sure the PHP `intl` extension is enabled. For simple placeholders only, use `Yiisoft\\Translator\\SimpleMessageFormatter` in the configuration below." +msgstr "Os exemplos usam a formatação de mensagens ICU para as formas de plural. Confira se a extensão `intl` do PHP está habilitada. Se você só precisa de placeholders simples, use `Yiisoft\\Translator\\SimpleMessageFormatter` na configuração abaixo." + +#. type: Title ## +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "Configure application locale" +msgstr "Configurando o idioma da aplicação" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "The application template keeps basic application settings in `config/common/application.php`. Set the source locale there:" +msgstr "O template da aplicação guarda as configurações básicas em `config/common/application.php`. Defina ali o idioma de origem:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "" +" 'UTF-8',\n" +" 'locale' => 'en-US',\n" +" 'name' => 'My Project',\n" +"];\n" +msgstr "" +" 'UTF-8',\n" +" 'locale' => 'en-US',\n" +" 'name' => 'My Project',\n" +"];\n" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "" +"The default layout uses this value in the `` attribute through `ApplicationParams`.\n" +"When your application chooses locale per request, set the selected locale on the view as shown in\n" +"[Choosing locale per request](#choosing-locale-per-request).\n" +msgstr "" +"O layout padrão usa esse valor no atributo `` por meio de `ApplicationParams`.\n" +"Quando a aplicação escolhe o idioma por requisição, defina o idioma escolhido na view, como mostrado em\n" +"[Escolhendo o idioma por requisição](#escolhendo-o-idioma-por-requisicao).\n" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "Configure translator defaults in `config/common/params.php`:" +msgstr "Configure os padrões do tradutor em `config/common/params.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "" +"'yiisoft/translator' => [\n" +" 'locale' => 'en-US',\n" +" 'fallbackLocale' => 'en-US',\n" +" 'defaultCategory' => 'app',\n" +"],\n" +msgstr "" +"'yiisoft/translator' => [\n" +" 'locale' => 'en-US',\n" +" 'fallbackLocale' => 'en-US',\n" +" 'defaultCategory' => 'app',\n" +"],\n" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "`locale` is the default translation locale. `fallbackLocale` is used when a translation is missing for the current locale. `defaultCategory` is the category used when a call to `translate()` does not specify one." +msgstr "`locale` é o idioma padrão das traduções. `fallbackLocale` é usado quando falta uma tradução para o idioma atual. `defaultCategory` é a categoria usada quando uma chamada a `translate()` não especifica nenhuma." + +#. type: Title ## +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "Configure message storage" +msgstr "Configurando o armazenamento de mensagens" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "Create `config/common/di/translator.php`:" +msgstr "Crie `config/common/di/translator.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "" +" [\n" +" 'definition' => static function (Aliases $aliases) use ($params): CategorySource {\n" +" $messageSource = new MessageSource($aliases->get('@root/messages'));\n" +"\n" +" return new CategorySource(\n" +" $params['yiisoft/translator']['defaultCategory'],\n" +" $messageSource,\n" +" new IntlMessageFormatter(),\n" +" $messageSource,\n" +" );\n" +" },\n" +" 'tags' => ['translation.categorySource'],\n" +" ],\n" +"];\n" +msgstr "" +" [\n" +" 'definition' => static function (Aliases $aliases) use ($params): CategorySource {\n" +" $messageSource = new MessageSource($aliases->get('@root/messages'));\n" +"\n" +" return new CategorySource(\n" +" $params['yiisoft/translator']['defaultCategory'],\n" +" $messageSource,\n" +" new IntlMessageFormatter(),\n" +" $messageSource,\n" +" );\n" +" },\n" +" 'tags' => ['translation.categorySource'],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "This registers the `app` category. The `MessageSource` reads PHP arrays from the `messages/` directory and writes extracted messages back to the same directory." +msgstr "Isso registra a categoria `app`. O `MessageSource` lê arrays PHP do diretório `messages/` e grava as mensagens extraídas de volta no mesmo diretório." + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "Create the source and target message files:" +msgstr "Crie os arquivos de mensagens de origem e de destino:" + +#. type: Fenced code block +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "" +"messages/\n" +"├── de/\n" +"│ └── app.php\n" +"└── en-US/\n" +" └── app.php\n" +msgstr "" +"messages/\n" +"├── de/\n" +"│ └── app.php\n" +"└── en-US/\n" +" └── app.php\n" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "`messages/en-US/app.php`:" +msgstr "`messages/en-US/app.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "" +" 'Home',\n" +" 'home.welcome' => 'Welcome to Yii3',\n" +" 'cart.items' => '{count, plural, =0{No items} one{# item} other{# items}}',\n" +"];\n" +msgstr "" +" 'Home',\n" +" 'home.welcome' => 'Welcome to Yii3',\n" +" 'cart.items' => '{count, plural, =0{No items} one{# item} other{# items}}',\n" +"];\n" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "`messages/de/app.php`:" +msgstr "`messages/de/app.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "" +" 'Home',\n" +" 'home.welcome' => 'Willkommen bei Yii3',\n" +" 'cart.items' => '{count, plural, =0{Keine Artikel} one{# Artikel} other{# Artikel}}',\n" +"];\n" +msgstr "" +" 'Home',\n" +" 'home.welcome' => 'Willkommen bei Yii3',\n" +" 'cart.items' => '{count, plural, =0{Keine Artikel} one{# Artikel} other{# Artikel}}',\n" +"];\n" + +#. type: Title ## +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "Translate messages" +msgstr "Traduzindo mensagens" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "Inject `Yiisoft\\Translator\\TranslatorInterface` where you prepare data for a response. For the default home page action, update `src/Web/HomePage/Action.php`:" +msgstr "Injete `Yiisoft\\Translator\\TranslatorInterface` onde você prepara os dados de uma resposta. Para a action padrão da página inicial, altere `src/Web/HomePage/Action.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "" +"viewRenderer->render(__DIR__ . '/template', [\n" +" 'itemCount' => 3,\n" +" 'translator' => $this->translator,\n" +" ]);\n" +" }\n" +"}\n" +msgstr "" +"viewRenderer->render(__DIR__ . '/template', [\n" +" 'itemCount' => 3,\n" +" 'translator' => $this->translator,\n" +" ]);\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "Use the translator in `src/Web/HomePage/template.php`:" +msgstr "Use o tradutor em `src/Web/HomePage/template.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "" +"setTitle($translator->translate('home.title'));\n" +"?>\n" +"\n" +"
\n" +"

translate('home.welcome')) ?>

\n" +"\n" +"

translate('cart.items', ['count' => $itemCount])) ?>

\n" +"
\n" +msgstr "" +"setTitle($translator->translate('home.title'));\n" +"?>\n" +"\n" +"
\n" +"

translate('home.welcome')) ?>

\n" +"\n" +"

translate('cart.items', ['count' => $itemCount])) ?>

\n" +"
\n" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "Escape translated text before output. Store trusted HTML separately or render it from a view template." +msgstr "Escape o texto traduzido antes de exibi-lo. Guarde HTML confiável separadamente ou renderize-o a partir de um template de view." + +#. type: Title ## +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "Choosing locale per request" +msgstr "Escolhendo o idioma por requisição " + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "For a web application, choose locale early in the middleware stack and apply it to both the translator and the view. The example below uses the `lang` query parameter and a fixed allow list:" +msgstr "Numa aplicação web, escolha o idioma cedo na pilha de middlewares e aplique-o tanto ao tradutor quanto à view. O exemplo abaixo usa o parâmetro `lang` da query string e uma lista fixa de idiomas permitidos:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "" +"getLocale($request);\n" +"\n" +" $this->translator->setLocale($locale);\n" +" $this->view->setLocale($locale);\n" +"\n" +" return $handler->handle($request);\n" +" }\n" +"\n" +" private function getLocale(ServerRequestInterface $request): string\n" +" {\n" +" $locale = $request->getQueryParams()['lang'] ?? null;\n" +"\n" +" return is_string($locale) && in_array($locale, self::SUPPORTED_LOCALES, true)\n" +" ? $locale\n" +" : self::DEFAULT_LOCALE;\n" +" }\n" +"}\n" +msgstr "" +"getLocale($request);\n" +"\n" +" $this->translator->setLocale($locale);\n" +" $this->view->setLocale($locale);\n" +"\n" +" return $handler->handle($request);\n" +" }\n" +"\n" +" private function getLocale(ServerRequestInterface $request): string\n" +" {\n" +" $locale = $request->getQueryParams()['lang'] ?? null;\n" +"\n" +" return is_string($locale) && in_array($locale, self::SUPPORTED_LOCALES, true)\n" +" ? $locale\n" +" : self::DEFAULT_LOCALE;\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "Register the middleware in `config/common/routes.php` or in the route group that needs localized output. Add middleware before the route action:" +msgstr "Registre o middleware em `config/common/routes.php` ou no grupo de rotas que precisa de saída localizada. Adicione o middleware antes da action da rota:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "" +"use App\\Web\\Middleware\\LocaleMiddleware;\n" +"use Yiisoft\\Router\\Route;\n" +"\n" +"return [\n" +" Route::get('/')\n" +" ->middleware(LocaleMiddleware::class)\n" +" ->action(App\\Web\\HomePage\\Action::class)\n" +" ->name('home'),\n" +"];\n" +msgstr "" +"use App\\Web\\Middleware\\LocaleMiddleware;\n" +"use Yiisoft\\Router\\Route;\n" +"\n" +"return [\n" +" Route::get('/')\n" +" ->middleware(LocaleMiddleware::class)\n" +" ->action(App\\Web\\HomePage\\Action::class)\n" +" ->name('home'),\n" +"];\n" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "Update `src/Web/Shared/Layout/Main/layout.php` to read the locale from the current view state:" +msgstr "Altere `src/Web/Shared/Layout/Main/layout.php` para ler o idioma do estado atual da view:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "getLocale()) ?>\">\n" +msgstr "getLocale()) ?>\">\n" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "Use the same approach when locale is stored in a session, a cookie, a user profile, or a route parameter." +msgstr "Use a mesma abordagem quando o idioma estiver guardado na sessão, num cookie, no perfil do usuário ou num parâmetro de rota." + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "`yiisoft/i18n` provides `Yiisoft\\I18n\\Locale` for working with BCP 47 locale codes:" +msgstr "O `yiisoft/i18n` oferece `Yiisoft\\I18n\\Locale` para trabalhar com códigos de locale BCP 47:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "" +"use Yiisoft\\I18n\\Locale;\n" +"\n" +"$locale = new Locale('de-DE');\n" +"\n" +"echo $locale->language(); // de\n" +"echo $locale->region(); // DE\n" +"echo $locale->fallbackLocale()->asString(); // de\n" +msgstr "" +"use Yiisoft\\I18n\\Locale;\n" +"\n" +"$locale = new Locale('de-DE');\n" +"\n" +"echo $locale->language(); // de\n" +"echo $locale->region(); // DE\n" +"echo $locale->fallbackLocale()->asString(); // de\n" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "This is useful when you need to derive a language fallback or inspect locale parts before choosing a supported locale." +msgstr "Isso é útil quando você precisa derivar um idioma de reserva ou inspecionar as partes do locale antes de escolher um idioma suportado." + +#. type: Title ## +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "Localized view files" +msgstr "Arquivos de view localizados" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "Use message translation for labels, headings, buttons, validation messages, and short paragraphs. Use localized view files when a page needs different markup or a different amount of text for each locale." +msgstr "Use tradução de mensagens para rótulos, títulos, botões, mensagens de validação e parágrafos curtos. Use arquivos de view localizados quando uma página precisa de marcação diferente ou de uma quantidade diferente de texto para cada idioma." + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "`yiisoft/view` looks for localized files in a locale subdirectory next to the original view file. For example, when `src/Web/HomePage/template.php` is rendered with locale `de-DE`, Yii checks:" +msgstr "O `yiisoft/view` procura arquivos localizados num subdiretório com o nome do locale, ao lado do arquivo de view original. Por exemplo, quando `src/Web/HomePage/template.php` é renderizado com o locale `de-DE`, o Yii verifica:" + +#. type: Bullet: '1. ' +#: ../src/guide/tutorial/i18n.md +msgid "`src/Web/HomePage/de-DE/template.php`" +msgstr "`src/Web/HomePage/de-DE/template.php`" + +#. type: Bullet: '2. ' +#: ../src/guide/tutorial/i18n.md +msgid "`src/Web/HomePage/de/template.php`" +msgstr "`src/Web/HomePage/de/template.php`" + +#. type: Bullet: '3. ' +#: ../src/guide/tutorial/i18n.md +msgid "`src/Web/HomePage/template.php`" +msgstr "`src/Web/HomePage/template.php`" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "The fallback to the two-letter language code is automatic." +msgstr "O fallback para o código de idioma de duas letras é automático." + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "You can set the locale for a single render call:" +msgstr "Você pode definir o idioma para uma única chamada de renderização:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "" +"return $this->viewRenderer\n" +" ->withLocale('de-DE')\n" +" ->render(__DIR__ . '/template');\n" +msgstr "" +"return $this->viewRenderer\n" +" ->withLocale('de-DE')\n" +" ->render(__DIR__ . '/template');\n" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "When the locale is set on `WebView` in middleware, the same locale is applied to views rendered by `WebViewRenderer`." +msgstr "Quando o idioma é definido no `WebView` dentro de um middleware, o mesmo idioma é aplicado às views renderizadas pelo `WebViewRenderer`." + +#. type: Title ## +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "Extract messages" +msgstr "Extraindo mensagens" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "Configure the extractor so it can read existing messages and write new IDs to the same message storage." +msgstr "Configure o extrator para que ele consiga ler as mensagens existentes e gravar novos IDs no mesmo armazenamento de mensagens." + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "Create `config/common/di/translator-extractor.php`:" +msgstr "Crie `config/common/di/translator-extractor.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "" +" [\n" +" '__construct()' => [\n" +" [\n" +" DynamicReference::to([\n" +" 'class' => ExtractorCategorySource::class,\n" +" '__construct()' => [\n" +" $params['yiisoft/translator']['defaultCategory'],\n" +" DynamicReference::to(\n" +" static fn (Aliases $aliases): MessageSource => new MessageSource($aliases->get('@root/messages')),\n" +" ),\n" +" DynamicReference::to(\n" +" static fn (Aliases $aliases): MessageSource => new MessageSource($aliases->get('@root/messages')),\n" +" ),\n" +" ],\n" +" ]),\n" +" ],\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +" [\n" +" '__construct()' => [\n" +" [\n" +" DynamicReference::to([\n" +" 'class' => ExtractorCategorySource::class,\n" +" '__construct()' => [\n" +" $params['yiisoft/translator']['defaultCategory'],\n" +" DynamicReference::to(\n" +" static fn (Aliases $aliases): MessageSource => new MessageSource($aliases->get('@root/messages')),\n" +" ),\n" +" DynamicReference::to(\n" +" static fn (Aliases $aliases): MessageSource => new MessageSource($aliases->get('@root/messages')),\n" +" ),\n" +" ],\n" +" ]),\n" +" ],\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "Rebuild config after adding the extractor configuration file:" +msgstr "Reconstrua a configuração depois de adicionar o arquivo de configuração do extrator:" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "Extract messages from application source files:" +msgstr "Extraia as mensagens dos arquivos-fonte da aplicação:" + +#. type: Fenced code block (sh) +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "./yii translator/extract src --languages=en-US,de\n" +msgstr "./yii translator/extract src --languages=en-US,de\n" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "The command scans calls such as:" +msgstr "O comando procura chamadas como:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "" +"$translator->translate('home.welcome');\n" +"$translator->translate('cart.items', ['count' => $itemCount]);\n" +msgstr "" +"$translator->translate('home.welcome');\n" +"$translator->translate('cart.items', ['count' => $itemCount]);\n" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "It writes missing IDs to:" +msgstr "Ele grava os IDs que faltam em:" + +#. type: Fenced code block +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "" +"messages/en-US/app.php\n" +"messages/de/app.php\n" +msgstr "" +"messages/en-US/app.php\n" +"messages/de/app.php\n" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "After extraction, edit target language files and replace source IDs with translated text." +msgstr "Depois da extração, edite os arquivos dos idiomas de destino e troque os IDs de origem pelo texto traduzido." + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "Use `--category` when a call belongs to another category:" +msgstr "Use `--category` quando uma chamada pertence a outra categoria:" + +#. type: Fenced code block (sh) +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "./yii translator/extract src --languages=en-US,de --category=shop\n" +msgstr "./yii translator/extract src --languages=en-US,de --category=shop\n" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "The extractor excludes `vendor/` by default. Use `--only` or `--except` when you need a narrower scan:" +msgstr "O extrator exclui `vendor/` por padrão. Use `--only` ou `--except` quando precisar de uma varredura mais restrita:" + +#. type: Fenced code block (sh) +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "./yii translator/extract src --languages=en-US,de --only=**/*.php --except=**/runtime/**\n" +msgstr "./yii translator/extract src --languages=en-US,de --only=**/*.php --except=**/runtime/**\n" + +#. type: Title ## +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "Working with categories" +msgstr "Trabalhando com categorias" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "The default `app` category is enough for most application messages. Add categories when a package or a large feature owns its own message files." +msgstr "A categoria padrão `app` basta para a maioria das mensagens da aplicação. Adicione categorias quando um pacote ou um recurso grande tem seus próprios arquivos de mensagens." + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "For a `shop` category, create another tagged category source:" +msgstr "Para uma categoria `shop`, crie outro category source com a tag:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "" +"'translation.shop' => [\n" +" 'definition' => static function (Aliases $aliases): CategorySource {\n" +" $messageSource = new MessageSource($aliases->get('@root/messages'));\n" +"\n" +" return new CategorySource(\n" +" 'shop',\n" +" $messageSource,\n" +" new IntlMessageFormatter(),\n" +" $messageSource,\n" +" );\n" +" },\n" +" 'tags' => ['translation.categorySource'],\n" +"],\n" +msgstr "" +"'translation.shop' => [\n" +" 'definition' => static function (Aliases $aliases): CategorySource {\n" +" $messageSource = new MessageSource($aliases->get('@root/messages'));\n" +"\n" +" return new CategorySource(\n" +" 'shop',\n" +" $messageSource,\n" +" new IntlMessageFormatter(),\n" +" $messageSource,\n" +" );\n" +" },\n" +" 'tags' => ['translation.categorySource'],\n" +"],\n" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "Translate with the category name:" +msgstr "Traduza informando o nome da categoria:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "$translator->translate('checkout.submit', category: 'shop');\n" +msgstr "$translator->translate('checkout.submit', category: 'shop');\n" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "The message files are stored as:" +msgstr "Os arquivos de mensagens ficam assim:" + +#. type: Fenced code block +#: ../src/guide/tutorial/i18n.md +#, no-wrap +msgid "" +"messages/de/shop.php\n" +"messages/en-US/shop.php\n" +msgstr "" +"messages/de/shop.php\n" +"messages/en-US/shop.php\n" + +#. type: Plain text +#: ../src/guide/tutorial/i18n.md +msgid "Keep message IDs stable. Changing an ID creates a new translation task for every locale." +msgstr "Mantenha os IDs de mensagens estáveis. Mudar um ID cria uma nova tarefa de tradução para cada idioma." diff --git a/_translations/po/pt-BR/guide_tutorial_mailing.md.po b/_translations/po/pt-BR/guide_tutorial_mailing.md.po new file mode 100644 index 00000000..ac5f6052 --- /dev/null +++ b/_translations/po/pt-BR/guide_tutorial_mailing.md.po @@ -0,0 +1,738 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-09-04 11:19+0500\n" +"PO-Revision-Date: 2025-09-04 11:19+0500\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: en/tutorial/mailing.md +#, no-wrap +msgid "Mailing" +msgstr "Envio de e-mails" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "Yii simplifies the composition and sending of email messages using the [yiisoft/mailer](https://github.com/yiisoft/mailer) package. This package provides content composition functionality and a basic interface for sending emails. By default, the package includes a file mailer that writes email contents into a file instead of sending them. This is particularly useful during the initial stages of application development." +msgstr "O Yii simplifica a composição e o envio de e-mails com o pacote [yiisoft/mailer](https://github.com/yiisoft/mailer). Esse pacote oferece a composição do conteúdo e uma interface básica para enviar e-mails. Por padrão, o pacote inclui um mailer de arquivo, que grava o conteúdo dos e-mails num arquivo em vez de enviá-los. Isso é especialmente útil nas fases iniciais do desenvolvimento da aplicação." + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "To send actual emails, you can use the [Symfony Mailer](https://github.com/yiisoft/mailer-symfony) implementation, which is used in the examples below." +msgstr "Para enviar e-mails de verdade, você pode usar a implementação com [Symfony Mailer](https://github.com/yiisoft/mailer-symfony), que é a usada nos exemplos abaixo." + +#. type: Title ## +#: en/tutorial/mailing.md +#, no-wrap +msgid "Configuring the Mailer" +msgstr "Configurando o mailer" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "The mailer service allows you to create a message instance, populate it with data, and send it. Typically, you get an instance from the DI container as `Yiisoft\\Mailer\\MailerInterface`." +msgstr "O serviço de mailer permite criar uma instância de mensagem, preenchê-la com dados e enviá-la. Normalmente, você obtém uma instância do container de DI como `Yiisoft\\Mailer\\MailerInterface`." + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "You can also create an instance manually as follows:" +msgstr "Você também pode criar uma instância manualmente:" + +#. type: Fenced code block (php) +#: en/tutorial/mailing.md +#, no-wrap +msgid "" +"\n" +"use Yiisoft\\Mailer\\Symfony\\Mailer;\n" +"\n" +"/**\n" +" * @var \\Symfony\\Component\\Mailer\\Transport\\TransportInterface $transport\n" +" */\n" +"\n" +"$mailer = new \\Yiisoft\\Mailer\\Symfony\\Mailer(\n" +" $transport,\n" +");\n" +msgstr "" +"\n" +"use Yiisoft\\Mailer\\Symfony\\Mailer;\n" +"\n" +"/**\n" +" * @var \\Symfony\\Component\\Mailer\\Transport\\TransportInterface $transport\n" +" */\n" +"\n" +"$mailer = new \\Yiisoft\\Mailer\\Symfony\\Mailer(\n" +" $transport,\n" +");\n" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "The `Yiisoft\\Mailer\\MailerInterface` provides two main methods:" +msgstr "A `Yiisoft\\Mailer\\MailerInterface` oferece dois métodos principais:" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`send()` - Sends the given email message." +msgstr "`send()` - Envia a mensagem de e-mail informada." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`sendMultiple()` - Sends many messages at once." +msgstr "`sendMultiple()` - Envia várias mensagens de uma vez." + +#. type: Title ## +#: en/tutorial/mailing.md +#, no-wrap +msgid "Creating a Message" +msgstr "Criando uma mensagem" + +#. type: Title ### +#: en/tutorial/mailing.md +#, no-wrap +msgid "Simple Text Message" +msgstr "Mensagem de texto simples" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "To create a simple message with a text body, use `Yiisoft\\Mailer\\Message`:" +msgstr "Para criar uma mensagem simples com corpo em texto, use `Yiisoft\\Mailer\\Message`:" + +#. type: Fenced code block (php) +#: en/tutorial/mailing.md +#, no-wrap +msgid "" +"$message = new \\Yiisoft\\Mailer\\Message(\n" +" from: 'from@domain.com',\n" +" to: 'to@domain.com',\n" +" subject: 'Message subject',\n" +" textBody: 'Plain text content'\n" +");\n" +msgstr "" +"$message = new \\Yiisoft\\Mailer\\Message(\n" +" from: 'from@domain.com',\n" +" to: 'to@domain.com',\n" +" subject: 'Message subject',\n" +" textBody: 'Plain text content'\n" +");\n" + +#. type: Title ### +#: en/tutorial/mailing.md +#, no-wrap +msgid "Simple HTML Message" +msgstr "Mensagem HTML simples" + +#. type: Fenced code block (php) +#: en/tutorial/mailing.md +#, no-wrap +msgid "" +"$message = new \\Yiisoft\\Mailer\\Message(\n" +" from: 'from@domain.com',\n" +" to: 'to@domain.com',\n" +" subject: 'Message subject',\n" +" htmlBody: 'HTML content'\n" +");\n" +msgstr "" +"$message = new \\Yiisoft\\Mailer\\Message(\n" +" from: 'from@domain.com',\n" +" to: 'to@domain.com',\n" +" subject: 'Message subject',\n" +" htmlBody: 'HTML content'\n" +");\n" + +#. type: Title ### +#: en/tutorial/mailing.md +#, no-wrap +msgid "HTML Message from template" +msgstr "Mensagem HTML a partir de um template" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "For this example, we will use package rendering package [view](https://github.com/yiisoft/view)." +msgstr "Neste exemplo, vamos usar o pacote de renderização [view](https://github.com/yiisoft/view)." + +#. type: Fenced code block (php) +#: en/tutorial/mailing.md +#, no-wrap +msgid "" +"/**\n" +" * @var \\Yiisoft\\View\\View $view\n" +" */\n" +"\n" +"$content = $view->render('path/to/view.php', [\n" +" 'name' => 'name',\n" +" 'code' => 'code',\n" +"]);\n" +"\n" +"$message = new \\Yiisoft\\Mailer\\Message(\n" +" from: 'from@domain.com',\n" +" to: 'to@domain.com',\n" +" subject: 'Subject',\n" +" htmlBody: $content\n" +");\n" +msgstr "" +"/**\n" +" * @var \\Yiisoft\\View\\View $view\n" +" */\n" +"\n" +"$content = $view->render('path/to/view.php', [\n" +" 'name' => 'name',\n" +" 'code' => 'code',\n" +"]);\n" +"\n" +"$message = new \\Yiisoft\\Mailer\\Message(\n" +" from: 'from@domain.com',\n" +" to: 'to@domain.com',\n" +" subject: 'Subject',\n" +" htmlBody: $content\n" +");\n" + +#. type: Title ### +#: en/tutorial/mailing.md +#, no-wrap +msgid "Using Layouts" +msgstr "Usando layouts" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "You can also pass parameters to layouts from your template message:" +msgstr "Você também pode passar parâmetros para os layouts a partir do template da mensagem:" + +#. type: Fenced code block (php) +#: en/tutorial/mailing.md +#, no-wrap +msgid "" +"/**\n" +" * @var \\Yiisoft\\View\\View $view\n" +" * @var array $layoutParameters\n" +" */\n" +"\n" +"$messageBody = $view->render('path/to/view.php', [\n" +" 'name' => 'name',\n" +" 'code' => 'code',\n" +"]);\n" +"\n" +"$layoutParameters['content'] = $messageBody;\n" +"\n" +"$content = $view->render('path/to/layout.php', $layoutParameters);\n" +"\n" +"$message = new \\Yiisoft\\Mailer\\Message(\n" +" from: 'from@domain.com',\n" +" to: 'to@domain.com',\n" +" subject: 'Subject',\n" +" htmlBody: $content\n" +");\n" +msgstr "" +"/**\n" +" * @var \\Yiisoft\\View\\View $view\n" +" * @var array $layoutParameters\n" +" */\n" +"\n" +"$messageBody = $view->render('path/to/view.php', [\n" +" 'name' => 'name',\n" +" 'code' => 'code',\n" +"]);\n" +"\n" +"$layoutParameters['content'] = $messageBody;\n" +"\n" +"$content = $view->render('path/to/layout.php', $layoutParameters);\n" +"\n" +"$message = new \\Yiisoft\\Mailer\\Message(\n" +" from: 'from@domain.com',\n" +" to: 'to@domain.com',\n" +" subject: 'Subject',\n" +" htmlBody: $content\n" +");\n" + +#. type: Title ### +#: en/tutorial/mailing.md +#, no-wrap +msgid "Layout Example" +msgstr "Exemplo de layout" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "You can wrap the view rendering result in a layout, similar to how layouts work in web applications. This is useful for setting up shared content like CSS styles:" +msgstr "Você pode envolver o resultado da renderização da view num layout, do mesmo jeito que os layouts funcionam em aplicações web. Isso é útil para definir conteúdo compartilhado, como estilos CSS:" + +#. type: Fenced code block (php) +#: en/tutorial/mailing.md +#, no-wrap +msgid "" +"\n" +"\n" +"\n" +"\n" +" \n" +"\n" +"\n" +"\n" +"\n" +"\n" +"
\n" +"--
\n" +"Mailed by Yii\n" +"
\n" +"\n" +"\n" +"\n" +msgstr "" +"\n" +"\n" +"\n" +"\n" +" \n" +"\n" +"\n" +"\n" +"\n" +"\n" +"
\n" +"--
\n" +"Mailed by Yii\n" +"
\n" +"\n" +"\n" +"\n" + +#. type: Title ## +#: en/tutorial/mailing.md +#, no-wrap +msgid "Adding More Data" +msgstr "Adicionando mais dados" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "The `Yiisoft\\Mailer\\MessageInterface` provides several methods to customize your message:" +msgstr "A `Yiisoft\\Mailer\\MessageInterface` oferece vários métodos para personalizar a mensagem:" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withCharset()` - Returns a new instance with the specified charset." +msgstr "`withCharset()` - Retorna uma nova instância com o charset informado." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withFrom()` - Returns a new instance with the specified sender email address." +msgstr "`withFrom()` - Retorna uma nova instância com o endereço de e-mail do remetente informado." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withTo()` - Returns a new instance with the specified recipient(s) email address." +msgstr "`withTo()` - Retorna uma nova instância com o(s) endereço(s) de e-mail do(s) destinatário(s) informado(s)." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withReplyTo()` - Returns a new instance with the specified reply-to address." +msgstr "`withReplyTo()` - Retorna uma nova instância com o endereço de resposta (reply-to) informado." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withCc()` - Returns a new instance with the specified Cc (extra copy receiver) addresses." +msgstr "`withCc()` - Retorna uma nova instância com os endereços em Cc (destinatários de cópia) informados." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withBcc()` - Returns a new instance with the specified Bcc (hidden copy receiver) addresses." +msgstr "`withBcc()` - Retorna uma nova instância com os endereços em Bcc (destinatários de cópia oculta) informados." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withSubject()` - Returns a new instance with the specified message subject." +msgstr "`withSubject()` - Retorna uma nova instância com o assunto da mensagem informado." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withDate()` - Returns a new instance with the specified date when the message was sent." +msgstr "`withDate()` - Retorna uma nova instância com a data de envio da mensagem informada." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withPriority()` - Returns a new instance with the specified priority of this message." +msgstr "`withPriority()` - Retorna uma nova instância com a prioridade da mensagem informada." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withReturnPath()` - Returns a new instance with the specified return-path (the bounce address) of this message." +msgstr "`withReturnPath()` - Retorna uma nova instância com o return-path (endereço de bounce) da mensagem informado." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withSender()` - Returns a new instance with the specified actual sender email address." +msgstr "`withSender()` - Retorna uma nova instância com o endereço de e-mail do remetente real informado." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withHtmlBody()` - Returns a new instance with the specified message HTML content." +msgstr "`withHtmlBody()` - Retorna uma nova instância com o conteúdo HTML da mensagem informado." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withTextBody()` - Returns a new instance with the specified message plain text content." +msgstr "`withTextBody()` - Retorna uma nova instância com o conteúdo em texto puro da mensagem informado." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withAddedHeader()` - Returns a new instance with the specified added custom header value." +msgstr "`withAddedHeader()` - Retorna uma nova instância com o valor de header personalizado adicionado." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withHeader()` - Returns a new instance with the specified custom header value." +msgstr "`withHeader()` - Retorna uma nova instância com o valor de header personalizado informado." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withHeaders()` - Returns a new instance with the specified custom header values." +msgstr "`withHeaders()` - Retorna uma nova instância com os valores de headers personalizados informados." + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "These methods are immutable, meaning they return a new instance of the message with the updated data." +msgstr "Esses métodos são imutáveis, ou seja, retornam uma nova instância da mensagem com os dados atualizados." + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "Note `with` prefix. It indicates that the method is immutable and returns a new instance of the class with the changed data." +msgstr "Repare no prefixo `with`. Ele indica que o método é imutável e retorna uma nova instância da classe com os dados alterados." + +#. type: Title ### +#: en/tutorial/mailing.md +#, no-wrap +msgid "Getters" +msgstr "Getters" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "The following getters are available to retrieve message data:" +msgstr "Os getters a seguir estão disponíveis para obter os dados da mensagem:" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getCharset()` - Returns the charset of this message." +msgstr "`getCharset()` - Retorna o charset da mensagem." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getFrom()` - Returns the message sender email address." +msgstr "`getFrom()` - Retorna o endereço de e-mail do remetente da mensagem." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getTo()` - Returns the message recipient(s) email address." +msgstr "`getTo()` - Retorna o(s) endereço(s) de e-mail do(s) destinatário(s) da mensagem." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getReplyTo()` - Returns the reply-to address of this message." +msgstr "`getReplyTo()` - Retorna o endereço de resposta (reply-to) da mensagem." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getCc()` - Returns the Cc (extra copy receiver) addresses of this message." +msgstr "`getCc()` - Retorna os endereços em Cc (destinatários de cópia) da mensagem." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getBcc()` - Returns the Bcc (hidden copy receiver) addresses of this message." +msgstr "`getBcc()` - Retorna os endereços em Bcc (destinatários de cópia oculta) da mensagem." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getSubject()` - Returns the message subject." +msgstr "`getSubject()` - Retorna o assunto da mensagem." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getDate()` - Returns the date when the message was sent, or null if it wasn't set." +msgstr "`getDate()` - Retorna a data de envio da mensagem, ou null se ela não foi definida." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getPriority()` - Returns the priority of this message." +msgstr "`getPriority()` - Retorna a prioridade da mensagem." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getReturnPath()` - Returns the return-path (the bounce address) of this message." +msgstr "`getReturnPath()` - Retorna o return-path (endereço de bounce) da mensagem." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getSender()` - Returns the message actual sender email address." +msgstr "`getSender()` - Retorna o endereço de e-mail do remetente real da mensagem." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getHtmlBody()` - Returns the message HTML body." +msgstr "`getHtmlBody()` - Retorna o corpo HTML da mensagem." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getTextBody()` - Returns the message text body." +msgstr "`getTextBody()` - Retorna o corpo em texto da mensagem." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getHeader()` - Returns all values for the specified header." +msgstr "`getHeader()` - Retorna todos os valores do header informado." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`__toString()` - Returns string representation of this message." +msgstr "`__toString()` - Retorna a representação em string da mensagem." + +#. type: Title ## +#: en/tutorial/mailing.md +#, no-wrap +msgid "Attaching Files" +msgstr "Anexando arquivos" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "You can attach files to your message using the `withAttached()` method:" +msgstr "Você pode anexar arquivos à mensagem com o método `withAttached()`:" + +#. type: Fenced code block (php) +#: en/tutorial/mailing.md +#, no-wrap +msgid "" +"use Yiisoft\\Mailer\\File;\n" +"\n" +"// Attach a file from the local file system\n" +"$message = $message->withAttached(\n" +" File::fromPath('/path/to/source/file.pdf'),\n" +");\n" +"\n" +"// Create an attachment on-the-fly\n" +"$message = $message->withAttached(\n" +" File::fromContent('Attachment content', 'attach.txt', 'text/plain'),\n" +");\n" +msgstr "" +"use Yiisoft\\Mailer\\File;\n" +"\n" +"// Anexa um arquivo do sistema de arquivos local\n" +"$message = $message->withAttached(\n" +" File::fromPath('/path/to/source/file.pdf'),\n" +");\n" +"\n" +"// Cria um anexo na hora\n" +"$message = $message->withAttached(\n" +" File::fromContent('Attachment content', 'attach.txt', 'text/plain'),\n" +");\n" + +#. type: Title ## +#: en/tutorial/mailing.md +#, no-wrap +msgid "Embedding Images" +msgstr "Incorporando imagens" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "You can embed images into the message content using the `withEmbedded()` method. This is particularly useful when composing messages with views:" +msgstr "Você pode incorporar imagens ao conteúdo da mensagem com o método `withEmbedded()`. Isso é especialmente útil ao compor mensagens com views:" + +#. type: Fenced code block (php) +#: en/tutorial/mailing.md +#, no-wrap +msgid "" +"$logo = 'path/to/logo';\n" +"$htmlBody = $this->view->render(\n" +" __DIR__ . 'template.php',\n" +" [\n" +" 'content' => $content,\n" +" 'logoCid' => $logo->cid(),\n" +" ],\n" +");\n" +"return new \\Yiisoft\\Mailer\\Message(\n" +" from: 'from@domain.com',\n" +" to: 'to@domain.com',\n" +" subject: 'Message subject',\n" +" htmlBody: $htmlBody,\n" +" embeddings: $logo\n" +" );\n" +msgstr "" +"$logo = 'path/to/logo';\n" +"$htmlBody = $this->view->render(\n" +" __DIR__ . 'template.php',\n" +" [\n" +" 'content' => $content,\n" +" 'logoCid' => $logo->cid(),\n" +" ],\n" +");\n" +"return new \\Yiisoft\\Mailer\\Message(\n" +" from: 'from@domain.com',\n" +" to: 'to@domain.com',\n" +" subject: 'Message subject',\n" +" htmlBody: $htmlBody,\n" +" embeddings: $logo\n" +" );\n" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "In your view or layout template, you can reference the embedded image using its CID:" +msgstr "No template da view ou do layout, você pode referenciar a imagem incorporada pelo seu CID:" + +#. type: Fenced code block (php) +#: en/tutorial/mailing.md +#, no-wrap +msgid "\">\n" +msgstr "\">\n" + +#. type: Title ## +#: en/tutorial/mailing.md +#, no-wrap +msgid "Sending a Message" +msgstr "Enviando uma mensagem" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "To send an email message:" +msgstr "Para enviar uma mensagem de e-mail:" + +#. type: Fenced code block (php) +#: en/tutorial/mailing.md +#, no-wrap +msgid "" +"/**\n" +" * @var \\Yiisoft\\View\\View $view\n" +" */\n" +"\n" +"$content = $view->render('path/to/view.php', [\n" +" 'name' => 'name',\n" +" 'code' => 'code',\n" +"]);\n" +"\n" +"$message = new \\Yiisoft\\Mailer\\Message(\n" +" from: 'from@domain.com',\n" +" to: 'to@domain.com',\n" +" subject: 'Subject',\n" +" htmlBody: $content\n" +");\n" +"\n" +"$mailer->send($message);\n" +msgstr "" +"/**\n" +" * @var \\Yiisoft\\View\\View $view\n" +" */\n" +"\n" +"$content = $view->render('path/to/view.php', [\n" +" 'name' => 'name',\n" +" 'code' => 'code',\n" +"]);\n" +"\n" +"$message = new \\Yiisoft\\Mailer\\Message(\n" +" from: 'from@domain.com',\n" +" to: 'to@domain.com',\n" +" subject: 'Subject',\n" +" htmlBody: $content\n" +");\n" +"\n" +"$mailer->send($message);\n" + +#. type: Title ## +#: en/tutorial/mailing.md +#, no-wrap +msgid "Sending Multiple Messages" +msgstr "Enviando várias mensagens" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "You can send multiple messages at once:" +msgstr "Você pode enviar várias mensagens de uma vez:" + +#. type: Fenced code block (php) +#: en/tutorial/mailing.md +#, no-wrap +msgid "" +"$messages = [];\n" +"\n" +"foreach ($users as $user) {\n" +" $messages[] = (new \\Yiisoft\\Mailer\\Message())\n" +" // ...\n" +" ->withTo($user->email);\n" +"}\n" +"\n" +"$result = $mailer->sendMultiple($messages);\n" +msgstr "" +"$messages = [];\n" +"\n" +"foreach ($users as $user) {\n" +" $messages[] = (new \\Yiisoft\\Mailer\\Message())\n" +" // ...\n" +" ->withTo($user->email);\n" +"}\n" +"\n" +"$result = $mailer->sendMultiple($messages);\n" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "The `sendMultiple()` method returns a `Yiisoft\\Mailer\\SendResults` object containing arrays of successfully sent and failed messages." +msgstr "O método `sendMultiple()` retorna um objeto `Yiisoft\\Mailer\\SendResults` com arrays das mensagens enviadas com sucesso e das que falharam." + +#. type: Title ## +#: en/tutorial/mailing.md +#, no-wrap +msgid "Implementing your own mail driver" +msgstr "Implementando seu próprio driver de e-mail" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "To create a custom mail solution, implement the `Yiisoft\\Mailer\\MailerInterface` and `Yiisoft\\Mailer\\MessageInterface` interfaces." +msgstr "Para criar uma solução de e-mail personalizada, implemente as interfaces `Yiisoft\\Mailer\\MailerInterface` e `Yiisoft\\Mailer\\MessageInterface`." + +#. type: Title ## +#: en/tutorial/mailing.md +#, no-wrap +msgid "For Development" +msgstr "Para desenvolvimento" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "For local or test development, you can use simplified implementations of the mailer that does not send emails. The package provides these implementations:" +msgstr "Em desenvolvimento local ou em testes, você pode usar implementações simplificadas do mailer que não enviam e-mails. O pacote oferece estas implementações:" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`Yiisoft\\Mailer\\StubMailer` - A simple mailer that stores messages in a local array." +msgstr "`Yiisoft\\Mailer\\StubMailer` - Um mailer simples que guarda as mensagens num array local." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`Yiisoft\\Mailer\\FileMailer` - A mock mailer that saves email messages as files instead of sending them." +msgstr "`Yiisoft\\Mailer\\FileMailer` - Um mailer de mentira que grava as mensagens de e-mail em arquivos em vez de enviá-las." + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`Yiisoft\\Mailer\\NullMailer` - A mailer that discards messages without sending or storing them." +msgstr "`Yiisoft\\Mailer\\NullMailer` - Um mailer que descarta as mensagens sem enviá-las nem guardá-las." + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "To use one of these mailers, configure it in your development environment file Example: `environments/local/di.php`" +msgstr "Para usar um desses mailers, configure-o no arquivo de ambiente de desenvolvimento. Exemplo: `environments/local/di.php`" + +#. type: Fenced code block (php) +#: en/tutorial/mailing.md +#, no-wrap +msgid "" +"return [\n" +" Yiisoft\\Mailer\\MailerInterface::class => Yiisoft\\Mailer\\StubMailer::class, //or any other\n" +"];\n" +"\n" +msgstr "" +"return [\n" +" Yiisoft\\Mailer\\MailerInterface::class => Yiisoft\\Mailer\\StubMailer::class, //ou qualquer outro\n" +"];\n" +"\n" diff --git a/_translations/po/pt-BR/guide_tutorial_performance-tuning.md.po b/_translations/po/pt-BR/guide_tutorial_performance-tuning.md.po new file mode 100644 index 00000000..7384aa06 --- /dev/null +++ b/_translations/po/pt-BR/guide_tutorial_performance-tuning.md.po @@ -0,0 +1,362 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-06-05 20:33+0000\n" +"PO-Revision-Date: 2026-06-05 20:33+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "Performance tuning" +msgstr "Ajuste de desempenho" + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "There are many factors affecting the performance of your application. Some are environmental, some are related to your code, while some others are related to Yii itself. In this section, we will count most of these factors and explain how you can improve your application performance by adjusting these factors." +msgstr "Muitos fatores afetam o desempenho da sua aplicação. Alguns são do ambiente, outros estão ligados ao seu código, e outros ao próprio Yii. Nesta seção, listamos a maioria desses fatores e explicamos como você pode melhorar o desempenho da aplicação ajustando cada um deles." + +#. type: Title ## +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "Optimizing your PHP Environment" +msgstr "Otimizando o ambiente PHP" + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "A well-configured PHP environment is important. To get maximum performance:" +msgstr "Um ambiente PHP bem configurado é importante. Para obter o máximo de desempenho:" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/performance-tuning.md +msgid "Use the latest stable PHP version. Major releases of PHP may bring significant performance improvements." +msgstr "Use a versão estável mais recente do PHP. Versões principais do PHP podem trazer ganhos de desempenho significativos." + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/performance-tuning.md +msgid "Enable bytecode caching with [Opcache](https://secure.php.net/opcache). Bytecode caching avoids the time spent on parsing and including PHP scripts for every incoming request." +msgstr "Ative o cache de bytecode com o [Opcache](https://secure.php.net/opcache). O cache de bytecode evita o tempo gasto para analisar e incluir os scripts PHP a cada requisição." + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/performance-tuning.md +msgid "[Tune `realpath()` cache](https://github.com/samdark/realpath_cache_tuner)." +msgstr "[Ajuste o cache do `realpath()`](https://github.com/samdark/realpath_cache_tuner)." + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/performance-tuning.md +msgid "Make sure [XDebug](https://xdebug.org/) isn't installed in the production environment." +msgstr "Garanta que o [XDebug](https://xdebug.org/) não esteja instalado no ambiente de produção." + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/performance-tuning.md +msgid "Try [PHP 7 preloading](https://wiki.php.net/rfc/preload)." +msgstr "Experimente o [preload do PHP 7](https://wiki.php.net/rfc/preload)." + +#. type: Title ## +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "Optimizing your code" +msgstr "Otimizando o seu código" + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "Beyond environment configuration, there are code-level optimizations that can improve your application's performance:" +msgstr "Além da configuração do ambiente, há otimizações no nível do código que podem melhorar o desempenho da aplicação:" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/performance-tuning.md +msgid "Look out for [algorithm complexity](https://en.wikipedia.org/wiki/Time_complexity). Especially give attention to `foreach` within `foreach` loops but look out for using [heavy PHP functions](https://stackoverflow.com/questions/2473989/list-of-big-o-for-php-functions) in loops as well." +msgstr "Fique atento à [complexidade dos algoritmos](https://en.wikipedia.org/wiki/Time_complexity). Preste atenção especial a loops `foreach` dentro de `foreach`, mas também ao uso de [funções PHP pesadas](https://stackoverflow.com/questions/2473989/list-of-big-o-for-php-functions) dentro de loops." + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/performance-tuning.md +msgid "[Speeding up array_merge()](https://www.exakat.io/speeding-up-array_merge/)" +msgstr "[Acelerando o array_merge()](https://www.exakat.io/speeding-up-array_merge/)" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/performance-tuning.md +msgid "[Move that foreach() inside the method](https://www.exakat.io/move-that-foreach-inside-the-method/)" +msgstr "[Mova aquele foreach() para dentro do método](https://www.exakat.io/move-that-foreach-inside-the-method/)" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/performance-tuning.md +msgid "[Array, classes and anonymous classes memory usage](https://www.exakat.io/array-classes-and-anonymous-memory-usage/)" +msgstr "[Uso de memória de arrays, classes e classes anônimas](https://www.exakat.io/array-classes-and-anonymous-memory-usage/)" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/performance-tuning.md +msgid "Use fully qualified function names with leading backslashes to optimize opcache performance. When calling [certain global functions](https://github.com/php/php-src/blob/944b6b6bbd6f05ad905f5f4ad07445792bee4027/Zend/zend_compile.c#L4291-L4353) from within a namespace, PHP first searches in the current namespace before falling back to the global namespace. Adding a leading backslash (e.g., `\\count()` instead of `count()`) tells PHP to directly use the global function, avoiding the namespace lookup and improving opcache efficiency. This optimization is best implemented automatically using tools like [PHP-CS-Fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer) with the `native_function_invocation` rule." +msgstr "Use nomes de funções totalmente qualificados, com barra invertida no início, para otimizar o desempenho do opcache. Ao chamar [certas funções globais](https://github.com/php/php-src/blob/944b6b6bbd6f05ad905f5f4ad07445792bee4027/Zend/zend_compile.c#L4291-L4353) de dentro de um namespace, o PHP primeiro procura no namespace atual antes de recorrer ao namespace global. Adicionar a barra invertida no início (por exemplo, `\\count()` em vez de `count()`) diz ao PHP para usar diretamente a função global, evitando a busca no namespace e melhorando a eficiência do opcache. O melhor é aplicar essa otimização automaticamente com ferramentas como o [PHP-CS-Fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer), usando a regra `native_function_invocation`." + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "The above optimizations would give you a significant performance boost only if the code in question is executed frequently. That is usually the case for big loops or batch processing." +msgstr "As otimizações acima só trazem um ganho de desempenho significativo se o código em questão for executado com frequência. Normalmente é o caso de loops grandes ou de processamento em lote." + +#. type: Title ## +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "Using caching techniques" +msgstr "Usando técnicas de cache" + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "You can use various caching techniques to significantly improve the performance of your application. For example, if your application allows users to enter text in Markdown format, you may consider caching the parsed Markdown content to avoid parsing the same Markdown text repeatedly in every request. Please refer to the [Caching](../caching/overview.md) section to learn about the caching support provided by Yii." +msgstr "Você pode usar várias técnicas de cache para melhorar bastante o desempenho da aplicação. Por exemplo, se a sua aplicação permite que os usuários digitem texto em Markdown, considere guardar em cache o conteúdo Markdown já processado, para não processar o mesmo texto repetidamente a cada requisição. Consulte a seção de [Cache](../caching/overview.md) para conhecer o suporte a cache oferecido pelo Yii." + +#. type: Title ## +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "Optimizing session storage" +msgstr "Otimizando o armazenamento de sessões" + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "" +"By default, session data is stored in files. The implementation is locking a file from opening a session to the point it's\n" +"closed either by `$session->close()` or at the end of request.\n" +"While the session file is locked, all other requests that are trying to use the same session are blocked. That's waiting for the\n" +"initial request to release a session file. This is fine for development and probably small projects. But when it comes \n" +"to handling massive concurrent requests, it's better to use more sophisticated storage, such as Redis.\n" +msgstr "" +"Por padrão, os dados de sessão são guardados em arquivos. A implementação trava o arquivo desde a abertura da sessão até o momento em que ela é\n" +"fechada, seja por `$session->close()` ou no fim da requisição.\n" +"Enquanto o arquivo de sessão está travado, todas as outras requisições que tentam usar a mesma sessão ficam bloqueadas, esperando a\n" +"requisição inicial liberar o arquivo de sessão. Isso serve para desenvolvimento e, provavelmente, para projetos pequenos. Mas quando se trata\n" +"de lidar com muitas requisições concorrentes, é melhor usar um armazenamento mais sofisticado, como o Redis.\n" + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "It could be done either by [configuring PHP via php.ini](https://www.digitalocean.com/community/tutorials/how-to-set-up-a-redis-server-as-a-session-handler-for-php-on-ubuntu-14-04) or [implementing SessionHandlerInterface](https://www.sitepoint.com/saving-php-sessions-in-redis/) and configuring session service as follows:" +msgstr "Isso pode ser feito [configurando o PHP via php.ini](https://www.digitalocean.com/community/tutorials/how-to-set-up-a-redis-server-as-a-session-handler-for-php-on-ubuntu-14-04) ou [implementando a SessionHandlerInterface](https://www.sitepoint.com/saving-php-sessions-in-redis/) e configurando o serviço de sessão assim:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "" +"\\Yiisoft\\Session\\SessionInterface::class => [\n" +" 'class' => \\Yiisoft\\Session\\Session::class,\n" +" '__construct()' => [[], $myCustomSessionHandler],\n" +"],\n" +msgstr "" +"\\Yiisoft\\Session\\SessionInterface::class => [\n" +" 'class' => \\Yiisoft\\Session\\Session::class,\n" +" '__construct()' => [[], $myCustomSessionHandler],\n" +"],\n" + +#. type: Title ## +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "Optimizing databases" +msgstr "Otimizando bancos de dados" + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "Executing DB queries and fetching data from databases are often the main performance bottleneck in a Web application. Although using [data caching](../caching/data.md) techniques may ease the performance hit, it doesn't fully solve the problem. When the database has enormous amounts of data and the cached data are invalid, fetching the latest data could be prohibitively expensive without a proper database and query design." +msgstr "Executar consultas e buscar dados no banco de dados costuma ser o principal gargalo de desempenho de uma aplicação web. Embora técnicas de [cache de dados](../caching/data.md) possam amenizar o impacto, elas não resolvem totalmente o problema. Quando o banco de dados tem uma quantidade enorme de dados e os dados em cache ficam inválidos, buscar os dados mais recentes pode ficar caro demais sem um bom projeto de banco de dados e de consultas." + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "A general technique to improve the performance of DB queries is to create indices for table columns that need to be filtered by. For example, if you need to look for a user record by `username`, you should create an index on `username`. Note that while indexing can make SELECT queries much faster, it will slow down INSERT, UPDATE and DELETE queries." +msgstr "Uma técnica geral para melhorar o desempenho das consultas é criar índices nas colunas das tabelas usadas em filtros. Por exemplo, se você precisa buscar o registro de um usuário pelo `username`, crie um índice em `username`. Note que, embora a indexação possa deixar as consultas SELECT muito mais rápidas, ela deixa as consultas INSERT, UPDATE e DELETE mais lentas." + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "For complex DB queries, it's recommended that you create database views to save the query parsing and preparation time." +msgstr "Para consultas complexas, é recomendável criar views no banco de dados para economizar o tempo de análise e preparação da consulta." + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "Last but not least, use `LIMIT` in your `SELECT` queries. This avoids fetching an overwhelming amount of data from the database and exhausting the memory allocated to PHP." +msgstr "Por último, mas não menos importante, use `LIMIT` nas suas consultas `SELECT`. Isso evita buscar uma quantidade excessiva de dados no banco e esgotar a memória alocada para o PHP." + +#. type: Title ## +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "Optimizing composer autoloader" +msgstr "Otimizando o autoloader do Composer" + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "Because Composer autoloader is used to include most third-party class files, you should consider optimizing it by executing the following command:" +msgstr "Como o autoloader do Composer é usado para incluir a maioria dos arquivos de classes de terceiros, considere otimizá-lo executando o seguinte comando:" + +#. type: Fenced code block +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "composer dumpautoload -o\n" +msgstr "composer dumpautoload -o\n" + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "Additionally, you may consider using [authoritative class maps](https://getcomposer.org/doc/articles/autoloader-optimization.md#optimization-level-2-a-authoritative-class-maps) and [APCu cache](https://getcomposer.org/doc/articles/autoloader-optimization.md#optimization-level-2-b-apcu-cache). Note that both optimizations may or may not be suitable for your particular case." +msgstr "Além disso, você pode considerar o uso de [class maps autoritativos](https://getcomposer.org/doc/articles/autoloader-optimization.md#optimization-level-2-a-authoritative-class-maps) e do [cache APCu](https://getcomposer.org/doc/articles/autoloader-optimization.md#optimization-level-2-b-apcu-cache). Note que essas duas otimizações podem ou não ser adequadas ao seu caso." + +#. type: Title ## +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "Processing data offline" +msgstr "Processando dados offline" + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "When a request involves some resource-intensive operations, you should think of ways to perform those operations in offline mode without having users wait for them to finish." +msgstr "Quando uma requisição envolve operações que consomem muitos recursos, pense em formas de executá-las em modo offline, sem fazer os usuários esperarem que terminem." + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "There are two methods to process data offline: pull and push." +msgstr "Há dois métodos para processar dados offline: pull e push." + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "In the pull method, whenever a request involves some complex operation, you create a task and save it in a persistent storage, such as a database. You then use a separate process (such as a cron job) to pull the tasks and process them. This method is straightforward to implement, but it has some drawbacks. For example, the task process needs to periodically pull from the task storage. If the pull frequency is too low, the tasks may be processed with great delay, but if the frequency is too high, it will introduce high overhead." +msgstr "No método pull, sempre que uma requisição envolve alguma operação complexa, você cria uma tarefa e a salva num armazenamento persistente, como um banco de dados. Depois, usa um processo separado (como um cron job) para buscar as tarefas e processá-las. Esse método é simples de implementar, mas tem algumas desvantagens. Por exemplo, o processo de tarefas precisa consultar periodicamente o armazenamento de tarefas. Se a frequência for baixa demais, as tarefas podem ser processadas com muito atraso; se for alta demais, gera muito overhead." + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "In the push method, you would use a message queue (e.g., RabbitMQ, ActiveMQ, Amazon SQS, etc.) to manage the tasks. Whenever a new task is put in the queue, it will initiate or notify the task handling process to trigger the task processing." +msgstr "No método push, você usa uma fila de mensagens (por exemplo, RabbitMQ, ActiveMQ, Amazon SQS etc.) para gerenciar as tarefas. Sempre que uma nova tarefa entra na fila, ela inicia ou notifica o processo responsável, que dispara o processamento da tarefa." + +#. type: Title ## +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "Using preloading" +msgstr "Usando preload" + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "As of PHP 7.4.0, PHP can be configured to preload scripts into the opcache when the engine starts. You can read more in the [documentation](https://www.php.net/manual/en/opcache.preloading.php) and the corresponding [RFC](https://wiki.php.net/rfc/preload)." +msgstr "A partir do PHP 7.4.0, o PHP pode ser configurado para pré-carregar scripts no opcache quando o engine inicia. Saiba mais na [documentação](https://www.php.net/manual/en/opcache.preloading.php) e na [RFC](https://wiki.php.net/rfc/preload) correspondente." + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "Note that the optimal tradeoff between performance and memory may vary with the application. \"Preload everything\" may be the easiest strategy, but not necessarily the best strategy." +msgstr "Note que o equilíbrio ideal entre desempenho e memória pode variar conforme a aplicação. \"Pré-carregar tudo\" pode ser a estratégia mais fácil, mas não necessariamente a melhor." + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "For example, we conducted a simple [yiisoft/app](https://github.com/yiisoft/app) application template benchmark. Without preloading and with preloading of the entire composer class map." +msgstr "Por exemplo, fizemos um benchmark simples do template de aplicação [yiisoft/app](https://github.com/yiisoft/app): sem preload e com preload de todo o class map do Composer." + +#. type: Title ### +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "Preloading benchmarks" +msgstr "Benchmarks de preload" + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "The application template benchmark includes configuring classes to injected dependencies in the bootstrap script." +msgstr "O benchmark do template de aplicação inclui a configuração das classes para as dependências injetadas no script de bootstrap." + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "For both variants, [ApacheBench](https://httpd.apache.org/docs/2.4/programs/ab.html) was used with the following run parameters:" +msgstr "Nas duas variantes, foi usado o [ApacheBench](https://httpd.apache.org/docs/2.4/programs/ab.html) com os seguintes parâmetros de execução:" + +#. type: Fenced code block (shell) +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "ab -n 1000 -c 10 -t 10\n" +msgstr "ab -n 1000 -c 10 -t 10\n" + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "Also, the debug mode was disabled. And an optimized autoloader of the [Composer](https://getcomposer.org) was used, and development dependencies weren't used:" +msgstr "Além disso, o modo debug estava desativado. Também foi usado um autoloader otimizado do [Composer](https://getcomposer.org), sem as dependências de desenvolvimento:" + +#. type: Fenced code block (shell) +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "composer install --optimize-autoloader --no-dev\n" +msgstr "composer install --optimize-autoloader --no-dev\n" + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "With preloading enabled, the entire composer class map (825 files) was used:" +msgstr "Com o preload ativado, foi usado todo o class map do Composer (825 arquivos):" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "" +"$files = require 'vendor/composer/autoload_classmap.php';\n" +"\n" +"foreach (array_unique($files) as $file) {\n" +" opcache_compile_file($file);\n" +"}\n" +msgstr "" +"$files = require 'vendor/composer/autoload_classmap.php';\n" +"\n" +"foreach (array_unique($files) as $file) {\n" +" opcache_compile_file($file);\n" +"}\n" + +#. type: Title #### +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "Test results" +msgstr "Resultados dos testes" + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "" +"| Benchmark | Preloaded files | Opcache memory used | Per request memory used | Time per request | Requests per second |\n" +"|--------------------|-----------------|---------------------|-------------------------|------------------|---------------------|\n" +"| Without preloading | 0 | 12.32 mb | 1.71 mb | 27.63 ms | 36.55 rq/s |\n" +"| With preloading | 825 | 17.86 mb | 1.82 mb | 26.21 ms | 38.42 rq/s |\n" +msgstr "" +"| Benchmark | Arquivos pré-carregados | Memória do Opcache usada | Memória usada por requisição | Tempo por requisição | Requisições por segundo |\n" +"|--------------------|-------------------------|--------------------------|------------------------------|----------------------|-------------------------|\n" +"| Sem preload | 0 | 12.32 mb | 1.71 mb | 27.63 ms | 36.55 rq/s |\n" +"| Com preload | 825 | 17.86 mb | 1.82 mb | 26.21 ms | 38.42 rq/s |\n" + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "As you can see, the test results aren't much different, since this is just a clean application template that contains a few classes. More discussion of preloading, including benchmarks, can be found in the [composer's issue](https://github.com/composer/composer/issues/7777)." +msgstr "Como você pode ver, os resultados não são muito diferentes, já que este é apenas um template de aplicação limpo, com poucas classes. Mais discussões sobre preload, incluindo benchmarks, estão na [issue do Composer](https://github.com/composer/composer/issues/7777)." + +#. type: Title ## +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "Performance profiling" +msgstr "Profiling de desempenho" + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "You should profile your code to find out the performance bottlenecks and take appropriate measures accordingly. The following profiling tools may be useful:" +msgstr "Faça o profiling do seu código para encontrar os gargalos de desempenho e tomar as medidas adequadas. As seguintes ferramentas de profiling podem ser úteis:" + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "\n" +msgstr "\n" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/performance-tuning.md +msgid "[Blackfire](https://blackfire.io/)" +msgstr "[Blackfire](https://blackfire.io/)" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/performance-tuning.md +msgid "[XHProf](https://secure.php.net/manual/en/book.xhprof.php)" +msgstr "[XHProf](https://secure.php.net/manual/en/book.xhprof.php)" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/performance-tuning.md +msgid "[XDebug profiler](https://xdebug.org/docs/profiler)" +msgstr "[Profiler do XDebug](https://xdebug.org/docs/profiler)" diff --git a/_translations/po/pt-BR/guide_tutorial_using-with-event-loop.md.po b/_translations/po/pt-BR/guide_tutorial_using-with-event-loop.md.po new file mode 100644 index 00000000..7ea76308 --- /dev/null +++ b/_translations/po/pt-BR/guide_tutorial_using-with-event-loop.md.po @@ -0,0 +1,158 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-10-07 15:22+0000\n" +"PO-Revision-Date: 2026-10-07 15:22+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/guide/tutorial/using-with-event-loop.md +#, no-wrap +msgid "Using Yii with event loop" +msgstr "Usando o Yii com event loop" + +#. type: Plain text +#: ../src/guide/tutorial/using-with-event-loop.md +#, no-wrap +msgid "" +"A normal PHP web request execution cycle consists of setting up an environment, getting a request, processing it to form a response\n" +"and sending the result. After the response is sent, execution is terminated and its context is lost. So, for the further \n" +" request, the whole sequence is repeated. Such an approach has a big advantage in ease of development since a developer doesn't\n" +"have to take much care about memory leaks or properly clean up context. On the other side, initializing everything for\n" +"every request takes time and overall consumes up to 50% of processing resources.\n" +msgstr "" +"O ciclo normal de execução de uma requisição web em PHP consiste em preparar o ambiente, receber a requisição, processá-la para gerar uma resposta\n" +"e enviar o resultado. Depois que a resposta é enviada, a execução termina e o contexto se perde. Então, na requisição\n" +" seguinte, toda a sequência se repete. Essa abordagem tem uma grande vantagem na facilidade de desenvolvimento, já que o desenvolvedor não\n" +"precisa se preocupar muito com vazamentos de memória nem com limpar o contexto corretamente. Por outro lado, inicializar tudo a\n" +"cada requisição leva tempo e, no total, consome até 50% dos recursos de processamento.\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-with-event-loop.md +msgid "There is an alternative way of running an application. Event loop. The idea is to initialize everything possible at once and then process a number of requests using it. Such an approach is usually called event loop." +msgstr "Existe outra forma de rodar uma aplicação: o event loop. A ideia é inicializar tudo o que for possível uma única vez e depois processar várias requisições usando esse contexto. Essa abordagem costuma ser chamada de event loop." + +#. type: Plain text +#: ../src/guide/tutorial/using-with-event-loop.md +msgid "There are multiple tools that could be used to achieve it. Notably, [FrankenPHP](https://frankenphp.dev/), [Rapira](https://rapira.rs/), [RoadRunner](https://roadrunner.dev/) and [Swoole](https://www.swoole.com/)." +msgstr "Há várias ferramentas que permitem fazer isso. As principais são [FrankenPHP](https://frankenphp.dev/), [Rapira](https://rapira.rs/), [RoadRunner](https://roadrunner.dev/) e [Swoole](https://www.swoole.com/)." + +#. type: Title ## +#: ../src/guide/tutorial/using-with-event-loop.md +#, no-wrap +msgid "Event loop implications" +msgstr "Implicações do event loop" + +#. type: Plain text +#: ../src/guide/tutorial/using-with-event-loop.md +msgid "Event loop worker basically looks like the following:" +msgstr "Um worker de event loop basicamente tem esta cara:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/using-with-event-loop.md +#, no-wrap +msgid "" +"initializeContext();\n" +"while ($request = getRequest()) {\n" +" $response = process($request);\n" +" emit($response);\n" +"}\n" +msgstr "" +"initializeContext();\n" +"while ($request = getRequest()) {\n" +" $response = process($request);\n" +" emit($response);\n" +"}\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-with-event-loop.md +msgid "Usually, there are multiple workers processing requests at the same time as with traditional php-fpm." +msgstr "Normalmente, há vários workers processando requisições ao mesmo tempo, como no php-fpm tradicional." + +#. type: Plain text +#: ../src/guide/tutorial/using-with-event-loop.md +msgid "That means that there's more to consider when developing applications." +msgstr "Isso significa que há mais coisas a considerar ao desenvolver aplicações." + +#. type: Title ### +#: ../src/guide/tutorial/using-with-event-loop.md +#, no-wrap +msgid "Processing is blocking" +msgstr "O processamento é bloqueante" + +#. type: Plain text +#: ../src/guide/tutorial/using-with-event-loop.md +msgid "Worker process requests one by one that's current processing is blocking processing next request. That means that long-running processes, same as in general PHP applications, should be put into a background via using a queue." +msgstr "O worker processa as requisições uma a uma, ou seja, o processamento atual bloqueia o processamento da próxima requisição. Isso significa que processos demorados, assim como em aplicações PHP comuns, devem ir para segundo plano usando uma fila." + +#. type: Title ### +#: ../src/guide/tutorial/using-with-event-loop.md +#, no-wrap +msgid "Services and state" +msgstr "Serviços e estado" + +#. type: Plain text +#: ../src/guide/tutorial/using-with-event-loop.md +msgid "Since the context in the event loop is shared between all request-responses processed by a single worker, all changes in the state of a service made by the previous request may affect the current request. Moreover, it can be a security problem if data from one user is available to another user." +msgstr "Como o contexto no event loop é compartilhado entre todas as requisições e respostas processadas por um mesmo worker, qualquer mudança no estado de um serviço feita pela requisição anterior pode afetar a requisição atual. Além disso, isso pode ser um problema de segurança se os dados de um usuário ficarem disponíveis para outro." + +#. type: Plain text +#: ../src/guide/tutorial/using-with-event-loop.md +msgid "There are two ways of dealing with it. First, you can avoid having state by making services stateless. PHP's `readonly` keyword may be handy for it. Second, you can reset the services' state at the end of the request processing. In this case, a state resetter will help you:" +msgstr "Há duas formas de lidar com isso. A primeira é evitar estado, tornando os serviços stateless. A palavra-chave `readonly` do PHP pode ajudar nisso. A segunda é redefinir o estado dos serviços ao fim do processamento da requisição. Nesse caso, um state resetter vai ajudar você:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/using-with-event-loop.md +#, no-wrap +msgid "" +"initializeContext();\n" +"$resetter = $container->get(\\Yiisoft\\Di\\StateResetter::class);\n" +"while ($request = getRequest()) {\n" +" $response = process($request);\n" +" emit($response);\n" +" $resetter->reset(); // We should reset the state of such services on every request.\n" +"}\n" +msgstr "" +"initializeContext();\n" +"$resetter = $container->get(\\Yiisoft\\Di\\StateResetter::class);\n" +"while ($request = getRequest()) {\n" +" $response = process($request);\n" +" emit($response);\n" +" $resetter->reset(); // Precisamos redefinir o estado desses serviços a cada requisição.\n" +"}\n" + +#. type: Title ## +#: ../src/guide/tutorial/using-with-event-loop.md +#, no-wrap +msgid "Integrations" +msgstr "Integrações" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/using-with-event-loop.md +msgid "[FrankenPHP](using-yii-with-frankenphp.md)" +msgstr "[FrankenPHP](using-yii-with-frankenphp.md)" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/using-with-event-loop.md +msgid "[Rapira](using-yii-with-rapira.md)" +msgstr "[Rapira](using-yii-with-rapira.md)" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/using-with-event-loop.md +msgid "[RoadRunner](using-yii-with-roadrunner.md)" +msgstr "[RoadRunner](using-yii-with-roadrunner.md)" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/using-with-event-loop.md +msgid "[Swoole](using-yii-with-swoole.md)" +msgstr "[Swoole](using-yii-with-swoole.md)" diff --git a/_translations/po/pt-BR/guide_tutorial_using-yii-with-frankenphp.md.po b/_translations/po/pt-BR/guide_tutorial_using-yii-with-frankenphp.md.po new file mode 100644 index 00000000..7459bd23 --- /dev/null +++ b/_translations/po/pt-BR/guide_tutorial_using-yii-with-frankenphp.md.po @@ -0,0 +1,438 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-10-07 15:22+0000\n" +"PO-Revision-Date: 2026-10-07 15:22+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/making-http-requests.md ../src/cookbook/sentry-integration.md ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md ../src/guide/tutorial/using-yii-with-frankenphp.md ../src/guide/tutorial/using-yii-with-rapira.md ../src/guide/tutorial/using-yii-with-roadrunner.md ../src/guide/tutorial/using-yii-with-swoole.md ../src/guide/views/asset.md ../src/guide/views/view.md ../src/guide/views/widget.md +#, no-wrap +msgid "Installation" +msgstr "Instalação" + +#. type: Title ## +#: ../src/cookbook/sentry-integration.md ../src/guide/concept/configuration.md ../src/guide/tutorial/using-yii-with-frankenphp.md ../src/guide/tutorial/using-yii-with-rapira.md ../src/guide/tutorial/using-yii-with-roadrunner.md ../src/guide/views/view-injections.md +#, no-wrap +msgid "Configuration" +msgstr "Configuração" + +#. type: Title # +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +#, no-wrap +msgid "Using Yii with FrankenPHP" +msgstr "Usando o Yii com FrankenPHP" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +#, no-wrap +msgid "" +"[FrankenPHP](https://frankenphp.dev/) is an application server for PHP with Caddy built in. It can run Yii in \n" +"[worker mode](using-with-event-loop.md), allowing the framework bootstrap to happen once per worker instead of\n" +"once per request.\n" +msgstr "" +"O [FrankenPHP](https://frankenphp.dev/) é um servidor de aplicação PHP com o Caddy embutido. Ele pode rodar o Yii em\n" +"[modo worker](using-with-event-loop.md), o que faz o bootstrap do framework acontecer uma vez por worker em vez de\n" +"uma vez por requisição.\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "The [FrankenPHP runner](https://github.com/yiisoft/yii-runner-frankenphp) requires PHP 8.1–8.5. Install FrankenPHP using its [installation instructions](https://frankenphp.dev/docs/), or use the Docker setup in the Yii application templates described below." +msgstr "O [runner para FrankenPHP](https://github.com/yiisoft/yii-runner-frankenphp) exige PHP 8.1–8.5. Instale o FrankenPHP seguindo as [instruções de instalação](https://frankenphp.dev/docs/) dele, ou use a configuração Docker dos templates de aplicação do Yii, descrita abaixo." + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "Install the runner package with Composer:" +msgstr "Instale o pacote do runner com o Composer:" + +#. type: Fenced code block (shell) +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +#, no-wrap +msgid "composer require yiisoft/yii-runner-frankenphp\n" +msgstr "composer require yiisoft/yii-runner-frankenphp\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "FrankenPHP works especially well in containerized deployments and is the runtime used by the Yii application templates Docker setup described in [Docker in application templates](docker.md)." +msgstr "O FrankenPHP funciona especialmente bem em deploys com containers e é o runtime usado pela configuração Docker dos templates de aplicação do Yii, descrita em [Docker nos templates de aplicação](docker.md)." + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +#, no-wrap +msgid "" +"> [!NOTE]\n" +"> This runner is for worker mode. To use FrankenPHP in classic mode, keep `public/index.php` and\n" +"> [yiisoft/yii-runner-http](https://github.com/yiisoft/yii-runner-http), the default HTTP runner in the templates.\n" +msgstr "" +"> [!NOTE]\n" +"> Este runner é para o modo worker. Para usar o FrankenPHP no modo clássico, mantenha o `public/index.php` e o\n" +"> [yiisoft/yii-runner-http](https://github.com/yiisoft/yii-runner-http), o runner HTTP padrão dos templates.\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "First, configure the worker entry script." +msgstr "Primeiro, configure o script de entrada do worker." + +#. type: Title ### +#: ../src/guide/tutorial/using-yii-with-frankenphp.md ../src/guide/tutorial/using-yii-with-rapira.md +#, no-wrap +msgid "Worker entry script" +msgstr "Script de entrada do worker" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "Create `/worker.php` in the project root:" +msgstr "Crie `/worker.php` na raiz do projeto:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +#, no-wrap +msgid "" +"setLevels([\n" +" LogLevel::EMERGENCY,\n" +" LogLevel::ERROR,\n" +" LogLevel::WARNING,\n" +" ]),\n" +" ],\n" +" ),\n" +" new PlainTextRenderer(),\n" +" ),\n" +");\n" +"$runner->run();\n" +msgstr "" +"setLevels([\n" +" LogLevel::EMERGENCY,\n" +" LogLevel::ERROR,\n" +" LogLevel::WARNING,\n" +" ]),\n" +" ],\n" +" ),\n" +" new PlainTextRenderer(),\n" +" ),\n" +");\n" +"$runner->run();\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "The runner bootstraps the application once and then keeps processing requests in worker mode. Unlike classic `public/index.php`, this script is not executed per request." +msgstr "O runner faz o bootstrap da aplicação uma vez e depois continua processando requisições em modo worker. Diferente do `public/index.php` clássico, este script não é executado a cada requisição." + +#. type: Title ### +#: ../src/guide/tutorial/using-yii-with-frankenphp.md ../src/guide/tutorial/using-yii-with-rapira.md +#, no-wrap +msgid "Server configuration" +msgstr "Configuração do servidor" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "FrankenPHP is configured through a `Caddyfile`. For production, it may look like the following:" +msgstr "O FrankenPHP é configurado por um `Caddyfile`. Em produção, ele pode ficar assim:" + +#. type: Fenced code block (caddyfile) +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +#, no-wrap +msgid "" +"{\n" +" skip_install_trust\n" +"\n" +" frankenphp {\n" +"\n" +" }\n" +"}\n" +"\n" +"{$SERVER_NAME::80} {\n" +" encode zstd br gzip\n" +" php_server {\n" +" root /app/public\n" +" worker {\n" +" match *\n" +" file /app/worker.php\n" +" }\n" +" }\n" +"}\n" +msgstr "" +"{\n" +" skip_install_trust\n" +"\n" +" frankenphp {\n" +"\n" +" }\n" +"}\n" +"\n" +"{$SERVER_NAME::80} {\n" +" encode zstd br gzip\n" +" php_server {\n" +" root /app/public\n" +" worker {\n" +" match *\n" +" file /app/worker.php\n" +" }\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "This configuration tells FrankenPHP to serve the `public` directory and handle all requests with `worker.php`. Static assets are still served from `public`, while PHP requests are processed through the long-running worker." +msgstr "Essa configuração diz ao FrankenPHP para servir o diretório `public` e atender todas as requisições com o `worker.php`. Os assets estáticos continuam sendo servidos de `public`, enquanto as requisições PHP são processadas pelo worker de longa duração." + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "For development, add `watch` so FrankenPHP reloads workers when PHP files change:" +msgstr "Em desenvolvimento, adicione `watch` para que o FrankenPHP recarregue os workers quando arquivos PHP mudarem:" + +#. type: Fenced code block (caddyfile) +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +#, no-wrap +msgid "" +"{\n" +" skip_install_trust\n" +"\n" +" frankenphp {\n" +"\n" +" }\n" +"}\n" +"\n" +"{$SERVER_NAME::80} {\n" +" encode zstd br gzip\n" +" php_server {\n" +" root /app/public\n" +" worker {\n" +" match *\n" +" file /app/worker.php\n" +" watch /app/**/*.php\n" +" }\n" +" }\n" +"}\n" +msgstr "" +"{\n" +" skip_install_trust\n" +"\n" +" frankenphp {\n" +"\n" +" }\n" +"}\n" +"\n" +"{$SERVER_NAME::80} {\n" +" encode zstd br gzip\n" +" php_server {\n" +" root /app/public\n" +" worker {\n" +" match *\n" +" file /app/worker.php\n" +" watch /app/**/*.php\n" +" }\n" +" }\n" +"}\n" + +#. type: Title ### +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +#, no-wrap +msgid "Docker setup in Yii application templates" +msgstr "Configuração Docker nos templates de aplicação do Yii" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "Yii application templates already ship with a FrankenPHP-based Docker setup. To switch the application to worker mode, update the files inside the Docker layout instead of relying on `public/index.php`." +msgstr "Os templates de aplicação do Yii já vêm com uma configuração Docker baseada no FrankenPHP. Para passar a aplicação para o modo worker, altere os arquivos da estrutura Docker em vez de depender do `public/index.php`." + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "Create `/worker.php` in the project root as shown above, then update the Caddy configuration used by the container. For development, edit `docker/dev/Caddyfile`:" +msgstr "Crie `/worker.php` na raiz do projeto como mostrado acima e depois altere a configuração do Caddy usada pelo container. Em desenvolvimento, edite `docker/dev/Caddyfile`:" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "For production, use the same configuration without `watch` in `docker/Caddyfile`:" +msgstr "Em produção, use a mesma configuração sem `watch` em `docker/Caddyfile`:" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "The templates use `dunglas/frankenphp` as the base image in `docker/Dockerfile`, mount the project into `/app` in development, and pass runtime configuration through environment files such as `docker/dev/.env` and `docker/prod/.env`. The default value of `SERVER_NAME` in these files is `:80`, which matches the examples above." +msgstr "Os templates usam `dunglas/frankenphp` como imagem base em `docker/Dockerfile`, montam o projeto em `/app` no desenvolvimento e passam a configuração de runtime por arquivos de ambiente como `docker/dev/.env` e `docker/prod/.env`. O valor padrão de `SERVER_NAME` nesses arquivos é `:80`, que corresponde aos exemplos acima." + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "After changing `worker.php` and the relevant `Caddyfile`, rebuild the image and restart the environment:" +msgstr "Depois de alterar o `worker.php` e o `Caddyfile` correspondente, reconstrua a imagem e reinicie o ambiente:" + +#. type: Fenced code block (shell) +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +#, no-wrap +msgid "" +"make build\n" +"make up\n" +msgstr "" +"make build\n" +"make up\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "In production, rebuild and deploy the production image using the project's production Docker workflow." +msgstr "Em produção, reconstrua a imagem de produção e faça o deploy usando o fluxo Docker de produção do projeto." + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "If you switch fully to worker mode, `public/index.php` and `yiisoft/yii-runner-http` are no longer needed." +msgstr "Se você passar totalmente para o modo worker, o `public/index.php` e o `yiisoft/yii-runner-http` deixam de ser necessários." + +#. type: Title ## +#: ../src/guide/tutorial/using-yii-with-frankenphp.md ../src/guide/tutorial/using-yii-with-rapira.md ../src/guide/tutorial/using-yii-with-roadrunner.md ../src/guide/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "Starting a server" +msgstr "Iniciando o servidor" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "The exact start command depends on how you run FrankenPHP:" +msgstr "O comando exato para iniciar depende de como você roda o FrankenPHP:" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "In the Yii application templates, run `make build` and `make up` after updating `worker.php` and the relevant `Caddyfile`." +msgstr "Nos templates de aplicação do Yii, execute `make build` e `make up` depois de alterar o `worker.php` e o `Caddyfile` correspondente." + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "With the standalone binary, run the following command from the directory containing your `Caddyfile`:" +msgstr "Com o binário standalone, execute o seguinte comando no diretório que contém o seu `Caddyfile`:" + +#. type: Fenced code block (shell) +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +#, no-wrap +msgid "frankenphp run --config Caddyfile\n" +msgstr "frankenphp run --config Caddyfile\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "The example configuration uses `/app` as the application root. Adjust `/app/public`, `/app/worker.php`, and the watch path to match your installation. See the [FrankenPHP configuration reference](https://frankenphp.dev/docs/config/) for other deployment options." +msgstr "A configuração de exemplo usa `/app` como raiz da aplicação. Ajuste `/app/public`, `/app/worker.php` e o caminho do watch conforme a sua instalação. Veja a [referência de configuração do FrankenPHP](https://frankenphp.dev/docs/config/) para outras opções de deploy." + +#. type: Title ## +#: ../src/guide/tutorial/using-yii-with-frankenphp.md ../src/guide/tutorial/using-yii-with-rapira.md ../src/guide/tutorial/using-yii-with-roadrunner.md +#, no-wrap +msgid "On worker scope" +msgstr "Sobre o escopo do worker" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "Each worker's memory is isolated from other workers." +msgstr "A memória de cada worker é isolada da dos outros workers." + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "A single worker handles multiple requests, so services created inside it may keep state between requests." +msgstr "Um único worker atende várias requisições, então os serviços criados dentro dele podem manter estado entre requisições." + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "At each iteration of the event loop, every stateful service should be reset." +msgstr "A cada iteração do event loop, todo serviço com estado deve ser redefinido." + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "For the general implications of long-running workers, see [Using Yii with event loop](using-with-event-loop.md)." +msgstr "Para as implicações gerais de workers de longa duração, veja [Usando o Yii com event loop](using-with-event-loop.md)." + +#. type: Title ## +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +#, no-wrap +msgid "Worker mode notes" +msgstr "Notas sobre o modo worker" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "Use the `MAX_REQUESTS` environment variable to limit how many requests a worker handles before restart." +msgstr "Use a variável de ambiente `MAX_REQUESTS` para limitar quantas requisições um worker atende antes de ser reiniciado." + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "The runner calls `Yiisoft\\Di\\StateResetter::reset()` after each request. Register resetters for your stateful services as described in the [Yii DI documentation](https://github.com/yiisoft/di#resetting-services-state)." +msgstr "O runner chama `Yiisoft\\Di\\StateResetter::reset()` depois de cada requisição. Registre resetters para os seus serviços com estado, como descrito na [documentação do Yii DI](https://github.com/yiisoft/di#resetting-services-state)." + +#. type: Title ## +#: ../src/guide/tutorial/using-yii-with-frankenphp.md ../src/guide/tutorial/using-yii-with-rapira.md +#, no-wrap +msgid "Additional configuration" +msgstr "Configuração adicional" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "`FrankenPHPApplicationRunner` is configured by default for Yii application templates and follows the [dependency container configuration](../concept/configuration.md#container-configuration) concept." +msgstr "O `FrankenPHPApplicationRunner` vem configurado por padrão para os templates de aplicação do Yii e segue o conceito de [configuração do container de dependências](../concept/configuration.md#configuracao-do-container)." + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-frankenphp.md +msgid "The constructor allows overriding the default bootstrap, events, DI, params, and error-handler configuration. You can also provide a custom config instance with `withConfig()` and a custom container with `withContainer()`." +msgstr "O construtor permite sobrescrever a configuração padrão de bootstrap, eventos, DI, params e tratamento de erros. Você também pode fornecer uma instância de configuração personalizada com `withConfig()` e um container personalizado com `withContainer()`." diff --git a/_translations/po/pt-BR/guide_tutorial_using-yii-with-rapira.md.po b/_translations/po/pt-BR/guide_tutorial_using-yii-with-rapira.md.po new file mode 100644 index 00000000..0805ae6c --- /dev/null +++ b/_translations/po/pt-BR/guide_tutorial_using-yii-with-rapira.md.po @@ -0,0 +1,282 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-10-07 20:23+0000\n" +"PO-Revision-Date: 2026-10-07 20:23+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/making-http-requests.md ../src/cookbook/sentry-integration.md ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md ../src/guide/tutorial/using-yii-with-frankenphp.md ../src/guide/tutorial/using-yii-with-rapira.md ../src/guide/tutorial/using-yii-with-roadrunner.md ../src/guide/tutorial/using-yii-with-swoole.md ../src/guide/views/asset.md ../src/guide/views/view.md ../src/guide/views/widget.md +#, no-wrap +msgid "Installation" +msgstr "Instalação" + +#. type: Title ## +#: ../src/cookbook/sentry-integration.md ../src/guide/concept/configuration.md ../src/guide/tutorial/using-yii-with-frankenphp.md ../src/guide/tutorial/using-yii-with-rapira.md ../src/guide/tutorial/using-yii-with-roadrunner.md ../src/guide/views/view-injections.md +#, no-wrap +msgid "Configuration" +msgstr "Configuração" + +#. type: Title ### +#: ../src/guide/tutorial/using-yii-with-frankenphp.md ../src/guide/tutorial/using-yii-with-rapira.md +#, no-wrap +msgid "Worker entry script" +msgstr "Script de entrada do worker" + +#. type: Title ### +#: ../src/guide/tutorial/using-yii-with-frankenphp.md ../src/guide/tutorial/using-yii-with-rapira.md +#, no-wrap +msgid "Server configuration" +msgstr "Configuração do servidor" + +#. type: Title ## +#: ../src/guide/tutorial/using-yii-with-frankenphp.md ../src/guide/tutorial/using-yii-with-rapira.md ../src/guide/tutorial/using-yii-with-roadrunner.md ../src/guide/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "Starting a server" +msgstr "Iniciando o servidor" + +#. type: Title ## +#: ../src/guide/tutorial/using-yii-with-frankenphp.md ../src/guide/tutorial/using-yii-with-rapira.md ../src/guide/tutorial/using-yii-with-roadrunner.md +#, no-wrap +msgid "On worker scope" +msgstr "Sobre o escopo do worker" + +#. type: Title ## +#: ../src/guide/tutorial/using-yii-with-frankenphp.md ../src/guide/tutorial/using-yii-with-rapira.md +#, no-wrap +msgid "Additional configuration" +msgstr "Configuração adicional" + +#. type: Title # +#: ../src/guide/tutorial/using-yii-with-rapira.md +#, no-wrap +msgid "Using Yii with Rapira" +msgstr "Usando o Yii com Rapira" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-rapira.md +#, no-wrap +msgid "" +"[Rapira](https://rapira.rs/) is a PHP application server written in Rust that embeds the PHP interpreter.\n" +"The [Yii Rapira runner](https://github.com/yiisoft/yii-runner-rapira) supports its classic, worker, and dispatcher modes.\n" +"Worker and dispatcher modes initialize the application once per worker and reuse it for subsequent requests.\n" +"See [Using Yii with event loop](using-with-event-loop.md) for the implications of keeping the application in memory.\n" +msgstr "" +"O [Rapira](https://rapira.rs/) é um servidor de aplicação PHP escrito em Rust que embute o interpretador PHP.\n" +"O [runner do Yii para Rapira](https://github.com/yiisoft/yii-runner-rapira) suporta os modos classic, worker e dispatcher.\n" +"Os modos worker e dispatcher inicializam a aplicação uma vez por worker e a reaproveitam nas requisições seguintes.\n" +"Veja [Usando o Yii com event loop](using-with-event-loop.md) para as implicações de manter a aplicação na memória.\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-rapira.md +msgid "The runner requires PHP 8.4–8.5. Install the Rapira binary following the [Rapira installation instructions](https://rapira.rs/docs/intro/installation), using a PHP version supported by the runner. The Composer packages provide the Yii integration; the server binary must be installed separately." +msgstr "O runner exige PHP 8.4–8.5. Instale o binário do Rapira seguindo as [instruções de instalação do Rapira](https://rapira.rs/docs/intro/installation), com uma versão do PHP suportada pelo runner. Os pacotes do Composer fornecem a integração com o Yii; o binário do servidor precisa ser instalado à parte." + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-rapira.md +msgid "Install the runner and its contract package in your Yii application:" +msgstr "Instale o runner e o pacote de contratos dele na sua aplicação Yii:" + +#. type: Fenced code block (shell) +#: ../src/guide/tutorial/using-yii-with-rapira.md +#, no-wrap +msgid "composer require yiisoft/yii-runner-rapira:@dev rapira/contract:@dev\n" +msgstr "composer require yiisoft/yii-runner-rapira:@dev rapira/contract:@dev\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-rapira.md +msgid "These stability flags allow the development versions used by the runner's installation instructions." +msgstr "Essas flags de estabilidade permitem as versões de desenvolvimento usadas nas instruções de instalação do runner." + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-rapira.md +msgid "The following example assumes an application based on `yiisoft/app` or `yiisoft/app-api`, with `App\\Environment` and `src/bootstrap.php` provided by the template." +msgstr "O exemplo a seguir supõe uma aplicação baseada em `yiisoft/app` ou `yiisoft/app-api`, com `App\\Environment` e `src/bootstrap.php` fornecidos pelo template." + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-rapira.md +msgid "Create `worker.php` in the application root:" +msgstr "Crie `worker.php` na raiz da aplicação:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/using-yii-with-rapira.md +#, no-wrap +msgid "" +"setLevels([\n" +" LogLevel::EMERGENCY,\n" +" LogLevel::ERROR,\n" +" LogLevel::WARNING,\n" +" ]),\n" +" ],\n" +" ),\n" +" new PlainTextRenderer(),\n" +" ),\n" +");\n" +"$runner->run();\n" +msgstr "" +"setLevels([\n" +" LogLevel::EMERGENCY,\n" +" LogLevel::ERROR,\n" +" LogLevel::WARNING,\n" +" ]),\n" +" ],\n" +" ),\n" +" new PlainTextRenderer(),\n" +" ),\n" +");\n" +"$runner->run();\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-rapira.md +msgid "The runner creates the container, starts the application, converts incoming requests to PSR-7 requests, and emits responses. It detects the Rapira execution mode, so the same entry script can be used with all three modes." +msgstr "O runner cria o container, inicia a aplicação, converte as requisições recebidas em requisições PSR-7 e emite as respostas. Ele detecta o modo de execução do Rapira, então o mesmo script de entrada serve para os três modos." + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-rapira.md +msgid "Create `rapira.toml` next to `worker.php`:" +msgstr "Crie `rapira.toml` ao lado de `worker.php`:" + +#. type: Fenced code block (toml) +#: ../src/guide/tutorial/using-yii-with-rapira.md +#, no-wrap +msgid "" +"[http]\n" +"listen = \"127.0.0.1:8000\"\n" +"\n" +"[http.pool]\n" +"entrypoint = \"worker.php\"\n" +"mode = \"worker\"\n" +"max_requests = 1000\n" +msgstr "" +"[http]\n" +"listen = \"127.0.0.1:8000\"\n" +"\n" +"[http.pool]\n" +"entrypoint = \"worker.php\"\n" +"mode = \"worker\"\n" +"max_requests = 1000\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-rapira.md +msgid "This configuration listens on the loopback interface and recycles each worker after 1,000 requests. For serving files from `public`, follow Rapira's [static file configuration](https://rapira.rs/docs/static-files). See the [configuration reference](https://rapira.rs/docs/configuration) for the other server and pool settings." +msgstr "Essa configuração escuta na interface de loopback e recicla cada worker depois de 1.000 requisições. Para servir arquivos de `public`, siga a [configuração de arquivos estáticos](https://rapira.rs/docs/static-files) do Rapira. Veja a [referência de configuração](https://rapira.rs/docs/configuration) para as outras opções do servidor e do pool." + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-rapira.md +msgid "Run the following command from the application root:" +msgstr "Execute o seguinte comando na raiz da aplicação:" + +#. type: Fenced code block (shell) +#: ../src/guide/tutorial/using-yii-with-rapira.md +#, no-wrap +msgid "rapira serve rapira.toml\n" +msgstr "rapira serve rapira.toml\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-rapira.md +msgid "Open `http://127.0.0.1:8000` to access the application. Restart the server after changing application code or configuration." +msgstr "Abra `http://127.0.0.1:8000` para acessar a aplicação. Reinicie o servidor depois de alterar o código ou a configuração da aplicação." + +#. type: Title ## +#: ../src/guide/tutorial/using-yii-with-rapira.md +#, no-wrap +msgid "Execution modes" +msgstr "Modos de execução" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-rapira.md +msgid "Set `mode` in the `[http.pool]` section of `rapira.toml` to choose how requests are processed:" +msgstr "Defina `mode` na seção `[http.pool]` do `rapira.toml` para escolher como as requisições são processadas:" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/using-yii-with-rapira.md +msgid "`classic` initializes the application for each request, similarly to PHP-FPM." +msgstr "`classic` inicializa a aplicação a cada requisição, como no PHP-FPM." + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/using-yii-with-rapira.md +msgid "`worker` keeps the application in memory and receives requests through PHP's SAPI superglobals." +msgstr "`worker` mantém a aplicação na memória e recebe as requisições pelas superglobais da SAPI do PHP." + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/using-yii-with-rapira.md +msgid "`dispatcher` keeps the application in memory and receives request objects through Rapira's dispatcher API. The Yii runner processes these requests sequentially within each worker." +msgstr "`dispatcher` mantém a aplicação na memória e recebe objetos de requisição pela API de dispatcher do Rapira. O runner do Yii processa essas requisições sequencialmente dentro de cada worker." + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-rapira.md +msgid "See [Rapira execution modes](https://rapira.rs/docs/execution-modes) for details." +msgstr "Veja [os modos de execução do Rapira](https://rapira.rs/docs/execution-modes) para mais detalhes." + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-rapira.md +msgid "In worker and dispatcher modes, services may retain state between requests. The runner calls `Yiisoft\\Di\\StateResetter::reset()` after each request, but you must configure resetters for your own stateful services. See the [Yii DI documentation](https://github.com/yiisoft/di#resetting-services-state)." +msgstr "Nos modos worker e dispatcher, os serviços podem manter estado entre requisições. O runner chama `Yiisoft\\Di\\StateResetter::reset()` depois de cada requisição, mas você precisa configurar resetters para os seus próprios serviços com estado. Veja a [documentação do Yii DI](https://github.com/yiisoft/di#resetting-services-state)." + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-rapira.md +msgid "The `max_requests` setting limits how long a worker lives; it does not replace resetting request-specific state." +msgstr "A opção `max_requests` limita quanto tempo um worker vive; ela não substitui a redefinição do estado específico de cada requisição." + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-rapira.md +msgid "`RapiraApplicationRunner` uses the application templates' web configuration groups by default. Its constructor accepts alternative groups, configuration directories, and a temporary error handler. Use `withConfig()` to supply a custom configuration instance or `withContainer()` to supply a PSR-11 container. See the [runner documentation](https://github.com/yiisoft/yii-runner-rapira#configuration) for examples." +msgstr "O `RapiraApplicationRunner` usa por padrão os grupos de configuração web dos templates de aplicação. O construtor aceita grupos alternativos, diretórios de configuração e um error handler temporário. Use `withConfig()` para fornecer uma instância de configuração personalizada ou `withContainer()` para fornecer um container PSR-11. Veja a [documentação do runner](https://github.com/yiisoft/yii-runner-rapira#configuration) para exemplos." diff --git a/_translations/po/pt-BR/guide_tutorial_using-yii-with-roadrunner.md.po b/_translations/po/pt-BR/guide_tutorial_using-yii-with-roadrunner.md.po new file mode 100644 index 00000000..0f4e3dd0 --- /dev/null +++ b/_translations/po/pt-BR/guide_tutorial_using-yii-with-roadrunner.md.po @@ -0,0 +1,384 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-09-25 14:35+0000\n" +"PO-Revision-Date: 2026-09-25 14:35+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/making-http-requests.md ../src/cookbook/sentry-integration.md ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md ../src/guide/tutorial/using-yii-with-frankenphp.md ../src/guide/tutorial/using-yii-with-roadrunner.md ../src/guide/tutorial/using-yii-with-swoole.md ../src/guide/views/asset.md ../src/guide/views/view.md ../src/guide/views/widget.md +#, no-wrap +msgid "Installation" +msgstr "Instalação" + +#. type: Title ## +#: ../src/cookbook/sentry-integration.md ../src/guide/concept/configuration.md ../src/guide/tutorial/using-yii-with-frankenphp.md ../src/guide/tutorial/using-yii-with-roadrunner.md ../src/guide/views/view-injections.md +#, no-wrap +msgid "Configuration" +msgstr "Configuração" + +#. type: Title ## +#: ../src/guide/tutorial/using-yii-with-frankenphp.md ../src/guide/tutorial/using-yii-with-roadrunner.md ../src/guide/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "Starting a server" +msgstr "Iniciando o servidor" + +#. type: Title ## +#: ../src/guide/tutorial/using-yii-with-frankenphp.md ../src/guide/tutorial/using-yii-with-roadrunner.md +#, no-wrap +msgid "On worker scope" +msgstr "Sobre o escopo do worker" + +#. type: Title # +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +#, no-wrap +msgid "Using Yii with RoadRunner" +msgstr "Usando o Yii com RoadRunner" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +#, no-wrap +msgid "" +"[RoadRunner](https://roadrunner.dev/) is a Golang-powered application server that integrates well with PHP. It runs\n" +"it as workers and each worker may handle multiple requests. Such an operation mode is often called\n" +"[event loop](using-with-event-loop.md) and allows not re-initializing a framework for each request that improves\n" +"performance significantly.\n" +msgstr "" +"O [RoadRunner](https://roadrunner.dev/) é um servidor de aplicação escrito em Go que se integra bem ao PHP. Ele roda\n" +"o PHP como workers, e cada worker pode atender várias requisições. Esse modo de operação costuma ser chamado de\n" +"[event loop](using-with-event-loop.md) e evita reinicializar o framework a cada requisição, o que melhora\n" +"bastante o desempenho.\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +msgid "RoadRunner works on Linux, macOS and Windows. The best way to install it is to use a Composer:" +msgstr "O RoadRunner funciona no Linux, macOS e Windows. A melhor forma de instalá-lo é pelo Composer:" + +#. type: Fenced code block +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +#, no-wrap +msgid "composer require yiisoft/yii-runner-roadrunner\n" +msgstr "composer require yiisoft/yii-runner-roadrunner\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +msgid "After installation is done, run" +msgstr "Terminada a instalação, execute" + +#. type: Fenced code block +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +#, no-wrap +msgid "./vendor/bin/rr get\n" +msgstr "./vendor/bin/rr get\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +msgid "That would download ready to use RoadRunner server `rr` binary." +msgstr "Isso baixa o binário `rr` do servidor RoadRunner, pronto para uso." + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +msgid "First, we need to configure the server itself. Create `/.rr.yaml` and add the following config:" +msgstr "Primeiro, precisamos configurar o próprio servidor. Crie `/.rr.yaml` e adicione a seguinte configuração:" + +#. type: Fenced code block (yaml) +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +#, no-wrap +msgid "" +"version: '3'\n" +"\n" +"server:\n" +" command: \"php worker.php\"\n" +"\n" +"rpc:\n" +" listen: tcp://127.0.0.1:6001\n" +"\n" +"http:\n" +" address: :8080\n" +" pool:\n" +" debug: false # set to true for local development only\n" +" supervisor:\n" +" max_worker_memory: 192\n" +" middleware: [static, gzip, headers, sendfile]\n" +" static:\n" +" dir: \"public\"\n" +" forbid: [\".php\", \".htaccess\"]\n" +" headers:\n" +" response:\n" +" \"Cache-Control\": \"no-cache\"\n" +"\n" +"logs:\n" +" mode: production\n" +" level: warn\n" +msgstr "" +"version: '3'\n" +"\n" +"server:\n" +" command: \"php worker.php\"\n" +"\n" +"rpc:\n" +" listen: tcp://127.0.0.1:6001\n" +"\n" +"http:\n" +" address: :8080\n" +" pool:\n" +" debug: false # defina como true apenas no desenvolvimento local\n" +" supervisor:\n" +" max_worker_memory: 192\n" +" middleware: [static, gzip, headers, sendfile]\n" +" static:\n" +" dir: \"public\"\n" +" forbid: [\".php\", \".htaccess\"]\n" +" headers:\n" +" response:\n" +" \"Cache-Control\": \"no-cache\"\n" +"\n" +"logs:\n" +" mode: production\n" +" level: warn\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +#, no-wrap +msgid "" +"> [!INFO]\n" +"> Read more about TLS, HTTP/2, HTTP/3 configuration and other middleware [on the RoadRunner docs](https://docs.roadrunner.dev/docs/http/http).\n" +msgstr "" +"> [!INFO]\n" +"> Saiba mais sobre configuração de TLS, HTTP/2, HTTP/3 e outros middlewares [na documentação do RoadRunner](https://docs.roadrunner.dev/docs/http/http).\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +msgid "We're specifying that the entry script is `worker.php`, the server listens on port 8080, `public` directory files are served statically except `.php` and `.htaccess`. The `max_worker_memory` is a soft limit: if a worker exceeds 192 MB, it will restart after finishing its current request. Also, we're sending an additional header." +msgstr "Estamos definindo que o script de entrada é o `worker.php`, que o servidor escuta na porta 8080 e que os arquivos do diretório `public` são servidos estaticamente, exceto `.php` e `.htaccess`. O `max_worker_memory` é um limite flexível: se um worker passar de 192 MB, ele reinicia depois de terminar a requisição atual. Também estamos enviando um header adicional." + +#. type: Title ## +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +#, no-wrap +msgid "KV cache" +msgstr "Cache KV" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +msgid "RoadRunner has a [KV plugin](https://docs.roadrunner.dev/docs/key-value/overview-kv) that can be used as a PSR-16 cache storage. It is useful when the application already runs under RoadRunner and needs a cache shared by workers." +msgstr "O RoadRunner tem um [plugin KV](https://docs.roadrunner.dev/docs/key-value/overview-kv) que pode ser usado como armazenamento de cache PSR-16. Ele é útil quando a aplicação já roda no RoadRunner e precisa de um cache compartilhado entre os workers." + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +msgid "Install the PHP bridge and Yii cache package:" +msgstr "Instale a ponte PHP e o pacote de cache do Yii:" + +#. type: Fenced code block +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +#, no-wrap +msgid "composer require spiral/roadrunner-kv yiisoft/cache\n" +msgstr "composer require spiral/roadrunner-kv yiisoft/cache\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +msgid "Add a KV storage to `.rr.yaml`:" +msgstr "Adicione um armazenamento KV ao `.rr.yaml`:" + +#. type: Fenced code block (yaml) +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +#, no-wrap +msgid "" +"kv:\n" +" cache:\n" +" driver: memory\n" +" config:\n" +" interval: 60\n" +msgstr "" +"kv:\n" +" cache:\n" +" driver: memory\n" +" config:\n" +" interval: 60\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +msgid "The `memory` driver stores values inside the RoadRunner process, so its data is lost when RoadRunner stops. For persistent cache storage, use another KV driver from the RoadRunner documentation." +msgstr "O driver `memory` guarda os valores dentro do processo do RoadRunner, então os dados se perdem quando o RoadRunner para. Para um armazenamento de cache persistente, use outro driver KV da documentação do RoadRunner." + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +msgid "Create `config/common/di/roadrunner-kv.php`:" +msgstr "Crie `config/common/di/roadrunner-kv.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +#, no-wrap +msgid "" +" static function (): StorageInterface {\n" +" $factory = new Factory(RPC::create('tcp://127.0.0.1:6001'));\n" +"\n" +" return $factory->select('cache');\n" +" },\n" +"\n" +" SimpleCacheInterface::class => StorageInterface::class,\n" +" YiiCacheInterface::class => Cache::class,\n" +"];\n" +msgstr "" +" static function (): StorageInterface {\n" +" $factory = new Factory(RPC::create('tcp://127.0.0.1:6001'));\n" +"\n" +" return $factory->select('cache');\n" +" },\n" +"\n" +" SimpleCacheInterface::class => StorageInterface::class,\n" +" YiiCacheInterface::class => Cache::class,\n" +"];\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +msgid "Now services can use `Yiisoft\\Cache\\CacheInterface` the same way as with other cache backends:" +msgstr "Agora os serviços podem usar `Yiisoft\\Cache\\CacheInterface` do mesmo jeito que com outros backends de cache:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +#, no-wrap +msgid "" +"use Yiisoft\\Cache\\CacheInterface;\n" +"\n" +"final readonly class FeedService\n" +"{\n" +" public function __construct(\n" +" private CacheInterface $cache,\n" +" ) {\n" +" }\n" +"\n" +" public function latest(): array\n" +" {\n" +" return $this->cache->getOrSet('feed-latest', fn (): array => $this->loadLatest(), 60);\n" +" }\n" +"\n" +" private function loadLatest(): array\n" +" {\n" +" return [];\n" +" }\n" +"}\n" +msgstr "" +"use Yiisoft\\Cache\\CacheInterface;\n" +"\n" +"final readonly class FeedService\n" +"{\n" +" public function __construct(\n" +" private CacheInterface $cache,\n" +" ) {\n" +" }\n" +"\n" +" public function latest(): array\n" +" {\n" +" return $this->cache->getOrSet('feed-latest', fn (): array => $this->loadLatest(), 60);\n" +" }\n" +"\n" +" private function loadLatest(): array\n" +" {\n" +" return [];\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +msgid "Create `/worker.php`:" +msgstr "Crie `/worker.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +#, no-wrap +msgid "" +"run();\n" +msgstr "" +"run();\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-roadrunner.md ../src/guide/tutorial/using-yii-with-swoole.md +msgid "To start a server, execute the following command:" +msgstr "Para iniciar o servidor, execute o seguinte comando:" + +#. type: Fenced code block +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +#, no-wrap +msgid "./rr serve\n" +msgstr "./rr serve\n" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +msgid "Each worker's scope is isolated from other workers. Memory isn't shared." +msgstr "O escopo de cada worker é isolado dos outros workers. A memória não é compartilhada." + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +msgid "A single worker serves multiple requests where the scope is shared." +msgstr "Um único worker atende várias requisições, e nelas o escopo é compartilhado." + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/using-yii-with-roadrunner.md +msgid "At each iteration of the event loop, every service that depends on state should be reset." +msgstr "A cada iteração do event loop, todo serviço que depende de estado deve ser redefinido." diff --git a/_translations/po/pt-BR/guide_tutorial_using-yii-with-swoole.md.po b/_translations/po/pt-BR/guide_tutorial_using-yii-with-swoole.md.po new file mode 100644 index 00000000..3f3526c7 --- /dev/null +++ b/_translations/po/pt-BR/guide_tutorial_using-yii-with-swoole.md.po @@ -0,0 +1,339 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-10-07 20:23+0000\n" +"PO-Revision-Date: 2026-10-07 20:23+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/making-http-requests.md ../src/cookbook/sentry-integration.md ../src/cookbook/third-party-integrations/symfony-messenger-integration-guide.md ../src/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md ../src/guide/tutorial/using-yii-with-frankenphp.md ../src/guide/tutorial/using-yii-with-rapira.md ../src/guide/tutorial/using-yii-with-roadrunner.md ../src/guide/tutorial/using-yii-with-swoole.md ../src/guide/views/asset.md ../src/guide/views/view.md ../src/guide/views/widget.md +#, no-wrap +msgid "Installation" +msgstr "Instalação" + +#. type: Title ## +#: ../src/guide/runtime/sessions.md ../src/guide/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "Sessions" +msgstr "Sessões" + +#. type: Title ## +#: ../src/guide/tutorial/using-yii-with-frankenphp.md ../src/guide/tutorial/using-yii-with-rapira.md ../src/guide/tutorial/using-yii-with-roadrunner.md ../src/guide/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "Starting a server" +msgstr "Iniciando o servidor" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-roadrunner.md ../src/guide/tutorial/using-yii-with-swoole.md +msgid "To start a server, execute the following command:" +msgstr "Para iniciar o servidor, execute o seguinte comando:" + +#. type: Title # +#: ../src/guide/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "Using Yii with Swoole" +msgstr "Usando o Yii com Swoole" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "" +"[Swoole](https://www.swoole.com/) is a PHP extension for event-driven, coroutine-based network applications. It\n" +"includes an HTTP server, coroutine APIs, and runtime hooks for common blocking I/O functions.\n" +msgstr "" +"O [Swoole](https://www.swoole.com/) é uma extensão PHP para aplicações de rede orientadas a eventos e baseadas em corrotinas. Ela\n" +"inclui um servidor HTTP, APIs de corrotinas e hooks de runtime para as funções de I/O bloqueantes mais comuns.\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-swoole.md +msgid "Swoole allows Yii request handlers to run as workers. Each worker may handle multiple requests. Such an operation mode is often called [event loop](using-with-event-loop.md) and allows not re-initializing a framework for each request that improves performance significantly." +msgstr "O Swoole permite que os handlers de requisição do Yii rodem como workers. Cada worker pode atender várias requisições. Esse modo de operação costuma ser chamado de [event loop](using-with-event-loop.md) e evita reinicializar o framework a cada requisição, o que melhora bastante o desempenho." + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-swoole.md +msgid "Swoole supports Linux, macOS, Cygwin, and WSL. Install the extension through PECL:" +msgstr "O Swoole suporta Linux, macOS, Cygwin e WSL. Instale a extensão pelo PECL:" + +#. type: Fenced code block (bash) +#: ../src/guide/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "pecl install swoole\n" +msgstr "pecl install swoole\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-swoole.md +msgid "If PECL doesn't enable the extension automatically, add it to your `php.ini`:" +msgstr "Se o PECL não habilitar a extensão automaticamente, adicione-a ao seu `php.ini`:" + +#. type: Fenced code block (ini) +#: ../src/guide/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "extension=swoole.so\n" +msgstr "extension=swoole.so\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-swoole.md +msgid "Check that PHP loads the extension:" +msgstr "Confira se o PHP carrega a extensão:" + +#. type: Fenced code block (bash) +#: ../src/guide/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "php --ri swoole\n" +msgstr "php --ri swoole\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-swoole.md +msgid "The Swoole project also provides a [Docker image](https://github.com/swoole/docker-swoole) and documents source builds with optional features such as OpenSSL, sockets, MySQL, PostgreSQL, and curl hooks." +msgstr "O projeto Swoole também oferece uma [imagem Docker](https://github.com/swoole/docker-swoole) e documenta builds a partir do código-fonte com recursos opcionais, como hooks para OpenSSL, sockets, MySQL, PostgreSQL e curl." + +#. type: Title ## +#: ../src/guide/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "Putting up a server" +msgstr "Subindo um servidor" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-swoole.md +msgid "Swoole passes `Swoole\\Http\\Request` and `Swoole\\Http\\Response` objects to request callbacks. Yii handles PSR-7 requests and responses, so add a converter package:" +msgstr "O Swoole passa objetos `Swoole\\Http\\Request` e `Swoole\\Http\\Response` para os callbacks de requisição. O Yii trabalha com requisições e respostas PSR-7, então adicione um pacote conversor:" + +#. type: Fenced code block (shell) +#: ../src/guide/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "composer require ilexn/swoole-convert-psr7\n" +msgstr "composer require ilexn/swoole-convert-psr7\n" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-swoole.md +msgid "Create an entry script, `server.php`:" +msgstr "Crie um script de entrada, `server.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "" +"setLevels([\n" +" LogLevel::EMERGENCY,\n" +" LogLevel::ERROR,\n" +" LogLevel::WARNING,\n" +" ]),\n" +" ],\n" +" ),\n" +" new HtmlRenderer(),\n" +" ),\n" +");\n" +"\n" +"$container = $runner->getContainer();\n" +"$application = $container->get(Application::class);\n" +"$errorCatcher = $container->get(ErrorCatcher::class);\n" +"\n" +"$serverRequestFactory = new SwooleServerRequestConverter(\n" +" $container->get(ServerRequestFactoryInterface::class),\n" +" $container->get(UriFactoryInterface::class),\n" +" $container->get(UploadedFileFactoryInterface::class),\n" +" $container->get(StreamFactoryInterface::class)\n" +");\n" +"\n" +"$server = new Server('0.0.0.0', 9501);\n" +"\n" +"$server->on('start', static function (Server $server) use ($application) {\n" +" $application->start();\n" +" echo \"Swoole http server is started at http://127.0.0.1:9501\\n\";\n" +"});\n" +"\n" +"$server->on('request', static function (\n" +" Request $request,\n" +" Response $response\n" +") use ($serverRequestFactory, $application, $errorCatcher, $container) {\n" +" try {\n" +" $psr7Request = $serverRequestFactory->createFromSwoole($request);\n" +" $psr7Response = $application->handle($psr7Request);\n" +" (new SwooleResponseConverter($response))->send($psr7Response);\n" +" } catch (Throwable $throwable) {\n" +" $handler = new ThrowableHandler($throwable);\n" +" $psr7Response = $errorCatcher->process($request, $handler);\n" +" (new SwooleResponseConverter($response))->send($psr7Response);\n" +" }\n" +" $application->afterEmit($psr7Response);\n" +" $container->get(StateResetter::class)->reset();\n" +"});\n" +"\n" +"$server->on('shutdown', static function (Server $server) use ($application) {\n" +" $application->shutdown();\n" +"});\n" +"\n" +"$server->start();\n" +msgstr "" +"setLevels([\n" +" LogLevel::EMERGENCY,\n" +" LogLevel::ERROR,\n" +" LogLevel::WARNING,\n" +" ]),\n" +" ],\n" +" ),\n" +" new HtmlRenderer(),\n" +" ),\n" +");\n" +"\n" +"$container = $runner->getContainer();\n" +"$application = $container->get(Application::class);\n" +"$errorCatcher = $container->get(ErrorCatcher::class);\n" +"\n" +"$serverRequestFactory = new SwooleServerRequestConverter(\n" +" $container->get(ServerRequestFactoryInterface::class),\n" +" $container->get(UriFactoryInterface::class),\n" +" $container->get(UploadedFileFactoryInterface::class),\n" +" $container->get(StreamFactoryInterface::class)\n" +");\n" +"\n" +"$server = new Server('0.0.0.0', 9501);\n" +"\n" +"$server->on('start', static function (Server $server) use ($application) {\n" +" $application->start();\n" +" echo \"Swoole http server is started at http://127.0.0.1:9501\\n\";\n" +"});\n" +"\n" +"$server->on('request', static function (\n" +" Request $request,\n" +" Response $response\n" +") use ($serverRequestFactory, $application, $errorCatcher, $container) {\n" +" try {\n" +" $psr7Request = $serverRequestFactory->createFromSwoole($request);\n" +" $psr7Response = $application->handle($psr7Request);\n" +" (new SwooleResponseConverter($response))->send($psr7Response);\n" +" } catch (Throwable $throwable) {\n" +" $handler = new ThrowableHandler($throwable);\n" +" $psr7Response = $errorCatcher->process($request, $handler);\n" +" (new SwooleResponseConverter($response))->send($psr7Response);\n" +" }\n" +" $application->afterEmit($psr7Response);\n" +" $container->get(StateResetter::class)->reset();\n" +"});\n" +"\n" +"$server->on('shutdown', static function (Server $server) use ($application) {\n" +" $application->shutdown();\n" +"});\n" +"\n" +"$server->start();\n" + +#. type: Fenced code block +#: ../src/guide/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "php server.php\n" +msgstr "php server.php\n" + +#. type: Title ## +#: ../src/guide/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "On scope" +msgstr "Sobre o escopo" + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-swoole.md +msgid "A scope is shared, so at each iteration of the event loop every service that depends on state should be reset." +msgstr "O escopo é compartilhado, então a cada iteração do event loop todo serviço que depende de estado deve ser redefinido." + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-swoole.md +msgid "Avoid native PHP sessions, including `Yiisoft\\Session\\Session`, when Swoole coroutines handle overlapping requests within one worker: they share session state and can expose one user's data to another request." +msgstr "Evite as sessões nativas do PHP, incluindo `Yiisoft\\Session\\Session`, quando corrotinas do Swoole atendem requisições simultâneas dentro de um mesmo worker: elas compartilham o estado da sessão e podem expor os dados de um usuário a outra requisição." + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-swoole.md +msgid "For requests handled one at a time, close the session and reset services between requests. `yiisoft/session` prevents stale session ID reuse, but does not isolate overlapping coroutines." +msgstr "Para requisições atendidas uma por vez, feche a sessão e redefina os serviços entre as requisições. O `yiisoft/session` impede o reuso de IDs de sessão antigos, mas não isola corrotinas simultâneas." + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-swoole.md +msgid "For authentication, consider tokens such as [JWT](https://jwt.io/introduction) instead of native sessions, especially for APIs. If you need session features, use an implementation that isolates each coroutine's session data; changing the native storage handler to Redis is not enough." +msgstr "Para autenticação, considere tokens como [JWT](https://jwt.io/introduction) em vez de sessões nativas, principalmente em APIs. Se você precisa de recursos de sessão, use uma implementação que isole os dados de sessão de cada corrotina; trocar o handler de armazenamento nativo para Redis não basta." + +#. type: Plain text +#: ../src/guide/tutorial/using-yii-with-swoole.md +msgid "See the [Swoole guidance](https://github.com/swoole/swoole-src/issues/4478#issuecomment-962840796) and [Yii session discussion](https://github.com/yiisoft/session/issues/25)." +msgstr "Veja as [orientações do Swoole](https://github.com/swoole/swoole-src/issues/4478#issuecomment-962840796) e a [discussão sobre sessões no Yii](https://github.com/yiisoft/session/issues/25)." diff --git a/_translations/po/pt-BR/guide_views_asset.md.po b/_translations/po/pt-BR/guide_views_asset.md.po new file mode 100644 index 00000000..e4d8cceb --- /dev/null +++ b/_translations/po/pt-BR/guide_views_asset.md.po @@ -0,0 +1,1457 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-05-05 22:01+0000\n" +"PO-Revision-Date: 2026-05-05 22:01+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md ../src/guide/views/asset.md +#, no-wrap +msgid "Troubleshooting" +msgstr "Solução de problemas" + +#. type: Title ## +#: ../src/cookbook/making-http-requests.md ../src/cookbook/sentry-integration.md ../src/guide/tutorial/using-yii-with-frankenphp.md ../src/guide/tutorial/using-yii-with-roadrunner.md ../src/guide/tutorial/using-yii-with-swoole.md ../src/guide/views/asset.md ../src/guide/views/view.md ../src/guide/views/widget.md +#, no-wrap +msgid "Installation" +msgstr "Instalação" + +#. type: Title # +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Assets" +msgstr "Assets" + +#. type: Plain text +#: ../src/guide/views/asset.md +msgid "Asset management is crucial for modern web applications. Assets include CSS stylesheets, JavaScript files, images, fonts, and other static resources. Yii3 provides a comprehensive asset management system through the `yiisoft/assets` package that handles dependencies, optimization, and deployment of these resources." +msgstr "O gerenciamento de assets é essencial em aplicações web modernas. Assets incluem folhas de estilo CSS, arquivos JavaScript, imagens, fontes e outros recursos estáticos. O Yii3 oferece um sistema completo de gerenciamento de assets por meio do pacote `yiisoft/assets`, que cuida das dependências, da otimização e da publicação desses recursos." + +#. type: Plain text +#: ../src/guide/views/asset.md +msgid "The asset management functionality is provided by the `yiisoft/assets` package:" +msgstr "A funcionalidade de gerenciamento de assets vem do pacote `yiisoft/assets`:" + +#. type: Fenced code block (bash) +#: ../src/guide/views/asset.md +#, no-wrap +msgid "composer require yiisoft/assets\n" +msgstr "composer require yiisoft/assets\n" + +#. type: Plain text +#: ../src/guide/views/asset.md +msgid "This package is included by default in the `yiisoft/app` application template." +msgstr "Esse pacote já vem incluído por padrão no template de aplicação `yiisoft/app`." + +#. type: Title ## +#: ../src/guide/views/asset.md ../src/guide/views/view.md ../src/guide/views/widget.md +#, no-wrap +msgid "Basic Concepts" +msgstr "Conceitos básicos" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Asset Bundles" +msgstr "Asset bundles" + +#. type: Plain text +#: ../src/guide/views/asset.md +msgid "An asset bundle is a collection of related asset files (CSS, JavaScript, images) that are logically grouped together. Asset bundles can depend on other bundles, allowing for proper dependency management." +msgstr "Um asset bundle é um conjunto de arquivos de asset relacionados (CSS, JavaScript, imagens) agrupados logicamente. Asset bundles podem depender de outros bundles, o que permite gerenciar as dependências corretamente." + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Asset Manager" +msgstr "Asset Manager" + +#. type: Plain text +#: ../src/guide/views/asset.md +msgid "The Asset Manager is responsible for: - Resolving asset bundle dependencies - Publishing assets from protected directories to web-accessible locations - Combining and minifying assets (when configured) - Generating proper URLs for assets" +msgstr "O Asset Manager é responsável por: - Resolver as dependências dos asset bundles - Publicar assets de diretórios protegidos em locais acessíveis pela web - Combinar e minificar assets (quando configurado) - Gerar as URLs corretas dos assets" + +#. type: Title ## +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Creating Asset Bundles" +msgstr "Criando asset bundles" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Basic Asset Bundle" +msgstr "Asset bundle básico" + +#. type: Plain text +#: ../src/guide/views/asset.md +msgid "Here's a simple asset bundle definition:" +msgstr "Esta é uma definição simples de asset bundle:" + +#. type: Fenced code block (php) +#: ../src/guide/views/asset.md +#, no-wrap +msgid "" +" 'print'],\n" +" ['css/admin/mobile.css', 'media' => 'screen and (max-width: 768px)'],\n" +" ];\n" +" \n" +" // JavaScript files with attributes\n" +" public array $js = [\n" +" 'js/admin/core.js',\n" +" ['js/admin/charts.js', 'defer' => true],\n" +" ['js/admin/analytics.js', 'async' => true],\n" +" ];\n" +" \n" +" // Global options for all JS files in this bundle\n" +" public array $jsOptions = [\n" +" 'data-admin' => 'true',\n" +" ];\n" +" \n" +" // Global options for all CSS files in this bundle\n" +" public array $cssOptions = [\n" +" 'data-bundle' => 'admin',\n" +" ];\n" +" \n" +" public array $depends = [\n" +" MainAsset::class,\n" +" ChartJsAsset::class,\n" +" ];\n" +"}\n" +msgstr "" +" 'print'],\n" +" ['css/admin/mobile.css', 'media' => 'screen and (max-width: 768px)'],\n" +" ];\n" +" \n" +" // Arquivos JavaScript com atributos\n" +" public array $js = [\n" +" 'js/admin/core.js',\n" +" ['js/admin/charts.js', 'defer' => true],\n" +" ['js/admin/analytics.js', 'async' => true],\n" +" ];\n" +" \n" +" // Opções globais para todos os arquivos JS deste bundle\n" +" public array $jsOptions = [\n" +" 'data-admin' => 'true',\n" +" ];\n" +" \n" +" // Opções globais para todos os arquivos CSS deste bundle\n" +" public array $cssOptions = [\n" +" 'data-bundle' => 'admin',\n" +" ];\n" +" \n" +" public array $depends = [\n" +" MainAsset::class,\n" +" ChartJsAsset::class,\n" +" ];\n" +"}\n" + +#. type: Title ## +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Using Asset Bundles" +msgstr "Usando asset bundles" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "In Controllers" +msgstr "Em controllers" + +#. type: Plain text +#: ../src/guide/views/asset.md +msgid "Register asset bundles in your controllers or views:" +msgstr "Registre os asset bundles nos seus controllers ou views:" + +#. type: Fenced code block (php) +#: ../src/guide/views/asset.md +#, no-wrap +msgid "" +"assetManager->register(MainAsset::class);\n" +" \n" +" return $this->viewRenderer->render('index', [\n" +" 'title' => 'Home Page',\n" +" ]);\n" +" }\n" +" \n" +" public function admin(): ResponseInterface\n" +" {\n" +" // Register multiple asset bundles\n" +" $this->assetManager->registerMany([\n" +" MainAsset::class,\n" +" AdminAsset::class,\n" +" ]);\n" +" \n" +" return $this->viewRenderer->render('admin/dashboard');\n" +" }\n" +"}\n" +msgstr "" +"assetManager->register(MainAsset::class);\n" +" \n" +" return $this->viewRenderer->render('index', [\n" +" 'title' => 'Home Page',\n" +" ]);\n" +" }\n" +" \n" +" public function admin(): ResponseInterface\n" +" {\n" +" // Registra vários asset bundles\n" +" $this->assetManager->registerMany([\n" +" MainAsset::class,\n" +" AdminAsset::class,\n" +" ]);\n" +" \n" +" return $this->viewRenderer->render('admin/dashboard');\n" +" }\n" +"}\n" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "In Views" +msgstr "Em views" + +#. type: Plain text +#: ../src/guide/views/asset.md +msgid "You can also register assets directly in views:" +msgstr "Você também pode registrar assets diretamente nas views:" + +#. type: Fenced code block (php) +#: ../src/guide/views/asset.md +#, no-wrap +msgid "" +"register(ProductAsset::class);\n" +"?>\n" +"\n" +"
\n" +"

\n" +" \n" +"
\n" +msgstr "" +"register(ProductAsset::class);\n" +"?>\n" +"\n" +"
\n" +"

\n" +" \n" +"
\n" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "With WebView Integration" +msgstr "Com integração à WebView" + +#. type: Plain text +#: ../src/guide/views/asset.md +msgid "The recommended approach is to integrate with WebView for automatic asset rendering:" +msgstr "A abordagem recomendada é integrar com a WebView para que os assets sejam renderizados automaticamente:" + +#. type: Fenced code block (php) +#: ../src/guide/views/asset.md +#, no-wrap +msgid "" +"register(MainAsset::class);\n" +"\n" +"// Add all registered assets to the view\n" +"$this->addCssFiles($assetManager->getCssFiles());\n" +"$this->addCssStrings($assetManager->getCssStrings());\n" +"$this->addJsFiles($assetManager->getJsFiles());\n" +"$this->addJsStrings($assetManager->getJsStrings());\n" +"$this->addJsVars($assetManager->getJsVars());\n" +"?>\n" +"\n" +"
\n" +" \n" +"
\n" +msgstr "" +"register(MainAsset::class);\n" +"\n" +"// Adiciona todos os assets registrados à view\n" +"$this->addCssFiles($assetManager->getCssFiles());\n" +"$this->addCssStrings($assetManager->getCssStrings());\n" +"$this->addJsFiles($assetManager->getJsFiles());\n" +"$this->addJsStrings($assetManager->getJsStrings());\n" +"$this->addJsVars($assetManager->getJsVars());\n" +"?>\n" +"\n" +"
\n" +" \n" +"
\n" + +#. type: Title ## +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Asset Publishing" +msgstr "Publicação de assets" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Source Path Publishing" +msgstr "Publicação a partir do source path" + +#. type: Plain text +#: ../src/guide/views/asset.md +msgid "When assets are located in non-web-accessible directories (like vendor packages), they need to be published:" +msgstr "Quando os assets ficam em diretórios não acessíveis pela web (como pacotes do vendor), eles precisam ser publicados:" + +#. type: Fenced code block (php) +#: ../src/guide/views/asset.md +#, no-wrap +msgid "" +"publish('@vendor/company/package/assets');\n" +"\n" +"// Get the published URL\n" +"$publishedUrl = $assetManager->getPublishedUrl('@vendor/company/package/assets');\n" +msgstr "" +"/**\n" +" * @var \\Yiisoft\\Assets\\AssetManager $assetManager\n" +" */\n" +"\n" +"// Publica um diretório\n" +"$publishedPath = $assetManager->publish('@vendor/company/package/assets');\n" +"\n" +"// Obtém a URL publicada\n" +"$publishedUrl = $assetManager->getPublishedUrl('@vendor/company/package/assets');\n" + +#. type: Title ## +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Third-party Library Assets" +msgstr "Assets de bibliotecas de terceiros" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "jQuery Asset Bundle" +msgstr "Asset bundle do jQuery" + +#. type: Fenced code block (php) +#: ../src/guide/views/asset.md +#, no-wrap +msgid "" +" 'sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3',\n" +" 'crossorigin' => 'anonymous',\n" +" ];\n" +"\n" +" public array $js = [\n" +" 'https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js',\n" +" ];\n" +"\n" +" public array $jsOptions = [\n" +" 'integrity' => 'sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p',\n" +" 'crossorigin' => 'anonymous',\n" +" ];\n" +"}\n" +msgstr "" +" 'sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3',\n" +" 'crossorigin' => 'anonymous',\n" +" ];\n" +"\n" +" public array $js = [\n" +" 'https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js',\n" +" ];\n" +"\n" +" public array $jsOptions = [\n" +" 'integrity' => 'sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p',\n" +" 'crossorigin' => 'anonymous',\n" +" ];\n" +"}\n" + +#. type: Title ## +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Asset Configuration" +msgstr "Configuração de assets" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Application Configuration" +msgstr "Configuração da aplicação" + +#. type: Plain text +#: ../src/guide/views/asset.md +msgid "Configure asset management in your application configuration:" +msgstr "Configure o gerenciamento de assets na configuração da sua aplicação:" + +#. type: Plain text +#: ../src/guide/views/asset.md +#, no-wrap +msgid "**config/web/params.php**\n" +msgstr "**config/web/params.php**\n" + +#. type: Fenced code block (php) +#: ../src/guide/views/asset.md +#, no-wrap +msgid "" +"return [\n" +" 'yiisoft/assets' => [\n" +" // Base path for published assets\n" +" 'basePath' => '@webroot/assets',\n" +" \n" +" // Base URL for assets\n" +" 'baseUrl' => '@web/assets',\n" +" \n" +" // Asset converter configuration\n" +" 'converter' => [\n" +" 'commands' => [\n" +" 'scss' => ['sass', '{from}', '{to}', '--style=compressed'],\n" +" 'ts' => ['tsc', '{from}', '--outFile', '{to}'],\n" +" ],\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" +"return [\n" +" 'yiisoft/assets' => [\n" +" // Caminho base dos assets publicados\n" +" 'basePath' => '@webroot/assets',\n" +" \n" +" // URL base dos assets\n" +" 'baseUrl' => '@web/assets',\n" +" \n" +" // Configuração do conversor de assets\n" +" 'converter' => [\n" +" 'commands' => [\n" +" 'scss' => ['sass', '{from}', '{to}', '--style=compressed'],\n" +" 'ts' => ['tsc', '{from}', '--outFile', '{to}'],\n" +" ],\n" +" ],\n" +" ],\n" +"];\n" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Environment-specific Assets" +msgstr "Assets por ambiente" + +#. type: Plain text +#: ../src/guide/views/asset.md +msgid "Configure different assets for different environments:" +msgstr "Configure assets diferentes para cada ambiente:" + +#. type: Fenced code block (php) +#: ../src/guide/views/asset.md +#, no-wrap +msgid "" +"css = ['css/main.css', 'css/debug.css'];\n" +" $this->js = ['js/main.js', 'js/debug.js'];\n" +" } else {\n" +" // Production assets (minified)\n" +" $this->css = ['css/main.min.css'];\n" +" $this->js = ['js/main.min.js'];\n" +" }\n" +" }\n" +"}\n" +msgstr "" +"css = ['css/main.css', 'css/debug.css'];\n" +" $this->js = ['js/main.js', 'js/debug.js'];\n" +" } else {\n" +" // Assets de produção (minificados)\n" +" $this->css = ['css/main.min.css'];\n" +" $this->js = ['js/main.min.js'];\n" +" }\n" +" }\n" +"}\n" + +#. type: Title ## +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Asset Optimization" +msgstr "Otimização de assets" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Asset Combination" +msgstr "Combinação de assets" + +#. type: Plain text +#: ../src/guide/views/asset.md +msgid "Combine multiple CSS or JavaScript files into single files:" +msgstr "Combine vários arquivos CSS ou JavaScript em arquivos únicos:" + +#. type: Fenced code block (php) +#: ../src/guide/views/asset.md +#, no-wrap +msgid "" +"/**\n" +" * @var \\Yiisoft\\Assets\\AssetManager $assetManager\n" +" */\n" +"\n" +"// Enable asset combination\n" +"$assetManager->setCombine(true);\n" +"\n" +"// Set combination options\n" +"$assetManager->setCombineOptions([\n" +" 'css' => true, // Combine CSS files\n" +" 'js' => true, // Combine JavaScript files\n" +"]);\n" +msgstr "" +"/**\n" +" * @var \\Yiisoft\\Assets\\AssetManager $assetManager\n" +" */\n" +"\n" +"// Habilita a combinação de assets\n" +"$assetManager->setCombine(true);\n" +"\n" +"// Define as opções de combinação\n" +"$assetManager->setCombineOptions([\n" +" 'css' => true, // Combina os arquivos CSS\n" +" 'js' => true, // Combina os arquivos JavaScript\n" +"]);\n" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Asset Compression" +msgstr "Compressão de assets" + +#. type: Plain text +#: ../src/guide/views/asset.md +msgid "Configure asset compression for production:" +msgstr "Configure a compressão de assets para produção:" + +#. type: Fenced code block (php) +#: ../src/guide/views/asset.md +#, no-wrap +msgid "" +"// In your asset manager configuration\n" +"'converter' => [\n" +" 'commands' => [\n" +" 'css' => ['cleancss', '{from}', '-o', '{to}'],\n" +" 'js' => ['uglifyjs', '{from}', '-o', '{to}', '--compress', '--mangle'],\n" +" ],\n" +"],\n" +msgstr "" +"// Na configuração do seu asset manager\n" +"'converter' => [\n" +" 'commands' => [\n" +" 'css' => ['cleancss', '{from}', '-o', '{to}'],\n" +" 'js' => ['uglifyjs', '{from}', '-o', '{to}', '--compress', '--mangle'],\n" +" ],\n" +"],\n" + +#. type: Title ## +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Working with Asset Converter" +msgstr "Trabalhando com o conversor de assets" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "SCSS/SASS Compilation" +msgstr "Compilação de SCSS/SASS" + +#. type: Fenced code block (php) +#: ../src/guide/views/asset.md +#, no-wrap +msgid "" +" 'screen and (max-width: 768px)'],\n" +" ];\n" +" \n" +" public array $depends = [\n" +" AppAsset::class,\n" +" ];\n" +"}\n" +msgstr "" +" 'screen and (max-width: 768px)'],\n" +" ];\n" +" \n" +" public array $depends = [\n" +" AppAsset::class,\n" +" ];\n" +"}\n" + +#. type: Title ## +#: ../src/guide/views/asset.md ../src/guide/views/script-style-meta.md ../src/guide/views/template-engines.md +#, no-wrap +msgid "Best Practices" +msgstr "Boas práticas" + +#. type: Bullet: '1. ' +#: ../src/guide/views/asset.md +msgid "**Organize by functionality**: Group related assets into logical bundles" +msgstr "**Organize por funcionalidade**: agrupe assets relacionados em bundles lógicos" + +#. type: Bullet: '2. ' +#: ../src/guide/views/asset.md +msgid "**Manage dependencies**: Properly declare dependencies between bundles" +msgstr "**Gerencie as dependências**: declare corretamente as dependências entre bundles" + +#. type: Bullet: '3. ' +#: ../src/guide/views/asset.md +msgid "**Use meaningful names**: Name your asset bundles clearly" +msgstr "**Use nomes significativos**: dê nomes claros aos seus asset bundles" + +#. type: Bullet: '4. ' +#: ../src/guide/views/asset.md +msgid "**Environment optimization**: Use minified assets in production" +msgstr "**Otimize por ambiente**: use assets minificados em produção" + +#. type: Bullet: '5. ' +#: ../src/guide/views/asset.md +msgid "**CDN consideration**: Use CDN for popular libraries when appropriate" +msgstr "**Considere uma CDN**: use CDN para bibliotecas populares quando fizer sentido" + +#. type: Bullet: '6. ' +#: ../src/guide/views/asset.md +msgid "**Version your assets**: Include version numbers in filenames for cache busting" +msgstr "**Versione seus assets**: inclua números de versão nos nomes dos arquivos para invalidar o cache" + +#. type: Bullet: '7. ' +#: ../src/guide/views/asset.md +msgid "**Minimize HTTP requests**: Combine related assets when possible" +msgstr "**Reduza as requisições HTTP**: combine assets relacionados quando possível" + +#. type: Bullet: '8. ' +#: ../src/guide/views/asset.md +msgid "**Optimize file sizes**: Compress and minify assets for production" +msgstr "**Otimize o tamanho dos arquivos**: comprima e minifique os assets para produção" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Common Issues" +msgstr "Problemas comuns" + +#. type: Plain text +#: ../src/guide/views/asset.md +#, no-wrap +msgid "" +"**Asset not found:**\n" +"- Check that the asset file exists in the specified path\n" +"- Verify `$basePath` and `$baseUrl` are configured correctly\n" +"- Ensure assets are published if using `$sourcePath`\n" +msgstr "" +"**Asset não encontrado:**\n" +"- Verifique se o arquivo de asset existe no caminho especificado\n" +"- Confira se `$basePath` e `$baseUrl` estão configurados corretamente\n" +"- Garanta que os assets foram publicados se você usa `$sourcePath`\n" + +#. type: Plain text +#: ../src/guide/views/asset.md +#, no-wrap +msgid "" +"**Dependencies not loading:**\n" +"- Verify the dependency bundles are properly registered\n" +"- Check for circular dependencies\n" +"- Ensure dependency bundles are correctly configured\n" +msgstr "" +"**Dependências não carregam:**\n" +"- Confira se os bundles de dependência estão registrados corretamente\n" +"- Verifique se há dependências circulares\n" +"- Garanta que os bundles de dependência estão configurados corretamente\n" + +#. type: Plain text +#: ../src/guide/views/asset.md +#, no-wrap +msgid "" +"**Assets not appearing in HTML:**\n" +"- Make sure you're calling `$this->addCssFiles()` and `$this->addJsFiles()` in your layout\n" +"- Verify that `$this->head()`, `$this->beginBody()`, and `$this->endBody()` are called in the layout\n" +msgstr "" +"**Assets não aparecem no HTML:**\n" +"- Verifique se você chama `$this->addCssFiles()` e `$this->addJsFiles()` no seu layout\n" +"- Confira se `$this->head()`, `$this->beginBody()` e `$this->endBody()` são chamados no layout\n" + +#. type: Plain text +#: ../src/guide/views/asset.md +#, no-wrap +msgid "" +"**Permission issues:**\n" +"- Check that the web server has write permissions to the assets directory\n" +"- Verify the published assets directory is web-accessible\n" +msgstr "" +"**Problemas de permissão:**\n" +"- Verifique se o servidor web tem permissão de escrita no diretório de assets\n" +"- Confira se o diretório de assets publicados é acessível pela web\n" diff --git a/_translations/po/pt-BR/guide_views_script-style-meta.md.po b/_translations/po/pt-BR/guide_views_script-style-meta.md.po new file mode 100644 index 00000000..665bdbab --- /dev/null +++ b/_translations/po/pt-BR/guide_views_script-style-meta.md.po @@ -0,0 +1,1119 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 13:00+0000\n" +"PO-Revision-Date: 2025-12-24 13:00+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/guide/structure/overview.md ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Overview" +msgstr "Visão geral" + +#. type: Title ## +#: ../src/guide/views/asset.md ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Practical Examples" +msgstr "Exemplos práticos" + +#. type: Title ## +#: ../src/guide/views/asset.md ../src/guide/views/script-style-meta.md ../src/guide/views/template-engines.md +#, no-wrap +msgid "Best Practices" +msgstr "Boas práticas" + +#. type: Title # +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Scripts, styles and meta tags" +msgstr "Scripts, estilos e meta tags" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "Modern web applications require careful management of CSS styles, JavaScript code, and HTML meta tags. Yii3 provides a comprehensive system for registering and organizing these resources through the `WebView` class, which is part of the `yiisoft/view` package." +msgstr "Aplicações web modernas exigem um gerenciamento cuidadoso de estilos CSS, código JavaScript e meta tags HTML. O Yii3 oferece um sistema completo para registrar e organizar esses recursos por meio da classe `WebView`, que faz parte do pacote `yiisoft/view`." + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "The `WebView` class extends the basic `View` class with web-specific functionality, allowing you to:" +msgstr "A classe `WebView` estende a classe básica `View` com funcionalidades específicas para a web, permitindo que você:" + +#. type: Bullet: '- ' +#: ../src/guide/views/script-style-meta.md +msgid "Register CSS files and inline styles" +msgstr "Registre arquivos CSS e estilos inline" + +#. type: Bullet: '- ' +#: ../src/guide/views/script-style-meta.md +msgid "Register JavaScript files and inline scripts" +msgstr "Registre arquivos JavaScript e scripts inline" + +#. type: Bullet: '- ' +#: ../src/guide/views/script-style-meta.md +msgid "Manage HTML meta tags and link tags" +msgstr "Gerencie meta tags e link tags HTML" + +#. type: Bullet: '- ' +#: ../src/guide/views/script-style-meta.md +msgid "Control the position where resources are rendered" +msgstr "Controle a posição em que os recursos são renderizados" + +#. type: Bullet: '- ' +#: ../src/guide/views/script-style-meta.md +msgid "Handle dependencies between resources" +msgstr "Lide com dependências entre recursos" + +#. type: Title ## +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "CSS management" +msgstr "Gerenciamento de CSS" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Registering CSS Files" +msgstr "Registrando arquivos CSS" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "You can register CSS files to be included in your HTML pages:" +msgstr "Você pode registrar arquivos CSS para incluí-los nas suas páginas HTML:" + +#. type: Fenced code block (php) +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "" +"registerCssFile('/css/styles.css');\n" +"\n" +"// Register CSS file with attributes\n" +"$this->registerCssFile('/css/print.css', WebView::POSITION_HEAD, [\n" +" 'media' => 'print',\n" +"]);\n" +"\n" +"// Register CSS file with custom key to avoid duplicates\n" +"$this->registerCssFile('/css/theme.css', WebView::POSITION_HEAD, [], 'theme-css');\n" +msgstr "" +"registerCssFile('/css/styles.css');\n" +"\n" +"// Registra um arquivo CSS com atributos\n" +"$this->registerCssFile('/css/print.css', WebView::POSITION_HEAD, [\n" +" 'media' => 'print',\n" +"]);\n" +"\n" +"// Registra um arquivo CSS com uma chave personalizada para evitar duplicatas\n" +"$this->registerCssFile('/css/theme.css', WebView::POSITION_HEAD, [], 'theme-css');\n" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Registering Inline CSS" +msgstr "Registrando CSS inline" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "For inline CSS styles, use the `registerCss()` method:" +msgstr "Para estilos CSS inline, use o método `registerCss()`:" + +#. type: Fenced code block (php) +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "" +"// Register inline CSS\n" +"$this->registerCss('\n" +" .highlight {\n" +" background-color: yellow;\n" +" font-weight: bold;\n" +" }\n" +" .error {\n" +" color: red;\n" +" border: 1px solid red;\n" +" }\n" +"', WebView::POSITION_HEAD);\n" +"\n" +"// With custom attributes\n" +"$this->registerCss('\n" +" @media print {\n" +" .no-print { display: none; }\n" +" }\n" +"', WebView::POSITION_HEAD, ['id' => 'print-styles']);\n" +msgstr "" +"// Registra CSS inline\n" +"$this->registerCss('\n" +" .highlight {\n" +" background-color: yellow;\n" +" font-weight: bold;\n" +" }\n" +" .error {\n" +" color: red;\n" +" border: 1px solid red;\n" +" }\n" +"', WebView::POSITION_HEAD);\n" +"\n" +"// Com atributos personalizados\n" +"$this->registerCss('\n" +" @media print {\n" +" .no-print { display: none; }\n" +" }\n" +"', WebView::POSITION_HEAD, ['id' => 'print-styles']);\n" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "CSS from Files" +msgstr "CSS a partir de arquivos" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "You can also register CSS content from external files:" +msgstr "Você também pode registrar o conteúdo CSS de arquivos externos:" + +#. type: Fenced code block (php) +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "" +"// Read CSS from a file and register as inline CSS\n" +"$this->registerCssFromFile('/path/to/dynamic-styles.css', WebView::POSITION_HEAD, [\n" +" 'id' => 'dynamic-styles',\n" +"]);\n" +msgstr "" +"// Lê o CSS de um arquivo e o registra como CSS inline\n" +"$this->registerCssFromFile('/path/to/dynamic-styles.css', WebView::POSITION_HEAD, [\n" +" 'id' => 'dynamic-styles',\n" +"]);\n" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Using Style Tags" +msgstr "Usando tags style" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "For more control, you can use HTML style tags directly:" +msgstr "Para ter mais controle, você pode usar tags style do HTML diretamente:" + +#. type: Fenced code block (php) +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "" +"use Yiisoft\\Html\\Html;\n" +"\n" +"$styleTag = Html::style('\n" +" .custom-button {\n" +" background: linear-gradient(45deg, #blue, #purple);\n" +" border: none;\n" +" color: white;\n" +" padding: 10px 20px;\n" +" }\n" +"', ['id' => 'custom-button-styles']);\n" +"\n" +"$this->registerStyleTag($styleTag, WebView::POSITION_HEAD);\n" +msgstr "" +"use Yiisoft\\Html\\Html;\n" +"\n" +"$styleTag = Html::style('\n" +" .custom-button {\n" +" background: linear-gradient(45deg, #blue, #purple);\n" +" border: none;\n" +" color: white;\n" +" padding: 10px 20px;\n" +" }\n" +"', ['id' => 'custom-button-styles']);\n" +"\n" +"$this->registerStyleTag($styleTag, WebView::POSITION_HEAD);\n" + +#. type: Title ## +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "JavaScript management" +msgstr "Gerenciamento de JavaScript" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Registering JavaScript Files" +msgstr "Registrando arquivos JavaScript" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "Include external JavaScript files using `registerJsFile()`:" +msgstr "Inclua arquivos JavaScript externos com `registerJsFile()`:" + +#. type: Fenced code block (php) +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "" +"// Register a JavaScript file\n" +"$this->registerJsFile('/js/main.js');\n" +"\n" +"// Register with attributes (async loading)\n" +"$this->registerJsFile('/js/analytics.js', WebView::POSITION_END, [\n" +" 'async' => true,\n" +"]);\n" +"\n" +"// Register with defer attribute\n" +"$this->registerJsFile('/js/interactive.js', WebView::POSITION_END, [\n" +" 'defer' => true,\n" +"]);\n" +"\n" +"// Register from CDN\n" +"$this->registerJsFile('https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js', \n" +" WebView::POSITION_END, [], 'jquery');\n" +msgstr "" +"// Registra um arquivo JavaScript\n" +"$this->registerJsFile('/js/main.js');\n" +"\n" +"// Registra com atributos (carregamento assíncrono)\n" +"$this->registerJsFile('/js/analytics.js', WebView::POSITION_END, [\n" +" 'async' => true,\n" +"]);\n" +"\n" +"// Registra com o atributo defer\n" +"$this->registerJsFile('/js/interactive.js', WebView::POSITION_END, [\n" +" 'defer' => true,\n" +"]);\n" +"\n" +"// Registra a partir de uma CDN\n" +"$this->registerJsFile('https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js', \n" +" WebView::POSITION_END, [], 'jquery');\n" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Registering Inline JavaScript" +msgstr "Registrando JavaScript inline" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "Add inline JavaScript code with `registerJs()`:" +msgstr "Adicione código JavaScript inline com `registerJs()`:" + +#. type: Fenced code block (php) +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "" +"// Register inline JavaScript\n" +"$this->registerJs('\n" +" document.addEventListener(\"DOMContentLoaded\", function() {\n" +" console.log(\"Page loaded!\");\n" +" initializeComponents();\n" +" });\n" +"', WebView::POSITION_END);\n" +"\n" +"// Register JavaScript that should run when DOM is ready\n" +"$this->registerJs('\n" +" function showAlert(message) {\n" +" alert(message);\n" +" }\n" +"', WebView::POSITION_READY);\n" +msgstr "" +"// Registra JavaScript inline\n" +"$this->registerJs('\n" +" document.addEventListener(\"DOMContentLoaded\", function() {\n" +" console.log(\"Page loaded!\");\n" +" initializeComponents();\n" +" });\n" +"', WebView::POSITION_END);\n" +"\n" +"// Registra JavaScript que deve rodar quando o DOM estiver pronto\n" +"$this->registerJs('\n" +" function showAlert(message) {\n" +" alert(message);\n" +" }\n" +"', WebView::POSITION_READY);\n" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "JavaScript Variables" +msgstr "Variáveis JavaScript" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "Pass PHP data to JavaScript using `registerJsVar()`:" +msgstr "Passe dados do PHP para o JavaScript com `registerJsVar()`:" + +#. type: Fenced code block (php) +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "" +"// Register JavaScript variables\n" +"$this->registerJsVar('apiUrl', 'https://api.example.com');\n" +"$this->registerJsVar('currentUser', [\n" +" 'id' => $user->getId(),\n" +" 'name' => $user->getName(),\n" +" 'isAdmin' => $user->isAdmin(),\n" +"]);\n" +"$this->registerJsVar('config', [\n" +" 'debug' => $this->isDebugMode(),\n" +" 'locale' => $this->getLocale(),\n" +"]);\n" +msgstr "" +"// Registra variáveis JavaScript\n" +"$this->registerJsVar('apiUrl', 'https://api.example.com');\n" +"$this->registerJsVar('currentUser', [\n" +" 'id' => $user->getId(),\n" +" 'name' => $user->getName(),\n" +" 'isAdmin' => $user->isAdmin(),\n" +"]);\n" +"$this->registerJsVar('config', [\n" +" 'debug' => $this->isDebugMode(),\n" +" 'locale' => $this->getLocale(),\n" +"]);\n" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "This generates JavaScript code like:" +msgstr "Isso gera um código JavaScript como este:" + +#. type: Fenced code block (html) +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "" +"\n" +msgstr "" +"\n" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Using Script Tags" +msgstr "Usando tags script" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "For more control over script tags:" +msgstr "Para ter mais controle sobre as tags script:" + +#. type: Fenced code block (php) +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "" +"use Yiisoft\\Html\\Html;\n" +"\n" +"$scriptTag = Html::script('\n" +" window.myApp = {\n" +" init: function() {\n" +" console.log(\"App initialized\");\n" +" }\n" +" };\n" +"', ['type' => 'module']);\n" +"\n" +"$this->registerScriptTag($scriptTag, WebView::POSITION_END);\n" +msgstr "" +"use Yiisoft\\Html\\Html;\n" +"\n" +"$scriptTag = Html::script('\n" +" window.myApp = {\n" +" init: function() {\n" +" console.log(\"App initialized\");\n" +" }\n" +" };\n" +"', ['type' => 'module']);\n" +"\n" +"$this->registerScriptTag($scriptTag, WebView::POSITION_END);\n" + +#. type: Title ## +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Position Constants" +msgstr "Constantes de posição" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "Resources can be positioned at different locations in the HTML document:" +msgstr "Os recursos podem ser posicionados em diferentes pontos do documento HTML:" + +#. type: Fenced code block (php) +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "" +"use Yiisoft\\View\\WebView;\n" +"\n" +"// In the section\n" +"WebView::POSITION_HEAD\n" +"\n" +"// At the beginning of \n" +"WebView::POSITION_BEGIN \n" +"\n" +"// At the end of (before )\n" +"WebView::POSITION_END\n" +"\n" +"// When DOM is ready (jQuery document.ready equivalent)\n" +"WebView::POSITION_READY\n" +"\n" +"// When page is fully loaded (window.onload equivalent)\n" +"WebView::POSITION_LOAD\n" +msgstr "" +"use Yiisoft\\View\\WebView;\n" +"\n" +"// Na seção \n" +"WebView::POSITION_HEAD\n" +"\n" +"// No início do \n" +"WebView::POSITION_BEGIN \n" +"\n" +"// No fim do (antes de )\n" +"WebView::POSITION_END\n" +"\n" +"// Quando o DOM estiver pronto (equivalente ao document.ready do jQuery)\n" +"WebView::POSITION_READY\n" +"\n" +"// Quando a página terminar de carregar (equivalente ao window.onload)\n" +"WebView::POSITION_LOAD\n" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "Example layout showing where each position is rendered:" +msgstr "Exemplo de layout mostrando onde cada posição é renderizada:" + +#. type: Fenced code block (php) +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "" +"\n" +"beginPage() ?>\n" +"\n" +"\n" +"\n" +" \n" +" head() ?>\n" +"\n" +"\n" +" \n" +" beginBody() ?>\n" +" \n" +"
\n" +" \n" +"
\n" +" \n" +" \n" +" endBody() ?>\n" +"\n" +"\n" +"endPage() ?>\n" +msgstr "" +"\n" +"beginPage() ?>\n" +"\n" +"\n" +"\n" +" \n" +" head() ?>\n" +"\n" +"\n" +" \n" +" beginBody() ?>\n" +" \n" +"
\n" +" \n" +"
\n" +" \n" +" \n" +" endBody() ?>\n" +"\n" +"\n" +"endPage() ?>\n" + +#. type: Title ## +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Meta tags" +msgstr "Meta tags" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Basic Meta Tags" +msgstr "Meta tags básicas" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "Register meta tags for SEO and page information:" +msgstr "Registre meta tags para SEO e informações da página:" + +#. type: Fenced code block (php) +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "" +"// Register meta tags using array syntax\n" +"$this->registerMeta(['name' => 'description', 'content' => 'Page description']);\n" +"$this->registerMeta(['name' => 'keywords', 'content' => 'yii, php, framework']);\n" +"$this->registerMeta(['name' => 'author', 'content' => 'John Doe']);\n" +"$this->registerMeta(['name' => 'robots', 'content' => 'index, follow']);\n" +"\n" +"// Viewport for responsive design\n" +"$this->registerMeta(['name' => 'viewport', 'content' => 'width=device-width, initial-scale=1']);\n" +"\n" +"// Open Graph tags for social media\n" +"$this->registerMeta(['property' => 'og:title', 'content' => 'Page Title']);\n" +"$this->registerMeta(['property' => 'og:description', 'content' => 'Page description']);\n" +"$this->registerMeta(['property' => 'og:image', 'content' => 'https://example.com/image.jpg']);\n" +msgstr "" +"// Registra meta tags usando a sintaxe de array\n" +"$this->registerMeta(['name' => 'description', 'content' => 'Page description']);\n" +"$this->registerMeta(['name' => 'keywords', 'content' => 'yii, php, framework']);\n" +"$this->registerMeta(['name' => 'author', 'content' => 'John Doe']);\n" +"$this->registerMeta(['name' => 'robots', 'content' => 'index, follow']);\n" +"\n" +"// Viewport para design responsivo\n" +"$this->registerMeta(['name' => 'viewport', 'content' => 'width=device-width, initial-scale=1']);\n" +"\n" +"// Tags Open Graph para redes sociais\n" +"$this->registerMeta(['property' => 'og:title', 'content' => 'Page Title']);\n" +"$this->registerMeta(['property' => 'og:description', 'content' => 'Page description']);\n" +"$this->registerMeta(['property' => 'og:image', 'content' => 'https://example.com/image.jpg']);\n" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Using Meta Tag Objects" +msgstr "Usando objetos de meta tag" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "For more control, use the `Html::meta()` helper:" +msgstr "Para ter mais controle, use o helper `Html::meta()`:" + +#. type: Fenced code block (php) +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "" +"use Yiisoft\\Html\\Html;\n" +"\n" +"// Create meta tags with the Html helper\n" +"$this->registerMetaTag(\n" +" Html::meta()\n" +" ->name('description')\n" +" ->content('This is a comprehensive guide to Yii3 views')\n" +");\n" +"\n" +"$this->registerMetaTag(\n" +" Html::meta()\n" +" ->httpEquiv('refresh')\n" +" ->content('300') // Refresh every 5 minutes\n" +");\n" +msgstr "" +"use Yiisoft\\Html\\Html;\n" +"\n" +"// Cria meta tags com o helper Html\n" +"$this->registerMetaTag(\n" +" Html::meta()\n" +" ->name('description')\n" +" ->content('This is a comprehensive guide to Yii3 views')\n" +");\n" +"\n" +"$this->registerMetaTag(\n" +" Html::meta()\n" +" ->httpEquiv('refresh')\n" +" ->content('300') // Atualiza a cada 5 minutos\n" +");\n" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Preventing Duplicate Meta Tags" +msgstr "Evitando meta tags duplicadas" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "Use keys to prevent duplicate meta tags:" +msgstr "Use chaves para evitar meta tags duplicadas:" + +#. type: Fenced code block (php) +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "" +"// First registration\n" +"$this->registerMeta([\n" +" 'name' => 'description',\n" +" 'content' => 'Original description'\n" +"], 'description');\n" +"\n" +"// This will override the previous one\n" +"$this->registerMeta([\n" +" 'name' => 'description', \n" +" 'content' => 'Updated description'\n" +"], 'description');\n" +msgstr "" +"// Primeiro registro\n" +"$this->registerMeta([\n" +" 'name' => 'description',\n" +" 'content' => 'Original description'\n" +"], 'description');\n" +"\n" +"// Este sobrescreve o anterior\n" +"$this->registerMeta([\n" +" 'name' => 'description', \n" +" 'content' => 'Updated description'\n" +"], 'description');\n" + +#. type: Title ## +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Link tags" +msgstr "Link tags" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Basic Link Tags" +msgstr "Link tags básicas" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "Register various types of link tags:" +msgstr "Registre vários tipos de link tags:" + +#. type: Fenced code block (php) +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "" +"// Favicon\n" +"$this->registerLink([\n" +" 'rel' => 'icon',\n" +" 'type' => 'image/png',\n" +" 'href' => '/favicon.png',\n" +"]);\n" +"\n" +"// RSS feed\n" +"$this->registerLink([\n" +" 'rel' => 'alternate',\n" +" 'type' => 'application/rss+xml',\n" +" 'title' => 'RSS Feed',\n" +" 'href' => '/feed.rss',\n" +"]);\n" +"\n" +"// Canonical URL\n" +"$this->registerLink([\n" +" 'rel' => 'canonical',\n" +" 'href' => 'https://example.com/canonical-url',\n" +"]);\n" +"\n" +"// Preload resources\n" +"$this->registerLink([\n" +" 'rel' => 'preload',\n" +" 'href' => '/fonts/main.woff2',\n" +" 'as' => 'font',\n" +" 'type' => 'font/woff2',\n" +" 'crossorigin' => 'anonymous',\n" +"]);\n" +msgstr "" +"// Favicon\n" +"$this->registerLink([\n" +" 'rel' => 'icon',\n" +" 'type' => 'image/png',\n" +" 'href' => '/favicon.png',\n" +"]);\n" +"\n" +"// Feed RSS\n" +"$this->registerLink([\n" +" 'rel' => 'alternate',\n" +" 'type' => 'application/rss+xml',\n" +" 'title' => 'RSS Feed',\n" +" 'href' => '/feed.rss',\n" +"]);\n" +"\n" +"// URL canônica\n" +"$this->registerLink([\n" +" 'rel' => 'canonical',\n" +" 'href' => 'https://example.com/canonical-url',\n" +"]);\n" +"\n" +"// Pré-carregamento de recursos\n" +"$this->registerLink([\n" +" 'rel' => 'preload',\n" +" 'href' => '/fonts/main.woff2',\n" +" 'as' => 'font',\n" +" 'type' => 'font/woff2',\n" +" 'crossorigin' => 'anonymous',\n" +"]);\n" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Using Link Tag Objects" +msgstr "Usando objetos de link tag" + +#. type: Fenced code block (php) +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "" +"use Yiisoft\\Html\\Html;\n" +"\n" +"// CSS stylesheet\n" +"$this->registerLinkTag(\n" +" Html::link('/css/main.css', [\n" +" 'rel' => 'stylesheet',\n" +" ])\n" +");\n" +"\n" +"// DNS prefetch\n" +"$this->registerLinkTag(\n" +" Html::link('https://fonts.googleapis.com', [\n" +" 'rel' => 'dns-prefetch',\n" +" ])\n" +");\n" +msgstr "" +"use Yiisoft\\Html\\Html;\n" +"\n" +"// Folha de estilo CSS\n" +"$this->registerLinkTag(\n" +" Html::link('/css/main.css', [\n" +" 'rel' => 'stylesheet',\n" +" ])\n" +");\n" +"\n" +"// Prefetch de DNS\n" +"$this->registerLinkTag(\n" +" Html::link('https://fonts.googleapis.com', [\n" +" 'rel' => 'dns-prefetch',\n" +" ])\n" +");\n" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Complete Page Setup" +msgstr "Configuração completa de uma página" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "Here's how you might set up a complete page with all types of resources:" +msgstr "Veja como montar uma página completa com todos os tipos de recursos:" + +#. type: Fenced code block (php) +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "" +"setTitle($title);\n" +"\n" +"// Meta tags\n" +"$this->registerMeta(['name' => 'description', 'content' => $description]);\n" +"$this->registerMeta(['name' => 'keywords', 'content' => 'ecommerce, products, online shop']);\n" +"\n" +"// Open Graph tags\n" +"$this->registerMeta(['property' => 'og:title', 'content' => $title]);\n" +"$this->registerMeta(['property' => 'og:description', 'content' => $description]);\n" +"$this->registerMeta(['property' => 'og:image', 'content' => $product['image']]);\n" +"\n" +"// CSS files\n" +"$this->registerCssFile('/css/product.css');\n" +"$this->registerCssFile('/css/responsive.css', WebView::POSITION_HEAD, [\n" +" 'media' => 'screen and (max-width: 768px)',\n" +"]);\n" +"\n" +"// JavaScript files\n" +"$this->registerJsFile('/js/product-gallery.js', WebView::POSITION_END);\n" +"$this->registerJsFile('/js/shopping-cart.js', WebView::POSITION_END);\n" +"\n" +"// JavaScript variables\n" +"$this->registerJsVar('productData', $product);\n" +"$this->registerJsVar('cartApiUrl', '/api/cart');\n" +"\n" +"// Inline JavaScript\n" +"$this->registerJs('\n" +" document.addEventListener(\"DOMContentLoaded\", function() {\n" +" initProductGallery();\n" +" initShoppingCart();\n" +" });\n" +"', WebView::POSITION_END);\n" +"\n" +"// Page-specific styles\n" +"$this->registerCss('\n" +" .product-special {\n" +" background: linear-gradient(45deg, #ff6b6b, #4ecdc4);\n" +" padding: 20px;\n" +" border-radius: 10px;\n" +" }\n" +"', WebView::POSITION_HEAD);\n" +"?>\n" +"\n" +"
\n" +" \n" +"
\n" +msgstr "" +"setTitle($title);\n" +"\n" +"// Meta tags\n" +"$this->registerMeta(['name' => 'description', 'content' => $description]);\n" +"$this->registerMeta(['name' => 'keywords', 'content' => 'ecommerce, products, online shop']);\n" +"\n" +"// Tags Open Graph\n" +"$this->registerMeta(['property' => 'og:title', 'content' => $title]);\n" +"$this->registerMeta(['property' => 'og:description', 'content' => $description]);\n" +"$this->registerMeta(['property' => 'og:image', 'content' => $product['image']]);\n" +"\n" +"// Arquivos CSS\n" +"$this->registerCssFile('/css/product.css');\n" +"$this->registerCssFile('/css/responsive.css', WebView::POSITION_HEAD, [\n" +" 'media' => 'screen and (max-width: 768px)',\n" +"]);\n" +"\n" +"// Arquivos JavaScript\n" +"$this->registerJsFile('/js/product-gallery.js', WebView::POSITION_END);\n" +"$this->registerJsFile('/js/shopping-cart.js', WebView::POSITION_END);\n" +"\n" +"// Variáveis JavaScript\n" +"$this->registerJsVar('productData', $product);\n" +"$this->registerJsVar('cartApiUrl', '/api/cart');\n" +"\n" +"// JavaScript inline\n" +"$this->registerJs('\n" +" document.addEventListener(\"DOMContentLoaded\", function() {\n" +" initProductGallery();\n" +" initShoppingCart();\n" +" });\n" +"', WebView::POSITION_END);\n" +"\n" +"// Estilos específicos da página\n" +"$this->registerCss('\n" +" .product-special {\n" +" background: linear-gradient(45deg, #ff6b6b, #4ecdc4);\n" +" padding: 20px;\n" +" border-radius: 10px;\n" +" }\n" +"', WebView::POSITION_HEAD);\n" +"?>\n" +"\n" +"
\n" +" \n" +"
\n" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Conditional Resource Loading" +msgstr "Carregamento condicional de recursos" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "Load resources based on conditions:" +msgstr "Carregue recursos de acordo com condições:" + +#. type: Fenced code block (php) +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "" +"registerCssFile('/css/dark-theme.css');\n" +"} else {\n" +" $this->registerCssFile('/css/light-theme.css');\n" +"}\n" +"\n" +"// Admin-specific resources\n" +"if ($isAdmin) {\n" +" $this->registerCssFile('/css/admin-toolbar.css');\n" +" $this->registerJsFile('/js/admin-functions.js');\n" +"}\n" +"\n" +"// Role-based JavaScript configuration\n" +"$this->registerJsVar('userPermissions', [\n" +" 'canEdit' => in_array($userRole, ['admin', 'editor']),\n" +" 'canDelete' => $userRole === 'admin',\n" +" 'canPublish' => in_array($userRole, ['admin', 'publisher']),\n" +"]);\n" +"?>\n" +msgstr "" +"registerCssFile('/css/dark-theme.css');\n" +"} else {\n" +" $this->registerCssFile('/css/light-theme.css');\n" +"}\n" +"\n" +"// Recursos específicos da área admin\n" +"if ($isAdmin) {\n" +" $this->registerCssFile('/css/admin-toolbar.css');\n" +" $this->registerJsFile('/js/admin-functions.js');\n" +"}\n" +"\n" +"// Configuração JavaScript baseada no papel do usuário\n" +"$this->registerJsVar('userPermissions', [\n" +" 'canEdit' => in_array($userRole, ['admin', 'editor']),\n" +" 'canDelete' => $userRole === 'admin',\n" +" 'canPublish' => in_array($userRole, ['admin', 'publisher']),\n" +"]);\n" +"?>\n" + +#. type: Bullet: '1. ' +#: ../src/guide/views/script-style-meta.md +msgid "**Use appropriate positions**: Place CSS in `POSITION_HEAD`, JavaScript at `POSITION_END`" +msgstr "**Use as posições adequadas**: coloque o CSS em `POSITION_HEAD` e o JavaScript em `POSITION_END`" + +#. type: Bullet: '2. ' +#: ../src/guide/views/script-style-meta.md +msgid "**Minimize inline resources**: Prefer external files for better caching" +msgstr "**Reduza os recursos inline**: prefira arquivos externos, que aproveitam melhor o cache" + +#. type: Bullet: '3. ' +#: ../src/guide/views/script-style-meta.md +msgid "**Use keys for duplicates**: Prevent duplicate resources with meaningful keys" +msgstr "**Use chaves contra duplicatas**: evite recursos duplicados com chaves significativas" + +#. type: Bullet: '4. ' +#: ../src/guide/views/script-style-meta.md +msgid "**Optimize loading**: Use `async` and `defer` attributes for non-critical JavaScript" +msgstr "**Otimize o carregamento**: use os atributos `async` e `defer` para JavaScript não crítico" + +#. type: Bullet: '5. ' +#: ../src/guide/views/script-style-meta.md +msgid "**Group related resources**: Keep related CSS and JS files together" +msgstr "**Agrupe recursos relacionados**: mantenha juntos os arquivos CSS e JS relacionados" + +#. type: Bullet: '6. ' +#: ../src/guide/views/script-style-meta.md +msgid "**Use CDNs wisely**: Balance performance with reliability" +msgstr "**Use CDNs com critério**: equilibre desempenho e confiabilidade" + +#. type: Bullet: '7. ' +#: ../src/guide/views/script-style-meta.md +msgid "**Validate meta tags**: Ensure proper SEO meta tags are set" +msgstr "**Valide as meta tags**: garanta que as meta tags de SEO estejam definidas corretamente" + +#. type: Bullet: '8. ' +#: ../src/guide/views/script-style-meta.md +msgid "**Consider security**: Be careful with inline scripts and CSP policies" +msgstr "**Pense na segurança**: tenha cuidado com scripts inline e políticas de CSP" + +#. type: Title ## +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Working with Asset Bundles" +msgstr "Trabalhando com asset bundles" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "For more complex asset management, consider using asset bundles:" +msgstr "Para um gerenciamento de assets mais complexo, considere usar asset bundles:" + +#. type: Fenced code block (php) +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "" +"// Register an asset bundle (covered in detail in the Assets guide)\n" +"$assetBundle = $this->assetManager->register(MainAsset::class);\n" +"\n" +"// Add all CSS files from the bundle\n" +"$this->addCssFiles($this->assetManager->getCssFiles());\n" +"\n" +"// Add all JavaScript files from the bundle \n" +"$this->addJsFiles($this->assetManager->getJsFiles());\n" +msgstr "" +"// Registra um asset bundle (explicado em detalhes no guia de Assets)\n" +"$assetBundle = $this->assetManager->register(MainAsset::class);\n" +"\n" +"// Adiciona todos os arquivos CSS do bundle\n" +"$this->addCssFiles($this->assetManager->getCssFiles());\n" +"\n" +"// Adiciona todos os arquivos JavaScript do bundle \n" +"$this->addJsFiles($this->assetManager->getJsFiles());\n" diff --git a/_translations/po/pt-BR/guide_views_template-engines.md.po b/_translations/po/pt-BR/guide_views_template-engines.md.po new file mode 100644 index 00000000..cd505f78 --- /dev/null +++ b/_translations/po/pt-BR/guide_views_template-engines.md.po @@ -0,0 +1,482 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-01-26 18:48+0000\n" +"PO-Revision-Date: 2026-01-26 18:48+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/guide/views/asset.md ../src/guide/views/script-style-meta.md ../src/guide/views/template-engines.md +#, no-wrap +msgid "Best Practices" +msgstr "Boas práticas" + +#. type: Title # +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "Template engines" +msgstr "Template engines" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +msgid "Yii3 supports multiple template engines through a flexible renderer system. By default, PHP is used as the template engine, but you can easily add support for other engines like Twig and [Blade](https://github.com/lee-to/yii-blade), or create your own custom renderers." +msgstr "O Yii3 suporta várias template engines por meio de um sistema flexível de renderers. Por padrão, o PHP é usado como template engine, mas você pode adicionar suporte a outras engines como Twig e [Blade](https://github.com/lee-to/yii-blade), ou criar seus próprios renderers." + +#. type: Plain text +#: ../src/guide/views/template-engines.md +msgid "PHP templates were described in the \"[View](view.md)\" guide section." +msgstr "Os templates PHP foram descritos na seção \"[View](view.md)\" do guia." + +#. type: Title ## +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "Twig Template Engine" +msgstr "Template engine Twig" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +msgid "Twig is a modern template engine that provides a more designer-friendly syntax. To use Twig in your Yii3 application, you need to install the Twig extension." +msgstr "O Twig é uma template engine moderna, com uma sintaxe mais amigável para designers. Para usar o Twig na sua aplicação Yii3, instale a extensão do Twig." + +#. type: Fenced code block (bash) +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "composer require yiisoft/view-twig\n" +msgstr "composer require yiisoft/view-twig\n" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +msgid "Now you can use `.twig` templates. For example, `views/site/about.twig`:" +msgstr "Agora você pode usar templates `.twig`. Por exemplo, `views/site/about.twig`:" + +#. type: Fenced code block (twig) +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "" +"{# Variable type hints for IDE support #}\n" +"{# @var user \\App\\Entity\\User #}\n" +"{# @var posts \\App\\Entity\\Post[] #}\n" +"\n" +"
\n" +"

{{ user.name }}

\n" +"

Email: {{ user.email }}

\n" +" \n" +" {% if posts is not empty %}\n" +"

Recent Posts

\n" +"
    \n" +" {% for post in posts %}\n" +"
  • \n" +"

    {{ post.title }}

    \n" +"

    {{ post.excerpt }}

    \n" +" \n" +"
  • \n" +" {% endfor %}\n" +"
\n" +" {% else %}\n" +"

No posts available.

\n" +" {% endif %}\n" +"
\n" +msgstr "" +"{# Dicas de tipo das variáveis para suporte na IDE #}\n" +"{# @var user \\App\\Entity\\User #}\n" +"{# @var posts \\App\\Entity\\Post[] #}\n" +"\n" +"
\n" +"

{{ user.name }}

\n" +"

Email: {{ user.email }}

\n" +" \n" +" {% if posts is not empty %}\n" +"

Recent Posts

\n" +"
    \n" +" {% for post in posts %}\n" +"
  • \n" +"

    {{ post.title }}

    \n" +"

    {{ post.excerpt }}

    \n" +" \n" +"
  • \n" +" {% endfor %}\n" +"
\n" +" {% else %}\n" +"

No posts available.

\n" +" {% endif %}\n" +"
\n" + +#. type: Title ### +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "Twig Features" +msgstr "Recursos do Twig" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "**Automatic Escaping**: Twig automatically escapes variables for HTML context:\n" +msgstr "**Escape automático**: o Twig escapa as variáveis automaticamente para o contexto HTML:\n" + +#. type: Fenced code block (twig) +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "" +"{# Automatically escaped #}\n" +"

{{ title }}

\n" +"\n" +"{# Raw output (use carefully) #}\n" +"
{{ content|raw }}
\n" +msgstr "" +"{# Escapado automaticamente #}\n" +"

{{ title }}

\n" +"\n" +"{# Saída bruta (use com cuidado) #}\n" +"
{{ content|raw }}
\n" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "**Filters and Functions**: Twig provides many built-in filters and functions:\n" +msgstr "**Filtros e funções**: o Twig oferece muitos filtros e funções nativos:\n" + +#. type: Fenced code block (twig) +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "" +"{# Date formatting #}\n" +"\n" +"\n" +"{# String manipulation #}\n" +"

{{ description|truncate(100) }}

\n" +"\n" +"{# URL generation #}\n" +"Profile\n" +msgstr "" +"{# Formatação de data #}\n" +"\n" +"\n" +"{# Manipulação de strings #}\n" +"

{{ description|truncate(100) }}

\n" +"\n" +"{# Geração de URLs #}\n" +"Profile\n" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "**Template Inheritance**: Twig supports template inheritance:\n" +msgstr "**Herança de templates**: o Twig suporta herança de templates:\n" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "**views/layout/main.twig**\n" +msgstr "**views/layout/main.twig**\n" + +#. type: Fenced code block (twig) +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "" +"\n" +"\n" +"\n" +" {% block title %}Default Title{% endblock %}\n" +"\n" +"\n" +"
\n" +" {% block content %}{% endblock %}\n" +"
\n" +"\n" +"\n" +msgstr "" +"\n" +"\n" +"\n" +" {% block title %}Default Title{% endblock %}\n" +"\n" +"\n" +"
\n" +" {% block content %}{% endblock %}\n" +"
\n" +"\n" +"\n" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "**views/site/about.twig**\n" +msgstr "**views/site/about.twig**\n" + +#. type: Fenced code block (twig) +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "" +"{% extends \"layout/main.twig\" %}\n" +"\n" +"{% block title %}About Us{% endblock %}\n" +"\n" +"{% block content %}\n" +"

About Our Company

\n" +"

Welcome to our website!

\n" +"{% endblock %}\n" +msgstr "" +"{% extends \"layout/main.twig\" %}\n" +"\n" +"{% block title %}About Us{% endblock %}\n" +"\n" +"{% block content %}\n" +"

About Our Company

\n" +"

Welcome to our website!

\n" +"{% endblock %}\n" + +#. type: Title ### +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "Rendering Twig Templates" +msgstr "Renderizando templates Twig" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +msgid "Use Twig templates the same way as PHP templates:" +msgstr "Use templates Twig da mesma forma que templates PHP:" + +#. type: Fenced code block (php) +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "" +"// In your controller\n" +"public function about(): ResponseInterface\n" +"{\n" +" return $this->viewRenderer->render('about.twig', [\n" +" 'user' => $this->getCurrentUser(),\n" +" 'posts' => $this->getRecentPosts(),\n" +" ]);\n" +"}\n" +msgstr "" +"// No seu controller\n" +"public function about(): ResponseInterface\n" +"{\n" +" return $this->viewRenderer->render('about.twig', [\n" +" 'user' => $this->getCurrentUser(),\n" +" 'posts' => $this->getRecentPosts(),\n" +" ]);\n" +"}\n" + +#. type: Title ## +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "Custom Template Engines" +msgstr "Template engines personalizadas" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +msgid "You can create custom template engines by implementing the `TemplateRendererInterface`:" +msgstr "Você pode criar template engines personalizadas implementando a `TemplateRendererInterface`:" + +#. type: Fenced code block (php) +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "" +" $value) {\n" +" $content = str_replace(\"{{$key}}\", (string) $value, $content);\n" +" }\n" +" \n" +" return $this->parser->parse($content);\n" +" }\n" +"}\n" +msgstr "" +" $value) {\n" +" $content = str_replace(\"{{$key}}\", (string) $value, $content);\n" +" }\n" +" \n" +" return $this->parser->parse($content);\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +msgid "Register your custom renderer:" +msgstr "Registre o seu renderer personalizado:" + +#. type: Fenced code block (php) +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "" +"use Yiisoft\\Container\\Reference;\n" +"\n" +"// In configuration\n" +"'yiisoft/view' => [\n" +" 'renderers' => [\n" +" 'md' => Reference::to(App\\View\\MarkdownRenderer::class),\n" +" ],\n" +"],\n" +msgstr "" +"use Yiisoft\\Container\\Reference;\n" +"\n" +"// Na configuração\n" +"'yiisoft/view' => [\n" +" 'renderers' => [\n" +" 'md' => Reference::to(App\\View\\MarkdownRenderer::class),\n" +" ],\n" +"],\n" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +msgid "Now you can use `.md` template files:" +msgstr "Agora você pode usar arquivos de template `.md`:" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "**views/content/help.md**\n" +msgstr "**views/content/help.md**\n" + +#. type: Fenced code block (markdown) +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "" +"# Help: {{title}}\n" +"\n" +"Welcome, {{username}}!\n" +"\n" +"This is a Markdown template with **bold** and *italic* text.\n" +"\n" +"- Feature 1\n" +"- Feature 2\n" +"- Feature 3\n" +msgstr "" +"# Help: {{title}}\n" +"\n" +"Welcome, {{username}}!\n" +"\n" +"This is a Markdown template with **bold** and *italic* text.\n" +"\n" +"- Feature 1\n" +"- Feature 2\n" +"- Feature 3\n" + +#. type: Title ## +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "Choosing the Right Template Engine" +msgstr "Escolhendo a template engine certa" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "" +"**Use PHP templates when:**\n" +"- You need maximum flexibility and performance\n" +"- Your team is comfortable with PHP\n" +"- You want to leverage existing PHP knowledge\n" +"- You need complex logic in templates (though this should be minimized)\n" +msgstr "" +"**Use templates PHP quando:**\n" +"- Você precisa do máximo de flexibilidade e desempenho\n" +"- Seu time está à vontade com PHP\n" +"- Você quer aproveitar o conhecimento de PHP que já tem\n" +"- Você precisa de lógica complexa nos templates (embora isso deva ser minimizado)\n" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "" +"**Use Twig templates when:**\n" +"- You want stricter separation between logic and presentation\n" +"- You work with designers who prefer cleaner syntax\n" +"- You need automatic escaping and security features\n" +"- You want template inheritance and advanced features\n" +msgstr "" +"**Use templates Twig quando:**\n" +"- Você quer uma separação mais rígida entre lógica e apresentação\n" +"- Você trabalha com designers que preferem uma sintaxe mais limpa\n" +"- Você precisa de escape automático e recursos de segurança\n" +"- Você quer herança de templates e recursos avançados\n" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "" +"**Use custom templates when:**\n" +"- You have specific requirements not met by PHP or Twig\n" +"- You're working with specialized content formats\n" +"- You need integration with external template systems\n" +msgstr "" +"**Use templates personalizados quando:**\n" +"- Você tem requisitos específicos que o PHP ou o Twig não atendem\n" +"- Você trabalha com formatos de conteúdo especializados\n" +"- Você precisa integrar com sistemas de template externos\n" + +#. type: Bullet: '1. ' +#: ../src/guide/views/template-engines.md +msgid "**Keep templates simple**: Move complex logic to controllers or services" +msgstr "**Mantenha os templates simples**: leve a lógica complexa para controllers ou serviços" + +#. type: Bullet: '2. ' +#: ../src/guide/views/template-engines.md +msgid "**Always escape output**: Prevent XSS attacks by properly escaping variables" +msgstr "**Sempre escape a saída**: evite ataques XSS escapando as variáveis corretamente" + +#. type: Bullet: '3. ' +#: ../src/guide/views/template-engines.md +msgid "**Use meaningful names**: Name your templates and variables clearly" +msgstr "**Use nomes significativos**: dê nomes claros aos seus templates e variáveis" + +#. type: Bullet: '4. ' +#: ../src/guide/views/template-engines.md +msgid "**Organize templates**: Group related templates in subdirectories" +msgstr "**Organize os templates**: agrupe templates relacionados em subdiretórios" + +#. type: Bullet: '5. ' +#: ../src/guide/views/template-engines.md +msgid "**Document variables**: Always add type hints for better IDE support" +msgstr "**Documente as variáveis**: sempre adicione dicas de tipo para um suporte melhor da IDE" + +#. type: Bullet: '6. ' +#: ../src/guide/views/template-engines.md +msgid "**Avoid business logic**: Keep business logic in models and services" +msgstr "**Evite lógica de negócio**: mantenha a lógica de negócio em models e serviços" diff --git a/_translations/po/pt-BR/guide_views_view-injections.md.po b/_translations/po/pt-BR/guide_views_view-injections.md.po new file mode 100644 index 00000000..637cb09f --- /dev/null +++ b/_translations/po/pt-BR/guide_views_view-injections.md.po @@ -0,0 +1,238 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 13:00+0000\n" +"PO-Revision-Date: 2025-12-24 13:00+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/sentry-integration.md ../src/guide/concept/configuration.md ../src/guide/tutorial/using-yii-with-roadrunner.md ../src/guide/views/view-injections.md +#, no-wrap +msgid "Configuration" +msgstr "Configuração" + +#. type: Title # +#: ../src/guide/views/view-injections.md +#, no-wrap +msgid "View injections" +msgstr "Injeções de view" + +#. type: Plain text +#: ../src/guide/views/view-injections.md +msgid "The view injections are designed to provide a standardized way to pass parameters to the common layer of views in an application. It allows developers to manage the data that will be available across various views, ensuring flexibility and reusability of code." +msgstr "As injeções de view oferecem uma forma padronizada de passar parâmetros para a camada comum das views de uma aplicação. Com elas, você gerencia os dados que ficarão disponíveis em várias views, o que garante flexibilidade e reaproveitamento de código." + +#. type: Plain text +#: ../src/guide/views/view-injections.md +msgid "The view injections could be used if you require `yiisoft/yii-view-renderer` package:" +msgstr "Você pode usar as injeções de view se a sua aplicação exige o pacote `yiisoft/yii-view-renderer`:" + +#. type: Fenced code block (sh) +#: ../src/guide/views/view-injections.md ../src/guide/views/view.md +#, no-wrap +msgid "composer require yiisoft/yii-view-renderer\n" +msgstr "composer require yiisoft/yii-view-renderer\n" + +#. type: Plain text +#: ../src/guide/views/view-injections.md +msgid "In config `params.php`:" +msgstr "Na configuração `params.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/views/view-injections.md +#, no-wrap +msgid "" +"...\n" +"'yiisoft/yii-view' => [\n" +" 'injections' => [\n" +" Reference::to(ContentViewInjection::class),\n" +" Reference::to(CsrfViewInjection::class),\n" +" Reference::to(LayoutViewInjection::class),\n" +" ],\n" +" ],\n" +msgstr "" +"...\n" +"'yiisoft/yii-view' => [\n" +" 'injections' => [\n" +" Reference::to(ContentViewInjection::class),\n" +" Reference::to(CsrfViewInjection::class),\n" +" Reference::to(LayoutViewInjection::class),\n" +" ],\n" +" ],\n" + +#. type: Title ## +#: ../src/guide/views/view-injections.md +#, no-wrap +msgid "New injections" +msgstr "Novas injeções" + +#. type: Plain text +#: ../src/guide/views/view-injections.md +msgid "Start by defining a class that will implement the `Yiisoft\\Yii\\View\\Renderer\\CommonParametersInjectionInterface`. This class will be responsible for providing the parameters you want to inject into your view templates and layouts." +msgstr "Comece definindo uma classe que implemente `Yiisoft\\Yii\\View\\Renderer\\CommonParametersInjectionInterface`. Essa classe fornece os parâmetros que você quer injetar nos templates de view e nos layouts." + +#. type: Fenced code block (php) +#: ../src/guide/views/view-injections.md +#, no-wrap +msgid "" +"class MyCustomParametersInjection implements Yiisoft\\Yii\\View\\Renderer\\CommonParametersInjectionInterface\n" +"{\n" +" // Class properties and methods will go here\n" +"\n" +" public function __construct(UserService $userService)\n" +" {\n" +" $this->userService = $userService;\n" +" }\n" +"\n" +" public function getCommonParameters(): array\n" +" {\n" +" return [\n" +" 'siteName' => 'My Awesome Site',\n" +" 'currentYear' => date('Y'),\n" +" 'user' => $this->userService->getCurrentUser(),\n" +" ];\n" +" }\n" +"}\n" +msgstr "" +"class MyCustomParametersInjection implements Yiisoft\\Yii\\View\\Renderer\\CommonParametersInjectionInterface\n" +"{\n" +" // As propriedades e os métodos da classe ficam aqui\n" +"\n" +" public function __construct(UserService $userService)\n" +" {\n" +" $this->userService = $userService;\n" +" }\n" +"\n" +" public function getCommonParameters(): array\n" +" {\n" +" return [\n" +" 'siteName' => 'My Awesome Site',\n" +" 'currentYear' => date('Y'),\n" +" 'user' => $this->userService->getCurrentUser(),\n" +" ];\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/views/view-injections.md +msgid "Add your new Injection to `params.php`:" +msgstr "Adicione a nova injeção ao `params.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/views/view-injections.md +#, no-wrap +msgid "" +"'yiisoft/yii-view' => [\n" +" 'injections' => [\n" +" ...,\n" +" Reference::to(MyCustomParametersInjection::class),\n" +" ],\n" +" ],\n" +msgstr "" +"'yiisoft/yii-view' => [\n" +" 'injections' => [\n" +" ...,\n" +" Reference::to(MyCustomParametersInjection::class),\n" +" ],\n" +" ],\n" + +#. type: Title ## +#: ../src/guide/views/view-injections.md +#, no-wrap +msgid "Using Separate Injections for Different Layouts" +msgstr "Usando injeções separadas para layouts diferentes" + +#. type: Plain text +#: ../src/guide/views/view-injections.md +msgid "If your application has multiple layouts, you can create separate parameter injections for each layout. This approach allows you to tailor the parameters injected into each layout according to its specific needs, enhancing the flexibility and maintainability of your application." +msgstr "Se a sua aplicação tem vários layouts, você pode criar injeções de parâmetros separadas para cada um. Assim, os parâmetros injetados em cada layout atendem às necessidades específicas dele, o que deixa a aplicação mais flexível e fácil de manter." + +#. type: Plain text +#: ../src/guide/views/view-injections.md +msgid "Create your custom ViewInjection for a specific layout:" +msgstr "Crie a sua ViewInjection personalizada para um layout específico:" + +#. type: Fenced code block (php) +#: ../src/guide/views/view-injections.md +#, no-wrap +msgid "" +"readonly final class CartViewInjection implements CommonParametersInjectionInterface\n" +"{\n" +" public function __construct(private Cart $cart)\n" +" {\n" +" }\n" +"\n" +" public function getCommonParameters(): array\n" +" {\n" +" return [\n" +" 'cart' => $this->cart,\n" +" ];\n" +" }\n" +"}\n" +msgstr "" +"readonly final class CartViewInjection implements CommonParametersInjectionInterface\n" +"{\n" +" public function __construct(private Cart $cart)\n" +" {\n" +" }\n" +"\n" +" public function getCommonParameters(): array\n" +" {\n" +" return [\n" +" 'cart' => $this->cart,\n" +" ];\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/views/view-injections.md +msgid "Add your new injection to `params.php` under specific layout name. In the following example, it's `@layout/cart`:" +msgstr "Adicione a nova injeção ao `params.php` sob o nome de um layout específico. No exemplo a seguir, é `@layout/cart`:" + +#. type: Fenced code block (php) +#: ../src/guide/views/view-injections.md +#, no-wrap +msgid "" +"'yiisoft/yii-view' => [\n" +" 'injections' => [\n" +" ...,\n" +" Reference::to(MyCustomParametersInjection::class),\n" +" DynamicReference::to(static function (ContainerInterface $container) {\n" +" $cart = $container\n" +" ->get(Cart::class);\n" +"\n" +" return new LayoutSpecificInjections(\n" +" '@layout/cart', // layout name for injection\n" +"\n" +" new CartViewInjection($cart)\n" +" );\n" +" }),\n" +" ],\n" +" ],\n" +msgstr "" +"'yiisoft/yii-view' => [\n" +" 'injections' => [\n" +" ...,\n" +" Reference::to(MyCustomParametersInjection::class),\n" +" DynamicReference::to(static function (ContainerInterface $container) {\n" +" $cart = $container\n" +" ->get(Cart::class);\n" +"\n" +" return new LayoutSpecificInjections(\n" +" '@layout/cart', // nome do layout para a injeção\n" +"\n" +" new CartViewInjection($cart)\n" +" );\n" +" }),\n" +" ],\n" +" ],\n" diff --git a/_translations/po/pt-BR/guide_views_view.md.po b/_translations/po/pt-BR/guide_views_view.md.po new file mode 100644 index 00000000..921406e7 --- /dev/null +++ b/_translations/po/pt-BR/guide_views_view.md.po @@ -0,0 +1,638 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-02-25 03:25+0000\n" +"PO-Revision-Date: 2026-02-25 03:25+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/making-http-requests.md ../src/cookbook/sentry-integration.md ../src/guide/tutorial/using-yii-with-roadrunner.md ../src/guide/tutorial/using-yii-with-swoole.md ../src/guide/views/asset.md ../src/guide/views/view.md ../src/guide/views/widget.md +#, no-wrap +msgid "Installation" +msgstr "Instalação" + +#. type: Title # +#: ../src/guide/index.md ../src/guide/views/view.md +#, no-wrap +msgid "Views" +msgstr "Views" + +#. type: Fenced code block (php) +#: ../src/guide/start/hello.md ../src/guide/views/view.md +#, no-wrap +msgid "" +"\n" +"\n" +"

The message is:

\n" +msgstr "" +"\n" +"\n" +"

The message is:

\n" + +#. type: Fenced code block (php) +#: ../src/guide/start/hello.md ../src/guide/views/view.md +#, no-wrap +msgid "" +"viewRenderer->render(__DIR__ . '/template', [\n" +" 'message' => $message,\n" +" ]);\n" +" }\n" +"}\n" +msgstr "" +"viewRenderer->render(__DIR__ . '/template', [\n" +" 'message' => $message,\n" +" ]);\n" +" }\n" +"}\n" + +#. type: Title ## +#: ../src/guide/views/asset.md ../src/guide/views/view.md ../src/guide/views/widget.md +#, no-wrap +msgid "Basic Concepts" +msgstr "Conceitos básicos" + +#. type: Fenced code block (sh) +#: ../src/guide/views/view-injections.md ../src/guide/views/view.md +#, no-wrap +msgid "composer require yiisoft/yii-view-renderer\n" +msgstr "composer require yiisoft/yii-view-renderer\n" + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "View is responsible for presenting data to end users. You give it a template with some placeholders and presentation logic and some data. The view is passing data to the template executing template logic. The end result is ready to be passed to end user, be it a browser, a file to download, an email to send or something else." +msgstr "A view é responsável por apresentar os dados ao usuário final. Você entrega a ela um template com alguns placeholders e lógica de apresentação, além de alguns dados. A view passa os dados para o template e executa a lógica do template. O resultado final está pronto para ser entregue ao usuário final, seja um navegador, um arquivo para download, um e-mail a ser enviado ou outra coisa." + +#. type: Fenced code block (mermaid) +#: ../src/guide/views/view.md +#, no-wrap +msgid "" +"flowchart LR\n" +" A[Data] --> V[View]\n" +" B[Template] --> V\n" +" V --> C[HTML]\n" +" C --> D[Browser]\n" +msgstr "" +"flowchart LR\n" +" A[Dados] --> V[View]\n" +" B[Template] --> V\n" +" V --> C[HTML]\n" +" C --> D[Navegador]\n" + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "In Yii3 views are typically PHP files that contain presentation logic and HTML markup. The view system provides a flexible way to organize your presentation layer and supports features like layouts and partial views. Instead of using plain PHP templates, you can leverage one of the template engines such as [Twig](template-engines.md) or [Blade](https://github.com/lee-to/yii-blade)." +msgstr "No Yii3, as views normalmente são arquivos PHP com lógica de apresentação e marcação HTML. O sistema de views oferece uma forma flexível de organizar a camada de apresentação e suporta recursos como layouts e views parciais. Em vez de templates PHP puros, você pode usar uma das template engines, como [Twig](template-engines.md) ou [Blade](https://github.com/lee-to/yii-blade)." + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "For basic view functionality, you need the `yiisoft/view` package:" +msgstr "Para a funcionalidade básica de views, você precisa do pacote `yiisoft/view`:" + +#. type: Fenced code block (sh) +#: ../src/guide/views/view.md +#, no-wrap +msgid "composer require yiisoft/view\n" +msgstr "composer require yiisoft/view\n" + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "For web applications, you should also install the `yiisoft/yii-view-renderer` package which provides [PSR-7](https://www.php-fig.org/psr/psr-7/) compatibility and web-specific features:" +msgstr "Em aplicações web, instale também o pacote `yiisoft/yii-view-renderer`, que oferece compatibilidade com [PSR-7](https://www.php-fig.org/psr/psr-7/) e recursos específicos para a web:" + +#. type: Plain text +#: ../src/guide/views/view.md ../src/guide/views/widget.md +msgid "These packages are included by default in the `yiisoft/app` application template." +msgstr "Esses pacotes já vêm incluídos por padrão no template de aplicação `yiisoft/app`." + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "A view template file contains presentation logic. In the `yiisoft/app` template, view files are typically stored alongside their controllers (e.g., `src/Web/Echo/Action.php`). Here's a simple view file example, `src/Web/Echo/template.php`:" +msgstr "Um arquivo de template de view contém lógica de apresentação. No template `yiisoft/app`, os arquivos de view normalmente ficam junto dos seus controllers (por exemplo, `src/Web/Echo/Action.php`). Este é um exemplo simples de arquivo de view, `src/Web/Echo/template.php`:" + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "Here `$message` is a view data that is passed when you render a template with the help of `WebViewRenderer`. For example, `src/Web/Echo/Action.php`:" +msgstr "Aqui, `$message` é um dado da view passado quando você renderiza um template com o `WebViewRenderer`. Por exemplo, `src/Web/Echo/Action.php`:" + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "First argument of the `render()` method is a path to the template file. In the `yiisoft/app`, template files are typically stored alongside their actions. The result is ready to be rendered to the browser so we return it immediately." +msgstr "O primeiro argumento do método `render()` é o caminho do arquivo de template. No `yiisoft/app`, os arquivos de template normalmente ficam junto das suas actions. O resultado já está pronto para ser enviado ao navegador, então o devolvemos imediatamente." + +#. type: Title ## +#: ../src/guide/views/view.md +#, no-wrap +msgid "Working with layouts" +msgstr "Trabalhando com layouts" + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "Most web applications use a common layout for all pages. In the `yiisoft/app` template, layouts are stored in `src/Web/Shared/Layout/Main/` directory. You can set a default layout in `config/common/params.php`:" +msgstr "A maioria das aplicações web usa um layout comum para todas as páginas. No template `yiisoft/app`, os layouts ficam no diretório `src/Web/Shared/Layout/Main/`. Você pode definir um layout padrão em `config/common/params.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/views/view.md +#, no-wrap +msgid "" +"return [\n" +" 'yiisoft/yii-view-renderer' => [\n" +" 'viewPath' => null,\n" +" 'layout' => '@src/Web/Shared/Layout/Main/layout.php',\n" +" ],\n" +"];\n" +msgstr "" +"return [\n" +" 'yiisoft/yii-view-renderer' => [\n" +" 'viewPath' => null,\n" +" 'layout' => '@src/Web/Shared/Layout/Main/layout.php',\n" +" ],\n" +"];\n" + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "A typical layout file such as `src/Web/Shared/Layout/Main/layout.php` looks like this:" +msgstr "Um arquivo de layout típico, como `src/Web/Shared/Layout/Main/layout.php`, tem esta cara:" + +#. type: Fenced code block (php) +#: ../src/guide/views/view.md +#, no-wrap +msgid "" +"register(MainAsset::class);\n" +"\n" +"$this->addCssFiles($assetManager->getCssFiles());\n" +"$this->addCssStrings($assetManager->getCssStrings());\n" +"$this->addJsFiles($assetManager->getJsFiles());\n" +"$this->addJsStrings($assetManager->getJsStrings());\n" +"$this->addJsVars($assetManager->getJsVars());\n" +"\n" +"$this->beginPage()\n" +"?>\n" +"\n" +"locale) ?>\">\n" +"\n" +" charset) ?>\">\n" +" \n" +" get('@baseUrl/favicon.svg') ?>\" type=\"image/svg+xml\">\n" +" <?= Html::encode($this->getTitle()) ?>\n" +" head() ?>\n" +"\n" +"\n" +"beginBody() ?>\n" +"\n" +"\n" +"\n" +"
\n" +" \n" +"
\n" +"\n" +"
\n" +" © name) ?> \n" +"
\n" +"\n" +"endBody() ?>\n" +"\n" +"\n" +"endPage() ?>\n" +msgstr "" +"register(MainAsset::class);\n" +"\n" +"$this->addCssFiles($assetManager->getCssFiles());\n" +"$this->addCssStrings($assetManager->getCssStrings());\n" +"$this->addJsFiles($assetManager->getJsFiles());\n" +"$this->addJsStrings($assetManager->getJsStrings());\n" +"$this->addJsVars($assetManager->getJsVars());\n" +"\n" +"$this->beginPage()\n" +"?>\n" +"\n" +"locale) ?>\">\n" +"\n" +" charset) ?>\">\n" +" \n" +" get('@baseUrl/favicon.svg') ?>\" type=\"image/svg+xml\">\n" +" <?= Html::encode($this->getTitle()) ?>\n" +" head() ?>\n" +"\n" +"\n" +"beginBody() ?>\n" +"\n" +"\n" +"\n" +"
\n" +" \n" +"
\n" +"\n" +"
\n" +" © name) ?> \n" +"
\n" +"\n" +"endBody() ?>\n" +"\n" +"\n" +"endPage() ?>\n" + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "In the template above `$applicationParams` is an array of parameters from `config/common/application.php`." +msgstr "No template acima, `$applicationParams` é um array de parâmetros de `config/common/application.php`." + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "`$aliases` refers to [aliases component](../concept/aliases.md) that is used to get the base URL of the application at the server for URLs." +msgstr "`$aliases` se refere ao [componente de aliases](../concept/aliases.md), usado para obter a URL base da aplicação no servidor para montar URLs." + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "`$this` is an instance of the view that we use to get page title and output assets. Both standard and custom." +msgstr "`$this` é uma instância da view que usamos para obter o título da página e gerar a saída dos assets, tanto os padrão quanto os personalizados." + +#. type: Plain text +#: ../src/guide/views/view.md +#, no-wrap +msgid "" +"With `$assetManager->register(MainAsset::class);` we register an asset that defines `css` to include to the page. It is\n" +"automatically copied to `public/assets` on first use. It is not very useful for a single CSS file but becomes handy as\n" +"the number of assets grows.\n" +msgstr "" +"Com `$assetManager->register(MainAsset::class);` registramos um asset que define o `css` a ser incluído na página. Ele é\n" +"copiado automaticamente para `public/assets` no primeiro uso. Isso não ajuda muito com um único arquivo CSS, mas se torna útil\n" +"conforme o número de assets cresce.\n" + +#. type: Plain text +#: ../src/guide/views/view.md +#, no-wrap +msgid "" +"> [!IMPORTANT]\n" +"> No output in plain PHP templates is encoded you should not forget to use `Html::encode()` to prevent\n" +"XSS security vulnerabilities.\n" +msgstr "" +"> [!IMPORTANT]\n" +"> Nenhuma saída em templates PHP puros é codificada, então não se esqueça de usar `Html::encode()` para evitar\n" +"vulnerabilidades de segurança do tipo XSS.\n" + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "More about what's available in layout could be read in [yiisoft/view](https://github.com/yiisoft/view) documentation." +msgstr "Você encontra mais detalhes sobre o que está disponível no layout na documentação do [yiisoft/view](https://github.com/yiisoft/view)." + +#. type: Title ### +#: ../src/guide/views/view.md +#, no-wrap +msgid "Rendering without layout" +msgstr "Renderizando sem layout" + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "Sometimes you need to render a view without a layout (for example, for AJAX responses):" +msgstr "Às vezes você precisa renderizar uma view sem layout (por exemplo, para respostas AJAX):" + +#. type: Fenced code block (php) +#: ../src/guide/views/view.md +#, no-wrap +msgid "" +"public function ajaxContent(): ResponseInterface\n" +"{\n" +" return $this->viewRenderer\n" +" ->withLayout(null)\n" +" ->render('ajax-content', ['data' => $data]);\n" +"}\n" +"\n" +"// Or use the renderPartial method\n" +"public function ajaxContent(): ResponseInterface\n" +"{\n" +" return $this->viewRenderer->renderPartial('ajax-content', ['data' => $data]);\n" +"}\n" +msgstr "" +"public function ajaxContent(): ResponseInterface\n" +"{\n" +" return $this->viewRenderer\n" +" ->withLayout(null)\n" +" ->render('ajax-content', ['data' => $data]);\n" +"}\n" +"\n" +"// Ou use o método renderPartial\n" +"public function ajaxContent(): ResponseInterface\n" +"{\n" +" return $this->viewRenderer->renderPartial('ajax-content', ['data' => $data]);\n" +"}\n" + +#. type: Title ## +#: ../src/guide/views/view.md +#, no-wrap +msgid "Nested Views and Partials" +msgstr "Views aninhadas e parciais" + +#. type: Title ### +#: ../src/guide/views/view.md +#, no-wrap +msgid "Rendering Sub-views" +msgstr "Renderizando sub-views" + +#. type: Plain text +#: ../src/guide/views/view.md +#, no-wrap +msgid "You can render other views from within a view using the `$this->render()` method:\n" +msgstr "Você pode renderizar outras views de dentro de uma view com o método `$this->render()`:\n" + +#. type: Fenced code block (php) +#: ../src/guide/views/view.md +#, no-wrap +msgid "" +"\n" +"
\n" +" \n" +" render('_post_item', ['post' => $post]) ?>\n" +" \n" +"
\n" +msgstr "" +"\n" +"
\n" +" \n" +" render('_post_item', ['post' => $post]) ?>\n" +" \n" +"
\n" + +#. type: Plain text +#: ../src/guide/views/view.md +#, no-wrap +msgid "**src/Web/Post/_item.php**\n" +msgstr "**src/Web/Post/_item.php**\n" + +#. type: Fenced code block (php) +#: ../src/guide/views/view.md +#, no-wrap +msgid "" +"\n" +"
\n" +"

getTitle()) ?>

\n" +"

getExcerpt()) ?>

\n" +" \n" +"
\n" +msgstr "" +"\n" +"
\n" +"

getTitle()) ?>

\n" +"

getExcerpt()) ?>

\n" +" \n" +"
\n" + +#. type: Title ### +#: ../src/guide/views/view.md +#, no-wrap +msgid "Using Blocks" +msgstr "Usando blocos" + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "Blocks allow you to define content in one view and display it in another, typically in layouts:" +msgstr "Os blocos permitem definir conteúdo em uma view e exibi-lo em outra, normalmente nos layouts:" + +#. type: Fenced code block (php) +#: ../src/guide/views/view.md +#, no-wrap +msgid "" +"// In a view file\n" +"setBlock('sidebar', $this->render('_sidebar', ['items' => $sidebarItems])) ?>\n" +"\n" +"// In the layout file\n" +"hasBlock('sidebar')): ?>\n" +" \n" +"\n" +msgstr "" +"// Em um arquivo de view\n" +"setBlock('sidebar', $this->render('_sidebar', ['items' => $sidebarItems])) ?>\n" +"\n" +"// No arquivo de layout\n" +"hasBlock('sidebar')): ?>\n" +" \n" +"\n" + +#. type: Title ## +#: ../src/guide/views/view.md +#, no-wrap +msgid "Rendering as String" +msgstr "Renderizando como string" + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "If you need the rendered content as a string instead of a PSR-7 response:" +msgstr "Se você precisa do conteúdo renderizado como string em vez de uma resposta PSR-7:" + +#. type: Fenced code block (php) +#: ../src/guide/views/view.md +#, no-wrap +msgid "" +"public function getEmailContent(): string\n" +"{\n" +" return $this->viewRenderer->renderAsString('email/welcome', [\n" +" 'user' => $user,\n" +" ]);\n" +"}\n" +msgstr "" +"public function getEmailContent(): string\n" +"{\n" +" return $this->viewRenderer->renderAsString('email/welcome', [\n" +" 'user' => $user,\n" +" ]);\n" +"}\n" + +#. type: Title ## +#: ../src/guide/views/view.md +#, no-wrap +msgid "View Events" +msgstr "Eventos de view" + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "The view system triggers events during the rendering process that you can listen to:" +msgstr "O sistema de views dispara eventos durante a renderização, e você pode escutá-los:" + +#. type: Fenced code block (php) +#: ../src/guide/views/view.md +#, no-wrap +msgid "" +"use Yiisoft\\View\\Event\\WebView\\BeforeRender;\n" +"use Yiisoft\\View\\Event\\WebView\\AfterRender;\n" +"\n" +"// Example event listener\n" +"final class ViewEventListener\n" +"{\n" +" public function onBeforeRender(BeforeRender $event): void\n" +" {\n" +" // Add global CSS class based on view name\n" +" if (str_contains($event->getFile(), 'admin/')) {\n" +" $event->getView()->registerCssClass('admin-view');\n" +" }\n" +" }\n" +"\n" +" public function onAfterRender(AfterRender $event): void\n" +" {\n" +" // Log rendering time\n" +" $this->logger->info('View rendered', [\n" +" 'view' => $event->getFile(),\n" +" 'time' => $event->getRenderTime(),\n" +" ]);\n" +" }\n" +"}\n" +msgstr "" +"use Yiisoft\\View\\Event\\WebView\\BeforeRender;\n" +"use Yiisoft\\View\\Event\\WebView\\AfterRender;\n" +"\n" +"// Exemplo de listener de eventos\n" +"final class ViewEventListener\n" +"{\n" +" public function onBeforeRender(BeforeRender $event): void\n" +" {\n" +" // Adiciona uma classe CSS global com base no nome da view\n" +" if (str_contains($event->getFile(), 'admin/')) {\n" +" $event->getView()->registerCssClass('admin-view');\n" +" }\n" +" }\n" +"\n" +" public function onAfterRender(AfterRender $event): void\n" +" {\n" +" // Registra no log o tempo de renderização\n" +" $this->logger->info('View rendered', [\n" +" 'view' => $event->getFile(),\n" +" 'time' => $event->getRenderTime(),\n" +" ]);\n" +" }\n" +"}\n" diff --git a/_translations/po/pt-BR/guide_views_widget.md.po b/_translations/po/pt-BR/guide_views_widget.md.po new file mode 100644 index 00000000..e18187ff --- /dev/null +++ b/_translations/po/pt-BR/guide_views_widget.md.po @@ -0,0 +1,1621 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 13:00+0000\n" +"PO-Revision-Date: 2025-12-24 13:00+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/cookbook/making-http-requests.md ../src/cookbook/sentry-integration.md ../src/guide/tutorial/using-yii-with-roadrunner.md ../src/guide/tutorial/using-yii-with-swoole.md ../src/guide/views/asset.md ../src/guide/views/view.md ../src/guide/views/widget.md +#, no-wrap +msgid "Installation" +msgstr "Instalação" + +#. type: Title ## +#: ../src/guide/views/asset.md ../src/guide/views/view.md ../src/guide/views/widget.md +#, no-wrap +msgid "Basic Concepts" +msgstr "Conceitos básicos" + +#. type: Plain text +#: ../src/guide/views/view.md ../src/guide/views/widget.md +msgid "These packages are included by default in the `yiisoft/app` application template." +msgstr "Esses pacotes já vêm incluídos por padrão no template de aplicação `yiisoft/app`." + +#. type: Title # +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Widgets" +msgstr "Widgets" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "Widgets are reusable, self-contained components that encapsulate complex HTML generation logic. They provide a clean way to create configurable UI elements that can be used across different views and applications. Yii3 provides a flexible widget system through the `yiisoft/widget` package." +msgstr "Widgets são componentes reutilizáveis e autocontidos que encapsulam uma lógica complexa de geração de HTML. Eles oferecem uma forma limpa de criar elementos de interface configuráveis, que podem ser usados em diferentes views e aplicações. O Yii3 oferece um sistema de widgets flexível por meio do pacote `yiisoft/widget`." + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "The widget functionality is provided by the `yiisoft/widget` package:" +msgstr "A funcionalidade de widgets vem do pacote `yiisoft/widget`:" + +#. type: Fenced code block (bash) +#: ../src/guide/views/widget.md +#, no-wrap +msgid "composer require yiisoft/widget\n" +msgstr "composer require yiisoft/widget\n" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "For ready-made widgets (like forms, navigation, etc.), you can also install:" +msgstr "Para widgets prontos (como formulários, navegação etc.), você também pode instalar:" + +#. type: Fenced code block (bash) +#: ../src/guide/views/widget.md +#, no-wrap +msgid "composer require yiisoft/yii-widgets\n" +msgstr "composer require yiisoft/yii-widgets\n" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Widget Class" +msgstr "Classe do widget" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "A widget is a PHP class that extends the abstract `Widget` class and implements a `render()` method that returns HTML content as a string." +msgstr "Um widget é uma classe PHP que estende a classe abstrata `Widget` e implementa um método `render()` que devolve o conteúdo HTML como string." + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Widget Factory" +msgstr "Widget factory" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "The `WidgetFactory` is responsible for creating widget instances and can inject dependencies through the DI container." +msgstr "A `WidgetFactory` é responsável por criar as instâncias dos widgets e pode injetar dependências por meio do container de DI." + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Widget Configuration" +msgstr "Configuração de widgets" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "Widgets can be configured with properties and methods, making them highly customizable and reusable across different contexts." +msgstr "Os widgets podem ser configurados com propriedades e métodos, o que os torna altamente personalizáveis e reutilizáveis em diferentes contextos." + +#. type: Title ## +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Creating Custom Widgets" +msgstr "Criando widgets próprios" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Simple Widget" +msgstr "Widget simples" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "Here's a basic widget that displays an alert message:" +msgstr "Este é um widget básico que exibe uma mensagem de alerta:" + +#. type: Fenced code block (php) +#: ../src/guide/views/widget.md +#, no-wrap +msgid "" +"message = $message;\n" +" return $new;\n" +" }\n" +"\n" +" public function type(string $type): self\n" +" {\n" +" $new = clone $this;\n" +" $new->type = $type;\n" +" return $new;\n" +" }\n" +"\n" +" public function closeable(bool $closeable = true): self\n" +" {\n" +" $new = clone $this;\n" +" $new->closeable = $closeable;\n" +" return $new;\n" +" }\n" +"\n" +" protected function render(): string\n" +" {\n" +" if (empty($this->message)) {\n" +" return '';\n" +" }\n" +"\n" +" $classes = ['alert', 'alert-' . $this->type];\n" +" \n" +" if ($this->closeable) {\n" +" $classes[] = 'alert-dismissible';\n" +" }\n" +"\n" +" $content = Html::encode($this->message);\n" +" \n" +" if ($this->closeable) {\n" +" $content .= Html::button('×', [\n" +" 'type' => 'button',\n" +" 'class' => 'btn-close',\n" +" 'data-bs-dismiss' => 'alert',\n" +" ]);\n" +" }\n" +"\n" +" return Html::div($content, ['class' => implode(' ', $classes)]);\n" +" }\n" +"}\n" +msgstr "" +"message = $message;\n" +" return $new;\n" +" }\n" +"\n" +" public function type(string $type): self\n" +" {\n" +" $new = clone $this;\n" +" $new->type = $type;\n" +" return $new;\n" +" }\n" +"\n" +" public function closeable(bool $closeable = true): self\n" +" {\n" +" $new = clone $this;\n" +" $new->closeable = $closeable;\n" +" return $new;\n" +" }\n" +"\n" +" protected function render(): string\n" +" {\n" +" if (empty($this->message)) {\n" +" return '';\n" +" }\n" +"\n" +" $classes = ['alert', 'alert-' . $this->type];\n" +" \n" +" if ($this->closeable) {\n" +" $classes[] = 'alert-dismissible';\n" +" }\n" +"\n" +" $content = Html::encode($this->message);\n" +" \n" +" if ($this->closeable) {\n" +" $content .= Html::button('×', [\n" +" 'type' => 'button',\n" +" 'class' => 'btn-close',\n" +" 'data-bs-dismiss' => 'alert',\n" +" ]);\n" +" }\n" +"\n" +" return Html::div($content, ['class' => implode(' ', $classes)]);\n" +" }\n" +"}\n" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Using the Widget" +msgstr "Usando o widget" + +#. type: Fenced code block (php) +#: ../src/guide/views/widget.md +#, no-wrap +msgid "" +"\n" +"\n" +"
\n" +" message('Operation completed successfully!')\n" +" ->type('success')\n" +" ->closeable() ?>\n" +" \n" +" message('Please review the form errors below.')\n" +" ->type('danger') ?>\n" +"
\n" +msgstr "" +"\n" +"\n" +"
\n" +" message('Operation completed successfully!')\n" +" ->type('success')\n" +" ->closeable() ?>\n" +" \n" +" message('Please review the form errors below.')\n" +" ->type('danger') ?>\n" +"
\n" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Widget with Dependencies" +msgstr "Widget com dependências" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "Widgets can use dependency injection for services:" +msgstr "Os widgets podem usar injeção de dependência para receber serviços:" + +#. type: Fenced code block (php) +#: ../src/guide/views/widget.md +#, no-wrap +msgid "" +"userService->getCurrentUser();\n" +" \n" +" if ($currentUser === null) {\n" +" return $this->renderLoginLink();\n" +" }\n" +"\n" +" return $this->renderUserMenu($currentUser);\n" +" }\n" +"\n" +" private function renderLoginLink(): string\n" +" {\n" +" return Html::a('Login', $this->urlGenerator->generate('login'), [\n" +" 'class' => 'btn btn-primary',\n" +" ]);\n" +" }\n" +"\n" +" private function renderUserMenu($user): string\n" +" {\n" +" $items = [\n" +" Html::a('Profile', $this->urlGenerator->generate('user.profile'), [\n" +" 'class' => 'dropdown-item',\n" +" ]),\n" +" Html::a('Settings', $this->urlGenerator->generate('user.settings'), [\n" +" 'class' => 'dropdown-item',\n" +" ]),\n" +" '
',\n" +" Html::a('Logout', $this->urlGenerator->generate('logout'), [\n" +" 'class' => 'dropdown-item',\n" +" ]),\n" +" ];\n" +"\n" +" return Html::div(\n" +" Html::button(\n" +" Html::encode($user->getName()) . ' ',\n" +" [\n" +" 'class' => 'btn btn-secondary dropdown-toggle',\n" +" 'type' => 'button',\n" +" 'data-bs-toggle' => 'dropdown',\n" +" ]\n" +" ) .\n" +" Html::div(implode('', $items), ['class' => 'dropdown-menu']),\n" +" ['class' => 'dropdown']\n" +" );\n" +" }\n" +"}\n" +msgstr "" +"userService->getCurrentUser();\n" +" \n" +" if ($currentUser === null) {\n" +" return $this->renderLoginLink();\n" +" }\n" +"\n" +" return $this->renderUserMenu($currentUser);\n" +" }\n" +"\n" +" private function renderLoginLink(): string\n" +" {\n" +" return Html::a('Login', $this->urlGenerator->generate('login'), [\n" +" 'class' => 'btn btn-primary',\n" +" ]);\n" +" }\n" +"\n" +" private function renderUserMenu($user): string\n" +" {\n" +" $items = [\n" +" Html::a('Profile', $this->urlGenerator->generate('user.profile'), [\n" +" 'class' => 'dropdown-item',\n" +" ]),\n" +" Html::a('Settings', $this->urlGenerator->generate('user.settings'), [\n" +" 'class' => 'dropdown-item',\n" +" ]),\n" +" '
',\n" +" Html::a('Logout', $this->urlGenerator->generate('logout'), [\n" +" 'class' => 'dropdown-item',\n" +" ]),\n" +" ];\n" +"\n" +" return Html::div(\n" +" Html::button(\n" +" Html::encode($user->getName()) . ' ',\n" +" [\n" +" 'class' => 'btn btn-secondary dropdown-toggle',\n" +" 'type' => 'button',\n" +" 'data-bs-toggle' => 'dropdown',\n" +" ]\n" +" ) .\n" +" Html::div(implode('', $items), ['class' => 'dropdown-menu']),\n" +" ['class' => 'dropdown']\n" +" );\n" +" }\n" +"}\n" + +#. type: Title ## +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Widget Factory Setup" +msgstr "Configuração da widget factory" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Bootstrap Configuration" +msgstr "Configuração de bootstrap" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "Initialize the widget factory in your application bootstrap:" +msgstr "Inicialize a widget factory no bootstrap da sua aplicação:" + +#. type: Plain text +#: ../src/guide/views/widget.md +#, no-wrap +msgid "**config/bootstrap.php**\n" +msgstr "**config/bootstrap.php**\n" + +#. type: Fenced code block (php) +#: ../src/guide/views/widget.md +#, no-wrap +msgid "" +" [\n" +" 'type()' => ['info'],\n" +" 'closeable()' => [true],\n" +" ],\n" +" App\\Widget\\CardWidget::class => [\n" +" 'headerClass()' => ['card-header bg-primary text-white'],\n" +" ],\n" +"];\n" +"\n" +"WidgetFactory::initialize($container, $widgetDefaults);\n" +msgstr "" +" [\n" +" 'type()' => ['info'],\n" +" 'closeable()' => [true],\n" +" ],\n" +" App\\Widget\\CardWidget::class => [\n" +" 'headerClass()' => ['card-header bg-primary text-white'],\n" +" ],\n" +"];\n" +"\n" +"WidgetFactory::initialize($container, $widgetDefaults);\n" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "DI Container Configuration" +msgstr "Configuração do container de DI" + +#. type: Plain text +#: ../src/guide/views/widget.md +#, no-wrap +msgid "**config/web/di.php**\n" +msgstr "**config/web/di.php**\n" + +#. type: Fenced code block (php) +#: ../src/guide/views/widget.md +#, no-wrap +msgid "" +"use App\\Widget\\AlertWidget;\n" +"use App\\Widget\\UserMenuWidget;\n" +"\n" +"return [\n" +" // Widget configurations can be defined here if needed\n" +" AlertWidget::class => static fn() => new AlertWidget(),\n" +" \n" +" UserMenuWidget::class => static fn(\n" +" App\\Service\\UserService $userService,\n" +" Yiisoft\\Router\\UrlGeneratorInterface $urlGenerator\n" +" ) => new UserMenuWidget($userService, $urlGenerator),\n" +"];\n" +msgstr "" +"use App\\Widget\\AlertWidget;\n" +"use App\\Widget\\UserMenuWidget;\n" +"\n" +"return [\n" +" // Configurações de widgets podem ser definidas aqui, se necessário\n" +" AlertWidget::class => static fn() => new AlertWidget(),\n" +" \n" +" UserMenuWidget::class => static fn(\n" +" App\\Service\\UserService $userService,\n" +" Yiisoft\\Router\\UrlGeneratorInterface $urlGenerator\n" +" ) => new UserMenuWidget($userService, $urlGenerator),\n" +"];\n" + +#. type: Title ## +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Advanced Widget Examples" +msgstr "Exemplos avançados de widgets" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Data List Widget" +msgstr "Widget de lista de dados" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "A widget that displays a list of items with pagination:" +msgstr "Um widget que exibe uma lista de itens com paginação:" + +#. type: Fenced code block (php) +#: ../src/guide/views/widget.md +#, no-wrap +msgid "" +"paginator = $paginator;\n" +" return $new;\n" +" }\n" +"\n" +" public function itemRenderer(callable $renderer): self\n" +" {\n" +" $new = clone $this;\n" +" $new->itemRenderer = $renderer;\n" +" return $new;\n" +" }\n" +"\n" +" public function containerClass(string $class): self\n" +" {\n" +" $new = clone $this;\n" +" $new->containerClass = $class;\n" +" return $new;\n" +" }\n" +"\n" +" public function itemClass(string $class): self\n" +" {\n" +" $new = clone $this;\n" +" $new->itemClass = $class;\n" +" return $new;\n" +" }\n" +"\n" +" public function emptyText(string $text): self\n" +" {\n" +" $new = clone $this;\n" +" $new->emptyText = $text;\n" +" return $new;\n" +" }\n" +"\n" +" protected function render(): string\n" +" {\n" +" if ($this->paginator === null) {\n" +" return '';\n" +" }\n" +"\n" +" $items = $this->paginator->read();\n" +" \n" +" if (empty($items)) {\n" +" return Html::div($this->emptyText, ['class' => 'empty-message']);\n" +" }\n" +"\n" +" $itemsHtml = '';\n" +" foreach ($items as $item) {\n" +" $content = $this->itemRenderer \n" +" ? ($this->itemRenderer)($item)\n" +" : Html::encode((string) $item);\n" +" \n" +" $itemsHtml .= Html::div($content, ['class' => $this->itemClass]);\n" +" }\n" +"\n" +" return Html::div($itemsHtml, ['class' => $this->containerClass]);\n" +" }\n" +"}\n" +msgstr "" +"paginator = $paginator;\n" +" return $new;\n" +" }\n" +"\n" +" public function itemRenderer(callable $renderer): self\n" +" {\n" +" $new = clone $this;\n" +" $new->itemRenderer = $renderer;\n" +" return $new;\n" +" }\n" +"\n" +" public function containerClass(string $class): self\n" +" {\n" +" $new = clone $this;\n" +" $new->containerClass = $class;\n" +" return $new;\n" +" }\n" +"\n" +" public function itemClass(string $class): self\n" +" {\n" +" $new = clone $this;\n" +" $new->itemClass = $class;\n" +" return $new;\n" +" }\n" +"\n" +" public function emptyText(string $text): self\n" +" {\n" +" $new = clone $this;\n" +" $new->emptyText = $text;\n" +" return $new;\n" +" }\n" +"\n" +" protected function render(): string\n" +" {\n" +" if ($this->paginator === null) {\n" +" return '';\n" +" }\n" +"\n" +" $items = $this->paginator->read();\n" +" \n" +" if (empty($items)) {\n" +" return Html::div($this->emptyText, ['class' => 'empty-message']);\n" +" }\n" +"\n" +" $itemsHtml = '';\n" +" foreach ($items as $item) {\n" +" $content = $this->itemRenderer \n" +" ? ($this->itemRenderer)($item)\n" +" : Html::encode((string) $item);\n" +" \n" +" $itemsHtml .= Html::div($content, ['class' => $this->itemClass]);\n" +" }\n" +"\n" +" return Html::div($itemsHtml, ['class' => $this->containerClass]);\n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "Usage:" +msgstr "Uso:" + +#. type: Fenced code block (php) +#: ../src/guide/views/widget.md +#, no-wrap +msgid "" +"\n" +"\n" +"paginator($postPaginator)\n" +" ->containerClass('posts-list row')\n" +" ->itemClass('col-md-4 mb-3')\n" +" ->itemRenderer(function ($post) {\n" +" return $this->render('_post_card', ['post' => $post]);\n" +" }) ?>\n" +msgstr "" +"\n" +"\n" +"paginator($postPaginator)\n" +" ->containerClass('posts-list row')\n" +" ->itemClass('col-md-4 mb-3')\n" +" ->itemRenderer(function ($post) {\n" +" return $this->render('_post_card', ['post' => $post]);\n" +" }) ?>\n" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Form Widget" +msgstr "Widget de formulário" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "A widget that simplifies form rendering:" +msgstr "Um widget que simplifica a renderização de formulários:" + +#. type: Fenced code block (php) +#: ../src/guide/views/widget.md +#, no-wrap +msgid "" +"model = $model;\n" +" return $new;\n" +" }\n" +"\n" +" public function action(string $action): self\n" +" {\n" +" $new = clone $this;\n" +" $new->action = $action;\n" +" return $new;\n" +" }\n" +"\n" +" public function method(string $method): self\n" +" {\n" +" $new = clone $this;\n" +" $new->method = $method;\n" +" return $new;\n" +" }\n" +"\n" +" public function options(array $options): self\n" +" {\n" +" $new = clone $this;\n" +" $new->options = $options;\n" +" return $new;\n" +" }\n" +"\n" +" public function field(string $attribute, array $options = []): self\n" +" {\n" +" $new = clone $this;\n" +" $new->fields[$attribute] = $options;\n" +" return $new;\n" +" }\n" +"\n" +" protected function render(): string\n" +" {\n" +" if ($this->model === null) {\n" +" return '';\n" +" }\n" +"\n" +" $formOptions = array_merge([\n" +" 'action' => $this->action,\n" +" 'method' => $this->method,\n" +" 'class' => 'form',\n" +" ], $this->options);\n" +"\n" +" $content = '';\n" +" foreach ($this->fields as $attribute => $options) {\n" +" $content .= $this->renderField($attribute, $options);\n" +" }\n" +"\n" +" return Html::form($content, $formOptions);\n" +" }\n" +"\n" +" private function renderField(string $attribute, array $options): string\n" +" {\n" +" $label = $options['label'] ?? ucfirst($attribute);\n" +" $type = $options['type'] ?? 'text';\n" +" $class = $options['class'] ?? 'form-control';\n" +"\n" +" $field = Html::div(\n" +" Html::label($label, null, ['class' => 'form-label']) .\n" +" Html::input($type, $attribute, $this->getModelValue($attribute), [\n" +" 'class' => $class,\n" +" 'id' => $attribute,\n" +" ]),\n" +" ['class' => 'mb-3']\n" +" );\n" +"\n" +" return $field;\n" +" }\n" +"\n" +" private function getModelValue(string $attribute): mixed\n" +" {\n" +" return $this->model->getAttributeValue($attribute);\n" +" }\n" +"}\n" +msgstr "" +"model = $model;\n" +" return $new;\n" +" }\n" +"\n" +" public function action(string $action): self\n" +" {\n" +" $new = clone $this;\n" +" $new->action = $action;\n" +" return $new;\n" +" }\n" +"\n" +" public function method(string $method): self\n" +" {\n" +" $new = clone $this;\n" +" $new->method = $method;\n" +" return $new;\n" +" }\n" +"\n" +" public function options(array $options): self\n" +" {\n" +" $new = clone $this;\n" +" $new->options = $options;\n" +" return $new;\n" +" }\n" +"\n" +" public function field(string $attribute, array $options = []): self\n" +" {\n" +" $new = clone $this;\n" +" $new->fields[$attribute] = $options;\n" +" return $new;\n" +" }\n" +"\n" +" protected function render(): string\n" +" {\n" +" if ($this->model === null) {\n" +" return '';\n" +" }\n" +"\n" +" $formOptions = array_merge([\n" +" 'action' => $this->action,\n" +" 'method' => $this->method,\n" +" 'class' => 'form',\n" +" ], $this->options);\n" +"\n" +" $content = '';\n" +" foreach ($this->fields as $attribute => $options) {\n" +" $content .= $this->renderField($attribute, $options);\n" +" }\n" +"\n" +" return Html::form($content, $formOptions);\n" +" }\n" +"\n" +" private function renderField(string $attribute, array $options): string\n" +" {\n" +" $label = $options['label'] ?? ucfirst($attribute);\n" +" $type = $options['type'] ?? 'text';\n" +" $class = $options['class'] ?? 'form-control';\n" +"\n" +" $field = Html::div(\n" +" Html::label($label, null, ['class' => 'form-label']) .\n" +" Html::input($type, $attribute, $this->getModelValue($attribute), [\n" +" 'class' => $class,\n" +" 'id' => $attribute,\n" +" ]),\n" +" ['class' => 'mb-3']\n" +" );\n" +"\n" +" return $field;\n" +" }\n" +"\n" +" private function getModelValue(string $attribute): mixed\n" +" {\n" +" return $this->model->getAttributeValue($attribute);\n" +" }\n" +"}\n" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Breadcrumb Widget" +msgstr "Widget de breadcrumb" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "A widget for navigation breadcrumbs:" +msgstr "Um widget para breadcrumbs de navegação:" + +#. type: Fenced code block (php) +#: ../src/guide/views/widget.md +#, no-wrap +msgid "" +"items = $items;\n" +" return $new;\n" +" }\n" +"\n" +" public function separator(string $separator): self\n" +" {\n" +" $new = clone $this;\n" +" $new->separator = $separator;\n" +" return $new;\n" +" }\n" +"\n" +" public function options(array $options): self\n" +" {\n" +" $new = clone $this;\n" +" $new->options = $options;\n" +" return $new;\n" +" }\n" +"\n" +" protected function render(): string\n" +" {\n" +" if (empty($this->items)) {\n" +" return '';\n" +" }\n" +"\n" +" $links = [];\n" +" $itemCount = count($this->items);\n" +" \n" +" foreach ($this->items as $index => $item) {\n" +" if ($index === $itemCount - 1) {\n" +" // Last item (current page) - no link\n" +" $links[] = Html::span($item['label'], ['class' => 'breadcrumb-item active']);\n" +" } else {\n" +" // Regular breadcrumb item with link\n" +" $url = isset($item['url']) \n" +" ? (is_array($item['url']) \n" +" ? $this->urlGenerator->generate($item['url'][0], $item['url'][1] ?? [])\n" +" : $item['url'])\n" +" : '#';\n" +" \n" +" $links[] = Html::span(\n" +" Html::a($item['label'], $url),\n" +" ['class' => 'breadcrumb-item']\n" +" );\n" +" }\n" +" }\n" +"\n" +" $options = array_merge(['class' => 'breadcrumb'], $this->options);\n" +"\n" +" return Html::nav(\n" +" Html::ol(implode('', $links), ['class' => 'breadcrumb']),\n" +" $options\n" +" );\n" +" }\n" +"}\n" +msgstr "" +"items = $items;\n" +" return $new;\n" +" }\n" +"\n" +" public function separator(string $separator): self\n" +" {\n" +" $new = clone $this;\n" +" $new->separator = $separator;\n" +" return $new;\n" +" }\n" +"\n" +" public function options(array $options): self\n" +" {\n" +" $new = clone $this;\n" +" $new->options = $options;\n" +" return $new;\n" +" }\n" +"\n" +" protected function render(): string\n" +" {\n" +" if (empty($this->items)) {\n" +" return '';\n" +" }\n" +"\n" +" $links = [];\n" +" $itemCount = count($this->items);\n" +" \n" +" foreach ($this->items as $index => $item) {\n" +" if ($index === $itemCount - 1) {\n" +" // Último item (página atual) - sem link\n" +" $links[] = Html::span($item['label'], ['class' => 'breadcrumb-item active']);\n" +" } else {\n" +" // Item de breadcrumb comum, com link\n" +" $url = isset($item['url']) \n" +" ? (is_array($item['url']) \n" +" ? $this->urlGenerator->generate($item['url'][0], $item['url'][1] ?? [])\n" +" : $item['url'])\n" +" : '#';\n" +" \n" +" $links[] = Html::span(\n" +" Html::a($item['label'], $url),\n" +" ['class' => 'breadcrumb-item']\n" +" );\n" +" }\n" +" }\n" +"\n" +" $options = array_merge(['class' => 'breadcrumb'], $this->options);\n" +"\n" +" return Html::nav(\n" +" Html::ol(implode('', $links), ['class' => 'breadcrumb']),\n" +" $options\n" +" );\n" +" }\n" +"}\n" + +#. type: Title ## +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Widget Best Practices" +msgstr "Boas práticas com widgets" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Configuration Pattern" +msgstr "Padrão de configuração" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "Use immutable configuration methods:" +msgstr "Use métodos de configuração imutáveis:" + +#. type: Fenced code block (php) +#: ../src/guide/views/widget.md +#, no-wrap +msgid "" +"public function someProperty($value): self\n" +"{\n" +" $new = clone $this;\n" +" $new->someProperty = $value;\n" +" return $new;\n" +"}\n" +msgstr "" +"public function someProperty($value): self\n" +"{\n" +" $new = clone $this;\n" +" $new->someProperty = $value;\n" +" return $new;\n" +"}\n" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Validation" +msgstr "Validação" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "Validate widget configuration in the render method:" +msgstr "Valide a configuração do widget no método render:" + +#. type: Fenced code block (php) +#: ../src/guide/views/widget.md +#, no-wrap +msgid "" +"protected function render(): string\n" +"{\n" +" if (empty($this->items)) {\n" +" throw new InvalidArgumentException('Items cannot be empty.');\n" +" }\n" +" \n" +" // ... render logic\n" +"}\n" +msgstr "" +"protected function render(): string\n" +"{\n" +" if (empty($this->items)) {\n" +" throw new InvalidArgumentException('Items cannot be empty.');\n" +" }\n" +" \n" +" // ... lógica de renderização\n" +"}\n" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "HTML Encoding" +msgstr "Codificação de HTML" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "Always encode user data:" +msgstr "Sempre codifique os dados vindos do usuário:" + +#. type: Fenced code block (php) +#: ../src/guide/views/widget.md +#, no-wrap +msgid "" +"protected function render(): string\n" +"{\n" +" return Html::div(Html::encode($this->userContent), [\n" +" 'class' => 'user-content',\n" +" ]);\n" +"}\n" +msgstr "" +"protected function render(): string\n" +"{\n" +" return Html::div(Html::encode($this->userContent), [\n" +" 'class' => 'user-content',\n" +" ]);\n" +"}\n" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Asset Management" +msgstr "Gerenciamento de assets" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "Register widget-specific assets:" +msgstr "Registre os assets específicos do widget:" + +#. type: Fenced code block (php) +#: ../src/guide/views/widget.md +#, no-wrap +msgid "" +"assetManager->register(ChartWidgetAsset::class);\n" +" \n" +" // Render widget content\n" +" return $this->renderChart();\n" +" }\n" +"}\n" +msgstr "" +"assetManager->register(ChartWidgetAsset::class);\n" +" \n" +" // Renderiza o conteúdo do widget\n" +" return $this->renderChart();\n" +" }\n" +"}\n" + +#. type: Title ## +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Using Widgets in Layouts" +msgstr "Usando widgets em layouts" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "Widgets are particularly useful in layouts for common UI elements:" +msgstr "Os widgets são especialmente úteis em layouts, para elementos de interface comuns:" + +#. type: Plain text +#: ../src/guide/views/widget.md +#, no-wrap +msgid "**views/layout/main.php**\n" +msgstr "**views/layout/main.php**\n" + +#. type: Fenced code block (php) +#: ../src/guide/views/widget.md +#, no-wrap +msgid "" +"\n" +"\n" +"\n" +"\n" +" \n" +"\n" +"\n" +"
\n" +" \n" +" \n" +"
\n" +" \n" +"
\n" +" \n" +"
\n" +" \n" +"
\n" +" \n" +"
\n" +"\n" +"\n" +msgstr "" +"\n" +"\n" +"\n" +"\n" +" \n" +"\n" +"\n" +"
\n" +" \n" +" \n" +"
\n" +" \n" +"
\n" +" \n" +"
\n" +" \n" +"
\n" +" \n" +"
\n" +"\n" +"\n" + +#. type: Title ## +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Testing Widgets" +msgstr "Testando widgets" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Unit Testing" +msgstr "Testes unitários" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "Test widget rendering logic:" +msgstr "Teste a lógica de renderização do widget:" + +#. type: Fenced code block (php) +#: ../src/guide/views/widget.md +#, no-wrap +msgid "" +"message('Test message')\n" +" ->type('success');\n" +" \n" +" $output = $widget->render();\n" +" \n" +" $this->assertStringContainsString('Test message', $output);\n" +" $this->assertStringContainsString('alert-success', $output);\n" +" }\n" +" \n" +" public function testRenderEmpty(): void\n" +" {\n" +" $widget = AlertWidget::widget();\n" +" $output = $widget->render();\n" +" \n" +" $this->assertEmpty($output);\n" +" }\n" +"}\n" +msgstr "" +"message('Test message')\n" +" ->type('success');\n" +" \n" +" $output = $widget->render();\n" +" \n" +" $this->assertStringContainsString('Test message', $output);\n" +" $this->assertStringContainsString('alert-success', $output);\n" +" }\n" +" \n" +" public function testRenderEmpty(): void\n" +" {\n" +" $widget = AlertWidget::widget();\n" +" $output = $widget->render();\n" +" \n" +" $this->assertEmpty($output);\n" +" }\n" +"}\n" + +#. type: Title ## +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Common Widget Patterns" +msgstr "Padrões comuns de widgets" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Conditional Rendering" +msgstr "Renderização condicional" + +#. type: Fenced code block (php) +#: ../src/guide/views/widget.md +#, no-wrap +msgid "" +"protected function render(): string\n" +"{\n" +" if (!$this->shouldRender()) {\n" +" return '';\n" +" }\n" +" \n" +" return $this->doRender();\n" +"}\n" +"\n" +"private function shouldRender(): bool\n" +"{\n" +" return !empty($this->items) && $this->isVisible;\n" +"}\n" +msgstr "" +"protected function render(): string\n" +"{\n" +" if (!$this->shouldRender()) {\n" +" return '';\n" +" }\n" +" \n" +" return $this->doRender();\n" +"}\n" +"\n" +"private function shouldRender(): bool\n" +"{\n" +" return !empty($this->items) && $this->isVisible;\n" +"}\n" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Template-based Rendering" +msgstr "Renderização baseada em template" + +#. type: Fenced code block (php) +#: ../src/guide/views/widget.md +#, no-wrap +msgid "" +"protected function render(): string\n" +"{\n" +" return $this->renderTemplate('widget-template', [\n" +" 'items' => $this->items,\n" +" 'options' => $this->options,\n" +" ]);\n" +"}\n" +"\n" +"private function renderTemplate(string $template, array $data): string\n" +"{\n" +" // Use a view renderer to render template files\n" +" return $this->viewRenderer->renderPartialAsString($template, $data);\n" +"}\n" +msgstr "" +"protected function render(): string\n" +"{\n" +" return $this->renderTemplate('widget-template', [\n" +" 'items' => $this->items,\n" +" 'options' => $this->options,\n" +" ]);\n" +"}\n" +"\n" +"private function renderTemplate(string $template, array $data): string\n" +"{\n" +" // Usa um view renderer para renderizar arquivos de template\n" +" return $this->viewRenderer->renderPartialAsString($template, $data);\n" +"}\n" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Event Integration" +msgstr "Integração com eventos" + +#. type: Fenced code block (php) +#: ../src/guide/views/widget.md +#, no-wrap +msgid "" +"protected function render(): string\n" +"{\n" +" $event = new BeforeWidgetRender($this);\n" +" $this->eventDispatcher->dispatch($event);\n" +" \n" +" $content = $this->doRender();\n" +" \n" +" $afterEvent = new AfterWidgetRender($this, $content);\n" +" $this->eventDispatcher->dispatch($afterEvent);\n" +" \n" +" return $afterEvent->getContent();\n" +"}\n" +msgstr "" +"protected function render(): string\n" +"{\n" +" $event = new BeforeWidgetRender($this);\n" +" $this->eventDispatcher->dispatch($event);\n" +" \n" +" $content = $this->doRender();\n" +" \n" +" $afterEvent = new AfterWidgetRender($this, $content);\n" +" $this->eventDispatcher->dispatch($afterEvent);\n" +" \n" +" return $afterEvent->getContent();\n" +"}\n" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "Widgets provide a powerful way to create reusable, configurable UI components in Yii3 applications. They help maintain clean separation of concerns and make your views more maintainable and testable." +msgstr "Os widgets oferecem uma forma eficaz de criar componentes de interface reutilizáveis e configuráveis em aplicações Yii3. Eles ajudam a manter uma separação clara de responsabilidades e deixam suas views mais fáceis de manter e testar." diff --git a/_translations/po/pt-BR/index.md.po b/_translations/po/pt-BR/index.md.po new file mode 100644 index 00000000..0957e486 --- /dev/null +++ b/_translations/po/pt-BR/index.md.po @@ -0,0 +1,97 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-01-13 11:06+0000\n" +"PO-Revision-Date: 2026-01-13 11:06+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Yaml Front Matter Hash Value: features details +#: ../src/index.md +#, no-wrap +msgid "Yii gives you the maximum functionality by adding the least possible overhead." +msgstr "O Yii oferece o máximo de funcionalidade com o mínimo possível de sobrecarga." + +#. type: Yaml Front Matter Hash Value: features title +#: ../src/index.md +#, no-wrap +msgid "Fast" +msgstr "Rápido" + +#. type: Yaml Front Matter Hash Value: features details +#: ../src/index.md +#, no-wrap +msgid "Sane defaults and built-in tools helps you write solid and secure code." +msgstr "Padrões sensatos e ferramentas embutidas ajudam você a escrever código sólido e seguro." + +#. type: Yaml Front Matter Hash Value: features title +#: ../src/index.md +#, no-wrap +msgid "Secure" +msgstr "Seguro" + +#. type: Yaml Front Matter Hash Value: features details +#: ../src/index.md +#, no-wrap +msgid "Write more code in less time with simple, yet powerful APIs and code generation." +msgstr "Escreva mais código em menos tempo com APIs simples e poderosas e com geração de código." + +#. type: Yaml Front Matter Hash Value: features title +#: ../src/index.md +#, no-wrap +msgid "Efficient" +msgstr "Eficiente" + +#. type: Yaml Front Matter Hash Value: hero actions text +#: ../src/index.md +#, no-wrap +msgid "Get Started" +msgstr "Comece agora" + +#. type: Yaml Front Matter Hash Value: hero name +#: ../src/index.md +#, no-wrap +msgid "Yii3 Framework" +msgstr "Yii3 Framework" + +#. type: Yaml Front Matter Hash Value: hero tagline +#: ../src/index.md +#, no-wrap +msgid "A simple, powerful and fast framework. Meet the modern, definitive guide to Yii you've always wanted." +msgstr "Um framework simples, poderoso e rápido. Conheça o guia definitivo e moderno do Yii que você sempre quis." + +#. type: Title ## +#: ../src/index.md ../src/internals/003-roadmap.md +#, no-wrap +msgid "Documentation" +msgstr "Documentação" + +#. type: Plain text +#: ../src/index.md +#, no-wrap +msgid "

\n" +msgstr "

\n" + +#. type: Bullet: '- ' +#: ../src/index.md +msgid "[The Definitive Guide](guide/) — the comprehensive guide covering all aspects of the framework." +msgstr "[Guia definitivo](guide/) — o guia completo que cobre todos os aspectos do framework." + +#. type: Bullet: '- ' +#: ../src/index.md +msgid "[Community Cookbook](cookbook/) — a collection of community-contributed tips, tricks, and solutions for common Yii development tasks." +msgstr "[Cookbook da comunidade](cookbook/) — uma coleção de dicas, truques e soluções da comunidade para tarefas comuns no desenvolvimento com Yii." + +#. type: Bullet: '- ' +#: ../src/index.md +msgid "[Internals](internals/) — documentation for developers contributing to the Yii framework itself, including guidelines, workflows, and best practices." +msgstr "[Detalhes internos](internals/) — documentação para quem contribui com o próprio framework Yii, incluindo diretrizes, fluxos de trabalho e boas práticas." diff --git a/_translations/po/pt-BR/internals_000-packages.md.po b/_translations/po/pt-BR/internals_000-packages.md.po new file mode 100644 index 00000000..77881865 --- /dev/null +++ b/_translations/po/pt-BR/internals_000-packages.md.po @@ -0,0 +1,242 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 08:02+0000\n" +"PO-Revision-Date: 2025-12-24 08:02+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Bullet: ' - ' +#: ../src/en/guide/start/databases.md ../src/en/internals/000-packages.md +msgid "..." +msgstr "..." + +#. type: Title # +#: ../src/en/internals/000-packages.md +#, no-wrap +msgid "000 — Packages" +msgstr "000 — Pacotes" + +#. type: Plain text +#: ../src/en/internals/000-packages.md +msgid "Yii3 team divided the framework into several packages that conform to the following agreements." +msgstr "O time do Yii3 dividiu o framework em vários pacotes que seguem os acordos abaixo." + +#. type: Plain text +#: ../src/en/internals/000-packages.md +msgid "For all packages, the GitHub repository name exactly matches the Packagist package name." +msgstr "Em todos os pacotes, o nome do repositório no GitHub corresponde exatamente ao nome do pacote no Packagist." + +#. type: Plain text +#: ../src/en/internals/000-packages.md +msgid "For a full list of packages and their building status, see [status page at yiiframework.com](https://www.yiiframework.com/status/3.0)." +msgstr "Para ver a lista completa de pacotes e o status de build de cada um, consulte a [página de status em yiiframework.com](https://www.yiiframework.com/status/3.0)." + +#. type: Title ## +#: ../src/en/internals/000-packages.md +#, no-wrap +msgid "Yii-specific packages (framework and extensions)" +msgstr "Pacotes específicos do Yii (framework e extensões)" + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "named `yiisoft/yii-something` or more specific: `yii-type-something` e.g.:" +msgstr "nomeados como `yiisoft/yii-something` ou de forma mais específica: `yii-type-something`, por exemplo:" + +#. type: Bullet: ' - ' +#: ../src/en/internals/000-packages.md +msgid "modules: `yii-module-users`, `yii-module-pages`" +msgstr "módulos: `yii-module-users`, `yii-module-pages`" + +#. type: Bullet: ' - ' +#: ../src/en/internals/000-packages.md +msgid "themes: `yii-theme-adminlte`, `yii-theme-hyde`" +msgstr "temas: `yii-theme-adminlte`, `yii-theme-hyde`" + +#. type: Bullet: ' - ' +#: ../src/en/internals/000-packages.md +msgid "widgets: `yii-widget-datepicker`" +msgstr "widgets: `yii-widget-datepicker`" + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "titled as \"Yii Framework ...\"" +msgstr "intitulados como \"Yii Framework ...\"" + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "may have any dependencies and Yii-specific code" +msgstr "podem ter quaisquer dependências e código específico do Yii" + +#. type: Title ## +#: ../src/en/internals/000-packages.md +#, no-wrap +msgid "General purpose packages (libraries)" +msgstr "Pacotes de uso geral (bibliotecas)" + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "you can use these independently of Yii Framework" +msgstr "você pode usá-los independentemente do Yii Framework" + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "named as `yiisoft/something` without yii-prefix" +msgstr "nomeados como `yiisoft/something`, sem o prefixo yii" + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "titled as \"Yii ...\"" +msgstr "intitulados como \"Yii ...\"" + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "must not have dependencies on any Yii-specific packages" +msgstr "não podem ter dependências de nenhum pacote específico do Yii" + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "should have as fewer dependencies as possible" +msgstr "devem ter o menor número possível de dependências" + +#. type: Title ## +#: ../src/en/internals/000-packages.md +#, no-wrap +msgid "Configs and defaults" +msgstr "Configurações e padrões" + +#. type: Plain text +#: ../src/en/internals/000-packages.md +msgid "The following applies to both Yii-specific packages and general purpose packages:" +msgstr "O que segue se aplica tanto aos pacotes específicos do Yii quanto aos pacotes de uso geral:" + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "Package may have `config` directory with Yii-specific defaults." +msgstr "O pacote pode ter um diretório `config` com padrões específicos do Yii." + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "Package may have \"config-plugin\" in \"extra\" section of `composer.json`." +msgstr "O pacote pode ter \"config-plugin\" na seção \"extra\" do `composer.json`." + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "Package mustn't have dependencies in `require` section of `composer.json` that are used in `config` only." +msgstr "O pacote não pode ter, na seção `require` do `composer.json`, dependências usadas apenas em `config`." + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "You should namespace parameters with `vendor/package-name`:" +msgstr "Você deve colocar os parâmetros sob o namespace `vendor/package-name`:" + +#. type: Fenced code block (php) +#: ../src/en/internals/000-packages.md +#, no-wrap +msgid "" +"return [\n" +" 'vendor/package-name' => [\n" +" 'param1' => 1,\n" +" 'param2' => 2,\n" +" ],\n" +"];\n" +msgstr "" +"return [\n" +" 'vendor/package-name' => [\n" +" 'param1' => 1,\n" +" 'param2' => 2,\n" +" ],\n" +"];\n" + +#. type: Title ## +#: ../src/en/internals/000-packages.md +#, no-wrap +msgid "Versions" +msgstr "Versões" + +#. type: Plain text +#: ../src/en/internals/000-packages.md +msgid "All packages follow [SemVer](https://semver.org/) versioning:" +msgstr "Todos os pacotes seguem o versionamento [SemVer](https://semver.org/):" + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "`x.*.*` - incompatible API changes." +msgstr "`x.*.*` - mudanças incompatíveis na API." + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "`*.x.*` - add functionality (backwards-compatible)." +msgstr "`*.x.*` - adição de funcionalidades (compatível com versões anteriores)." + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "`*.*.x` - bug fixes (backwards-compatible)." +msgstr "`*.*.x` - correções de bugs (compatível com versões anteriores)." + +#. type: Plain text +#: ../src/en/internals/000-packages.md +msgid "The first stable version should be 1.0.0." +msgstr "A primeira versão estável deve ser 1.0.0." + +#. type: Plain text +#: ../src/en/internals/000-packages.md +msgid "Each package version number doesn't depend on any other package version or framework name/version, only on its own public contract. The framework as a whole has the \"Yii3\" name." +msgstr "O número de versão de cada pacote não depende da versão de nenhum outro pacote nem do nome/versão do framework, apenas do seu próprio contrato público. O framework como um todo tem o nome \"Yii3\"." + +#. type: Plain text +#: ../src/en/internals/000-packages.md +msgid "It's alright to use packages with different major versions together, as long as they're compatible." +msgstr "Não há problema em usar juntos pacotes com versões major diferentes, desde que sejam compatíveis." + +#. type: Title ## +#: ../src/en/internals/000-packages.md +#, no-wrap +msgid "PHP versions support" +msgstr "Suporte a versões do PHP" + +#. type: Plain text +#: ../src/en/internals/000-packages.md +msgid "The support of PHP versions supported for a package depends on [PHP versions life cycle](https://www.php.net/supported-versions.php)." +msgstr "O suporte às versões do PHP em um pacote depende do [ciclo de vida das versões do PHP](https://www.php.net/supported-versions.php)." + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "Package versions with active support MUST support all PHP versions that have active support." +msgstr "Versões de pacotes com suporte ativo DEVEM suportar todas as versões do PHP que têm suporte ativo." + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "Both packages and application templates MUST have supported versions that receive bug and security fixes. These SHOULD correspond to PHP versions receiving security fixes." +msgstr "Tanto os pacotes quanto os templates de aplicação DEVEM ter versões suportadas que recebem correções de bugs e de segurança. Essas versões DEVERIAM corresponder às versões do PHP que recebem correções de segurança." + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "Packages and application templates MIGHT have supported versions that work with unsupported PHP versions." +msgstr "Pacotes e templates de aplicação PODEM ter versões suportadas que funcionam com versões do PHP sem suporte." + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "Bumping the minimal PHP version in a package or an application template is a minor change." +msgstr "Aumentar a versão mínima do PHP em um pacote ou template de aplicação é uma mudança minor." + +#. type: Title ## +#: ../src/en/internals/000-packages.md +#, no-wrap +msgid "composer.json" +msgstr "composer.json" + +#. type: Plain text +#: ../src/en/internals/000-packages.md +#, no-wrap +msgid "A logical OR operator in version ranges MUST use double pipe (`||`). For example: `\"yiisoft/arrays\": \"^1.0 || ^2.0\"`. \n" +msgstr "Um operador lógico OU em intervalos de versão DEVE usar pipe duplo (`||`). Por exemplo: `\"yiisoft/arrays\": \"^1.0 || ^2.0\"`. \n" diff --git a/_translations/po/pt-BR/internals_001-yii-values.md.po b/_translations/po/pt-BR/internals_001-yii-values.md.po new file mode 100644 index 00000000..edf50d94 --- /dev/null +++ b/_translations/po/pt-BR/internals_001-yii-values.md.po @@ -0,0 +1,242 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 08:02+0000\n" +"PO-Revision-Date: 2025-12-24 08:02+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/en/internals/001-yii-values.md +#, no-wrap +msgid "001 — Yii goal and values" +msgstr "001 — Objetivo e valores do Yii" + +#. type: Title ## +#: ../src/en/internals/001-yii-values.md +#, no-wrap +msgid "Goal" +msgstr "Objetivo" + +#. type: Plain text +#: ../src/en/internals/001-yii-values.md +msgid "The Yii project aims to build and support _practical_ and _helpful_ tools and community." +msgstr "O projeto Yii tem como objetivo construir e manter ferramentas e uma comunidade _práticas_ e _úteis_." + +#. type: Title ## +#: ../src/en/internals/001-yii-values.md +#, no-wrap +msgid "Values" +msgstr "Valores" + +#. type: Plain text +#: ../src/en/internals/001-yii-values.md +msgid "The values we express in our work support the goal. We try to" +msgstr "Os valores que expressamos em nosso trabalho apoiam esse objetivo. Procuramos" + +#. type: Title ## +#: ../src/en/internals/001-yii-values.md +#, no-wrap +msgid "Be practical" +msgstr "Ser práticos" + +#. type: Bullet: ' - ' +#: ../src/en/internals/001-yii-values.md +msgid "[High performance](#high-performance)" +msgstr "[Alto desempenho](#alto-desempenho)" + +#. type: Bullet: ' - ' +#: ../src/en/internals/001-yii-values.md +msgid "[Sensible defaults and flexibility](#sensible-defaults-and-flexibility)" +msgstr "[Padrões sensatos e flexibilidade](#padroes-sensatos-e-flexibilidade)" + +#. type: Bullet: ' - ' +#: ../src/en/internals/001-yii-values.md +msgid "[Be practice-oriented](#be-practice-oriented)" +msgstr "[Ser orientado à prática](#ser-orientado-a-pratica)" + +#. type: Title ## +#: ../src/en/internals/001-yii-values.md +#, no-wrap +msgid "Be helpful" +msgstr "Ser úteis" + +#. type: Bullet: ' - ' +#: ../src/en/internals/001-yii-values.md +msgid "[Be simple](#be-simple)" +msgstr "[Ser simples](#ser-simples)" + +#. type: Bullet: ' - ' +#: ../src/en/internals/001-yii-values.md +msgid "[Be explicit](#be-explicit)" +msgstr "[Ser explícito](#ser-explicito)" + +#. type: Bullet: ' - ' +#: ../src/en/internals/001-yii-values.md +msgid "[Be consistent](#be-consistent)" +msgstr "[Ser consistente](#ser-consistente)" + +#. type: Title ### +#: ../src/en/internals/001-yii-values.md +#, no-wrap +msgid "High performance" +msgstr "Alto desempenho" + +#. type: Plain text +#: ../src/en/internals/001-yii-values.md +msgid "Performance is a necessary condition of practicality. Software shouldn't waste machine resources or human resources." +msgstr "Desempenho é uma condição necessária para a praticidade. O software não deve desperdiçar recursos de máquina nem recursos humanos." + +#. type: Title ### +#: ../src/en/internals/001-yii-values.md +#, no-wrap +msgid "Sensible defaults and flexibility" +msgstr "Padrões sensatos e flexibilidade " + +#. type: Plain text +#: ../src/en/internals/001-yii-values.md +msgid "We prefer sensible defaults and conventions that users can customize. We seek a balance between flexibility, discipline and simplicity that meets common needs." +msgstr "Preferimos padrões e convenções sensatos que os usuários possam personalizar. Buscamos um equilíbrio entre flexibilidade, disciplina e simplicidade que atenda às necessidades comuns." + +#. type: Title ### +#: ../src/en/internals/001-yii-values.md +#, no-wrap +msgid "Be practice-oriented" +msgstr "Ser orientado à prática " + +#. type: Plain text +#: ../src/en/internals/001-yii-values.md +msgid "We prefer practice to theory. For example:" +msgstr "Preferimos a prática à teoria. Por exemplo:" + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "Solutions for known use cases should avoid excess complexity by providing only necessary flexibility." +msgstr "Soluções para casos de uso conhecidos devem evitar complexidade excessiva, oferecendo apenas a flexibilidade necessária." + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "Standard implementations should take practical use into account." +msgstr "Implementações padrão devem levar em conta o uso prático." + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "Experience is at least as useful as theory in guiding design." +msgstr "A experiência é pelo menos tão útil quanto a teoria para orientar o design." + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "Context is critical in determining appropriateness." +msgstr "O contexto é fundamental para determinar o que é adequado." + +#. type: Plain text +#: ../src/en/internals/001-yii-values.md +msgid "This value guides technical decisions as well as community activity. Consideration of how software features help users should guide development. Community-wise, we value any helpful contribution, be it a pull request or an answer in the forum." +msgstr "Esse valor orienta tanto as decisões técnicas quanto a atividade da comunidade. O desenvolvimento deve ser guiado pela forma como os recursos do software ajudam os usuários. Na comunidade, valorizamos qualquer contribuição útil, seja um pull request ou uma resposta no fórum." + +#. type: Plain text +#: ../src/en/internals/001-yii-values.md +msgid "When the other principles conflict, we choose a solution that's more helpful to the community." +msgstr "Quando os outros princípios entram em conflito, escolhemos a solução mais útil para a comunidade." + +#. type: Title ### +#: ../src/en/internals/001-yii-values.md +#, no-wrap +msgid "Be simple" +msgstr "Ser simples" + +#. type: Plain text +#: ../src/en/internals/001-yii-values.md +msgid "Solutions should be simple and expressive:" +msgstr "As soluções devem ser simples e expressivas:" + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "We use as much complexity as needed and no more." +msgstr "Usamos tanta complexidade quanto necessário, e não mais." + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "We avoid ugly solutions unless there is no alternative." +msgstr "Evitamos soluções feias, a menos que não haja alternativa." + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "Fewer rules are better than more rules." +msgstr "Menos regras é melhor do que mais regras." + +#. type: Title ### +#: ../src/en/internals/001-yii-values.md +#, no-wrap +msgid "Be Explicit" +msgstr "Ser explícito " + +#. type: Plain text +#: ../src/en/internals/001-yii-values.md +msgid "We prefer explicit, obvious solutions and code. Solutions should clearly express exactly what they do. For example:" +msgstr "Preferimos soluções e código explícitos e óbvios. As soluções devem expressar claramente o que fazem. Por exemplo:" + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "A straightforward solution is better than an abstract one unless the abstraction has a practical purpose." +msgstr "Uma solução direta é melhor do que uma abstrata, a menos que a abstração tenha um propósito prático." + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "Loud fails are better than silent fails or masking errors." +msgstr "Falhas ruidosas são melhores do que falhas silenciosas ou erros mascarados." + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "Explicit casts are better than PHP type juggling, type hints are good." +msgstr "Conversões explícitas são melhores do que a conversão automática de tipos do PHP; type hints são bons." + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "No magic unless necessary." +msgstr "Nada de mágica, a menos que seja necessário." + +#. type: Title ### +#: ../src/en/internals/001-yii-values.md +#, no-wrap +msgid "Be consistent" +msgstr "Ser consistente" + +#. type: Plain text +#: ../src/en/internals/001-yii-values.md +msgid "We try to be consistent in:" +msgstr "Procuramos ser consistentes em:" + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "Code style" +msgstr "Estilo de código" + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "Naming" +msgstr "Nomenclatura" + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "Design" +msgstr "Design" + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "Structure" +msgstr "Estrutura" + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "Values and goals" +msgstr "Valores e objetivos" diff --git a/_translations/po/pt-BR/internals_002-issue-workflow.md.po b/_translations/po/pt-BR/internals_002-issue-workflow.md.po new file mode 100644 index 00000000..596a7acb --- /dev/null +++ b/_translations/po/pt-BR/internals_002-issue-workflow.md.po @@ -0,0 +1,95 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 10:12+0000\n" +"PO-Revision-Date: 2025-12-24 10:12+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/internals/002-issue-workflow.md +#, no-wrap +msgid "002 — Issue workflow" +msgstr "002 — Fluxo de issues" + +#. type: Plain text +#: ../src/internals/002-issue-workflow.md +msgid "The process of handing incoming issues is the following:" +msgstr "O processo de tratamento das issues recebidas é o seguinte:" + +#. type: Plain text +#: ../src/internals/002-issue-workflow.md +msgid "![Issue workflow schema](/images/internals/002-issue-workflow.svg)" +msgstr "![Esquema do fluxo de issues](/images/internals/002-issue-workflow.svg)" + +#. type: Title ## +#: ../src/internals/002-issue-workflow.md +#, no-wrap +msgid "Roles" +msgstr "Papéis" + +#. type: Plain text +#: ../src/internals/002-issue-workflow.md +msgid "We've many roles:" +msgstr "Temos vários papéis:" + +#. type: Bullet: '- ' +#: ../src/internals/002-issue-workflow.md +msgid "Process managers - initially triage issues and manage labels." +msgstr "Gerentes de processo - fazem a triagem inicial das issues e gerenciam os labels." + +#. type: Bullet: '- ' +#: ../src/internals/002-issue-workflow.md +msgid "Decision makers - participate in discussions moving them to resolutions." +msgstr "Tomadores de decisão - participam das discussões, levando-as a uma resolução." + +#. type: Bullet: '- ' +#: ../src/internals/002-issue-workflow.md +msgid "Bug hunters - verifying bugs." +msgstr "Caçadores de bugs - verificam os bugs." + +#. type: Bullet: '- ' +#: ../src/internals/002-issue-workflow.md +msgid "Contributors - create code for pull requests." +msgstr "Contribuidores - escrevem o código dos pull requests." + +#. type: Bullet: '- ' +#: ../src/internals/002-issue-workflow.md +msgid "Code reviewers - review pull requests." +msgstr "Revisores de código - revisam os pull requests." + +#. type: Plain text +#: ../src/internals/002-issue-workflow.md +msgid "A single person may take one or more roles in the issue-resolving process." +msgstr "Uma mesma pessoa pode assumir um ou mais papéis no processo de resolução de issues." + +#. type: Title ## +#: ../src/internals/002-issue-workflow.md +#, no-wrap +msgid "Labels" +msgstr "Labels" + +#. type: Plain text +#: ../src/internals/002-issue-workflow.md +msgid "We label issues to mark many things: current status, issue type, component affected. Status labels speak for themselves." +msgstr "Usamos labels nas issues para marcar várias coisas: status atual, tipo da issue, componente afetado. Os labels de status falam por si." + +#. type: Title ## +#: ../src/internals/002-issue-workflow.md +#, no-wrap +msgid "Milestones" +msgstr "Milestones" + +#. type: Plain text +#: ../src/internals/002-issue-workflow.md +msgid "Issues aren't assigned to milestones unless they're critical or there is a likely good pull request exists." +msgstr "As issues não são atribuídas a milestones, a menos que sejam críticas ou que provavelmente exista um bom pull request para elas." diff --git a/_translations/po/pt-BR/internals_003-roadmap.md.po b/_translations/po/pt-BR/internals_003-roadmap.md.po new file mode 100644 index 00000000..dd9183fe --- /dev/null +++ b/_translations/po/pt-BR/internals_003-roadmap.md.po @@ -0,0 +1,598 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-01-10 15:51+0000\n" +"PO-Revision-Date: 2026-01-10 15:51+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/index.md ../src/internals/003-roadmap.md +#, no-wrap +msgid "Documentation" +msgstr "Documentação" + +#. type: Title ## +#: ../src/cookbook/sentry-integration.md ../src/internals/003-roadmap.md +#, no-wrap +msgid "Console" +msgstr "Console" + +#. type: Title # +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "003 — Roadmap" +msgstr "003 — Roadmap" + +#. type: Plain text +#: ../src/internals/003-roadmap.md +msgid "We want Yii 3 to:" +msgstr "Queremos que o Yii 3:" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "Not limit a developer to choosing architecture. Allow anything from \"classic\" MVC to DDD." +msgstr "Não limite o desenvolvedor na escolha da arquitetura. Permita qualquer coisa, do MVC \"clássico\" ao DDD." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "Be based on the best practices such as SOLID, GRASP, etc. and teach them to the community." +msgstr "Seja baseado em boas práticas como SOLID, GRASP etc. e as ensine à comunidade." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "Keep the most good things from Yii 2." +msgstr "Mantenha a maior parte das coisas boas do Yii 2." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "Be more open to the global PHP community and infrastructure." +msgstr "Seja mais aberto à comunidade e à infraestrutura PHP global." + +#. type: Title ## +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "PSRs compliance" +msgstr "Conformidade com PSRs" + +#. type: Plain text +#: ../src/internals/003-roadmap.md +msgid "PSR compliance helps with customizability, the ability to use general PHP libraries and implement fewer wrappers. Here's the list of PSRs we want to implement." +msgstr "A conformidade com PSRs ajuda na personalização, permite usar bibliotecas PHP gerais e implementar menos wrappers. Aqui está a lista de PSRs que queremos implementar." + +#. type: Title ### +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "PSR-3 Logger" +msgstr "PSR-3 Logger" + +#. type: Plain text +#: ../src/internals/003-roadmap.md +msgid "Implemented as a [separate package that isn't dependent on a framework](https://github.com/yiisoft/log)." +msgstr "Implementado como um [pacote separado que não depende de um framework](https://github.com/yiisoft/log)." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Framework packages should depend on interface only." +msgstr "[x] Os pacotes do framework devem depender apenas da interface." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Split drivers into packages." +msgstr "[x] Separar os drivers em pacotes." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Clean-up code." +msgstr "[x] Limpar o código." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] [Fix email target](https://github.com/yiisoft/log-target-email)." +msgstr "[x] [Corrigir o destino de e-mail](https://github.com/yiisoft/log-target-email)." + +#. type: Title ### +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "PSR-4 Autoloading" +msgstr "PSR-4 Autoloading" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Autoloading is fine already." +msgstr "[x] O autoloading já está bom." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Document on how it works." +msgstr "[x] Documentar como funciona." + +#. type: Title ### +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "PSR-7 HTTP message" +msgstr "PSR-7 HTTP message" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Remove our own implementation. At least for now." +msgstr "[x] Remover nossa própria implementação. Pelo menos por enquanto." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Framework packages should depend on interfaces only." +msgstr "[x] Os pacotes do framework devem depender apenas de interfaces." + +#. type: Title ### +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "PSR-11 Container" +msgstr "PSR-11 Container" + +#. type: Plain text +#: ../src/internals/003-roadmap.md +msgid "Implemented as a [separate package that isn't dependent on a framework](https://github.com/yiisoft/di)." +msgstr "Implementado como um [pacote separado que não depende de um framework](https://github.com/yiisoft/di)." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Framework packages shouldn't use container directly. One should be able to instantiate everything manually." +msgstr "[x] Os pacotes do framework não devem usar o container diretamente. Deve ser possível instanciar tudo manualmente." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Finish refactoring." +msgstr "[x] Terminar a refatoração." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Remove all framework-specific implementations from the package. Move to a framework." +msgstr "[x] Remover do pacote todas as implementações específicas do framework. Movê-las para o framework." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] [Implement autoloader fallback](https://github.com/yiisoft/di/issues/88)" +msgstr "[x] [Implementar fallback para o autoloader](https://github.com/yiisoft/di/issues/88)" + +#. type: Title ### +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "PSR-12 Code style" +msgstr "PSR-12 Code style" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Make sure the code follows it." +msgstr "[x] Garantir que o código o siga." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Automate fixing style before release." +msgstr "[x] Automatizar a correção de estilo antes do release." + +#. type: Title ### +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "PSR-14 Event dispatcher" +msgstr "PSR-14 Event dispatcher" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] [Implement as a separate library](https://github.com/yiisoft/event-dispatcher)." +msgstr "[x] [Implementar como uma biblioteca separada](https://github.com/yiisoft/event-dispatcher)." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Use in other packages." +msgstr "[x] Usar em outros pacotes." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Polish." +msgstr "[x] Polir." + +#. type: Title ### +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "PSR-15 HTTP handlers" +msgstr "PSR-15 HTTP handlers" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Rewrite HTTP flow to PSR-7 request-response + formatting response via emitter." +msgstr "[x] Reescrever o fluxo HTTP para requisição-resposta PSR-7 + formatação da resposta via emitter." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Offer SAPI emitter out of the box." +msgstr "[x] Oferecer um emitter SAPI pronto para uso." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Make it possible to use alternative emitters such as RoadRunner." +msgstr "[x] Possibilitar o uso de emitters alternativos, como o RoadRunner." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Support middleware." +msgstr "[x] Suportar middleware." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Implement filters as middleware:" +msgstr "[x] Implementar filtros como middleware:" + +#. type: Bullet: ' - ' +#: ../src/internals/003-roadmap.md +msgid "[x] [Rate limiting](https://github.com/yiisoft/yii-web/issues/63)" +msgstr "[x] [Limitação de taxa](https://github.com/yiisoft/yii-web/issues/63)" + +#. type: Bullet: ' - ' +#: ../src/internals/003-roadmap.md +msgid "[x] [Authentication](https://github.com/yiisoft/yii-web/issues/114)" +msgstr "[x] [Autenticação](https://github.com/yiisoft/yii-web/issues/114)" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Re-implement router w/ middleware support for route groups." +msgstr "[x] Reimplementar o router com suporte a middleware para grupos de rotas." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Filters should be middlewares." +msgstr "[x] Filtros devem ser middlewares." + +#. type: Title ### +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "PSR-16 Simple cache" +msgstr "PSR-16 Simple cache" + +#. type: Plain text +#: ../src/internals/003-roadmap.md +msgid "Implemented as a [separate package that isn't dependent on a framework](https://github.com/yiisoft/cache)." +msgstr "Implementado como um [pacote separado que não depende de um framework](https://github.com/yiisoft/cache)." + +#. type: Title ### +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "PSR-17 HTTP factories" +msgstr "PSR-17 HTTP factories" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Use PSR factories." +msgstr "[x] Usar as factories PSR." + +#. type: Title ### +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "PSR-18 HTTP client" +msgstr "PSR-18 HTTP client" + +#. type: Title ## +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "Stricter types" +msgstr "Tipos mais estritos" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Make sure type hinting is used everywhere." +msgstr "[x] Garantir que type hints sejam usados em todo lugar." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Make sure types are as definitive as possible. Avoid varying types if possible." +msgstr "[x] Garantir que os tipos sejam o mais definidos possível. Evitar tipos variáveis sempre que possível." + +#. type: Title ## +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "Single application template" +msgstr "Template de aplicação único" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Drop basic/advanced." +msgstr "[x] Abandonar basic/advanced." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Create a [single application template that works out of the box](https://github.com/yiisoft/app)." +msgstr "[x] Criar um [template de aplicação único que funcione de imediato](https://github.com/yiisoft/app)." + +#. type: Title ## +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "Router" +msgstr "Router" + +#. type: Plain text +#: ../src/internals/003-roadmap.md +msgid "Implemented as a [separate package that isn't dependent on a framework](https://github.com/yiisoft/router)." +msgstr "Implementado como um [pacote separado que não depende de um framework](https://github.com/yiisoft/router)." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] DSL for configuration." +msgstr "[x] DSL para configuração." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Ability to route to any callable." +msgstr "[x] Possibilidade de rotear para qualquer callable." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Named routes." +msgstr "[x] Rotas nomeadas." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Route groups w/ middleware support." +msgstr "[x] Grupos de rotas com suporte a middleware." + +#. type: Title ## +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "Best practices and SOLID compliance of all classes/packages" +msgstr "Boas práticas e conformidade com SOLID em todas as classes/pacotes" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Make sure interfaces follow the \"interface segregation\" principle." +msgstr "[x] Garantir que as interfaces sigam o princípio de \"segregação de interfaces\"." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Don't use public properties." +msgstr "[x] Não usar propriedades públicas." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Don't use `init()`." +msgstr "[x] Não usar `init()`." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Don't inherit from `BaseObject` or `Component`. Remove these." +msgstr "[x] Não herdar de `BaseObject` ou `Component`. Removê-los." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] No globals." +msgstr "[x] Nada de globais." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] No static calls except helpers that are final." +msgstr "[x] Nada de chamadas estáticas, exceto helpers finais." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Prefer throwing exceptions to fixing input." +msgstr "[x] Preferir lançar exceções a corrigir a entrada." + +#. type: Title ## +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "Development toolkit" +msgstr "Kit de ferramentas de desenvolvimento" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Release command line tool" +msgstr "[x] Ferramenta de linha de comando para release" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Development command line tool (symlinks packages into usable application)" +msgstr "[x] Ferramenta de linha de comando para desenvolvimento (cria symlinks dos pacotes em uma aplicação utilizável)" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Separate web and console application" +msgstr "[x] Separar aplicação web e aplicação de console" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Possibly eliminate base application (still needed)" +msgstr "[x] Possivelmente eliminar a aplicação base (ainda é necessária)" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Create an interface for the console (using Symfony one)" +msgstr "[x] Criar uma interface para o console (usando a do Symfony)" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Implementation may be one of the popular ones (using Symfony one)" +msgstr "[x] A implementação pode ser uma das populares (usando a do Symfony)" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Ensure application can add commands via config" +msgstr "[x] Garantir que a aplicação possa adicionar comandos via configuração" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[ ] Follow best practices." +msgstr "[ ] Seguir boas práticas." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[ ] Don't use the \"MVC\" term." +msgstr "[ ] Não usar o termo \"MVC\"." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[ ] Upgrading from Yii 2." +msgstr "[ ] Upgrade a partir do Yii 2." + +#. type: Title ## +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "RBAC" +msgstr "RBAC" + +#. type: Plain text +#: ../src/internals/003-roadmap.md +msgid "RBAC is implemented as [a framework-independent package](https://github.com/yiisoft/rbac)." +msgstr "O RBAC é implementado como [um pacote independente de framework](https://github.com/yiisoft/rbac)." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Make sure it follows best practices." +msgstr "[x] Garantir que siga boas práticas." + +#. type: Title ## +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "View" +msgstr "View" + +#. type: Plain text +#: ../src/internals/003-roadmap.md +msgid "View is implemented as [framework-independent package](https://github.com/yiisoft/view)." +msgstr "A view é implementada como [pacote independente de framework](https://github.com/yiisoft/view)." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Finish refactoring ([see issues](https://github.com/yiisoft/view/issues))." +msgstr "[x] Terminar a refatoração ([veja as issues](https://github.com/yiisoft/view/issues))." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Port widgets." +msgstr "[x] Portar os widgets." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Rethink and implement active form widgets." +msgstr "[x] Repensar e implementar os widgets de active form." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Implement caching widgets." +msgstr "[x] Implementar widgets de cache." + +#. type: Title ## +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "Data abstractions and grid" +msgstr "Abstrações de dados e grid" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Finish [data abstractions](https://github.com/yiisoft/data)." +msgstr "[x] Terminar as [abstrações de dados](https://github.com/yiisoft/data)." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Port sort, use data abstractions. Should be part of [yii-dataview](https://github.com/yiisoft/yii-dataview)." +msgstr "[x] Portar a ordenação, usando abstrações de dados. Deve fazer parte do [yii-dataview](https://github.com/yiisoft/yii-dataview)." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Port paging, use data abstractions. Should be part of [yii-dataview](https://github.com/yiisoft/yii-dataview)." +msgstr "[x] Portar a paginação, usando abstrações de dados. Deve fazer parte do [yii-dataview](https://github.com/yiisoft/yii-dataview)." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Port grid, use data abstractions. Should be part of [yii-dataview](https://github.com/yiisoft/yii-dataview)." +msgstr "[x] Portar o grid, usando abstrações de dados. Deve fazer parte do [yii-dataview](https://github.com/yiisoft/yii-dataview)." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Port list, use data abstractions. Should be part of [yii-dataview](https://github.com/yiisoft/yii-dataview)." +msgstr "[x] Portar a lista, usando abstrações de dados. Deve fazer parte do [yii-dataview](https://github.com/yiisoft/yii-dataview)." + +#. type: Title ## +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "Validators" +msgstr "Validadores" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Finish [the main package](https://github.com/yiisoft/validator) redesign" +msgstr "[x] Terminar o redesign do [pacote principal](https://github.com/yiisoft/validator)" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Port necessary validators" +msgstr "[x] Portar os validadores necessários" + +#. type: Title ## +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "Debug toolbar" +msgstr "Debug toolbar" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Port debug toolbar." +msgstr "[x] Portar a debug toolbar." + +#. type: Title ## +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "Gii" +msgstr "Gii" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Port Gii." +msgstr "[x] Portar o Gii." + +#. type: Title ## +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "Infrastructure" +msgstr "Infraestrutura" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Cover [config](https://github.com/yiisoft/config) with tests." +msgstr "[x] Cobrir o [config](https://github.com/yiisoft/config) com testes." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Release stable [config](https://github.com/yiisoft/config)." +msgstr "[x] Lançar uma versão estável do [config](https://github.com/yiisoft/config)." + +#. type: Title ## +#: ../src/internals/003-roadmap.md ../src/internals/022-config-groups.md +#, no-wrap +msgid "Others" +msgstr "Outros" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] [Decide on namespaces](https://forum.yiiframework.com/t/lowercase-or-camelcase-namespaces/124983/52)." +msgstr "[x] [Decidir sobre os namespaces](https://forum.yiiframework.com/t/lowercase-or-camelcase-namespaces/124983/52)." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] [Clean up error handler](https://github.com/yiisoft/yii2/issues/14348). Make sure the error handler catches fatals and is using response." +msgstr "[x] [Limpar o error handler](https://github.com/yiisoft/yii2/issues/14348). Garantir que o error handler capture erros fatais e use a resposta." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Make validators independent of models to allow reusing them in handlers." +msgstr "[x] Tornar os validadores independentes dos models para permitir reutilizá-los em handlers." + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] [Split IdentityInterface](https://github.com/yiisoft/yii2/issues/13825)." +msgstr "[x] [Dividir a IdentityInterface](https://github.com/yiisoft/yii2/issues/13825)." diff --git a/_translations/po/pt-BR/internals_004-namespaces.md.po b/_translations/po/pt-BR/internals_004-namespaces.md.po new file mode 100644 index 00000000..9569903d --- /dev/null +++ b/_translations/po/pt-BR/internals_004-namespaces.md.po @@ -0,0 +1,81 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 08:02+0000\n" +"PO-Revision-Date: 2025-12-24 08:02+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/en/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md ../src/en/guide/concept/autoloading.md ../src/en/guide/security/best-practices.md ../src/en/guide/structure/domain.md ../src/en/guide/tutorial/console-applications.md ../src/en/internals/004-namespaces.md ../src/en/internals/007-exceptions.md ../src/en/internals/008-interfaces.md +#, no-wrap +msgid "References" +msgstr "Referências" + +#. type: Title # +#: ../src/en/internals/004-namespaces.md +#, no-wrap +msgid "004 — Namespaces" +msgstr "004 — Namespaces" + +#. type: Plain text +#: ../src/en/internals/004-namespaces.md +msgid "Package namespace rules are the following:" +msgstr "As regras de namespace dos pacotes são as seguintes:" + +#. type: Bullet: '1. ' +#: ../src/en/internals/004-namespaces.md +msgid "PascalCase is used for namespace parts." +msgstr "As partes do namespace usam PascalCase." + +#. type: Bullet: '2. ' +#: ../src/en/internals/004-namespaces.md +msgid "Root vendor namespace is `Yiisoft`." +msgstr "O namespace raiz do vendor é `Yiisoft`." + +#. type: Bullet: '3. ' +#: ../src/en/internals/004-namespaces.md +msgid "Package name parts are used in namespace." +msgstr "As partes do nome do pacote são usadas no namespace." + +#. type: Bullet: '4. ' +#: ../src/en/internals/004-namespaces.md +msgid "Adjective is added to a noun and is a single part." +msgstr "Um adjetivo é unido ao substantivo e forma uma única parte." + +#. type: Plain text +#: ../src/en/internals/004-namespaces.md +msgid "Some examples:" +msgstr "Alguns exemplos:" + +#. type: Plain text +#: ../src/en/internals/004-namespaces.md +#, no-wrap +msgid "" +"| Package | Namespace |\n" +"|----------------------------|---------------------------|\n" +"| yiisoft/yii-web | Yiisoft\\Yii\\Web |\n" +"| yiisoft/di | Yiisoft\\Di |\n" +"| yiisoft/db-mysql | Yiisoft\\Db\\Mysql |\n" +"| yiisoft/friendly-exception | Yiisoft\\FriendlyException |\n" +msgstr "" +"| Pacote | Namespace |\n" +"|----------------------------|---------------------------|\n" +"| yiisoft/yii-web | Yiisoft\\Yii\\Web |\n" +"| yiisoft/di | Yiisoft\\Di |\n" +"| yiisoft/db-mysql | Yiisoft\\Db\\Mysql |\n" +"| yiisoft/friendly-exception | Yiisoft\\FriendlyException |\n" + +#. type: Bullet: '- ' +#: ../src/en/internals/004-namespaces.md +msgid "[International forum discussion](https://forum.yiiframework.com/t/use-yiisoft-as-a-root-namespace-instead-of-yii-for-yii-3-packages/125734)" +msgstr "[Discussão no fórum internacional](https://forum.yiiframework.com/t/use-yiisoft-as-a-root-namespace-instead-of-yii-for-yii-3-packages/125734)" diff --git a/_translations/po/pt-BR/internals_005-development-tool.md.po b/_translations/po/pt-BR/internals_005-development-tool.md.po new file mode 100644 index 00000000..2646f725 --- /dev/null +++ b/_translations/po/pt-BR/internals_005-development-tool.md.po @@ -0,0 +1,108 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 08:02+0000\n" +"PO-Revision-Date: 2025-12-24 08:02+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/en/internals/005-development-tool.md +#, no-wrap +msgid "005 — Yii development tool" +msgstr "005 — Ferramenta de desenvolvimento do Yii" + +#. type: Plain text +#: ../src/en/internals/005-development-tool.md +msgid "For Yii3, the number of packages increased significantly to achieve more reusability and independent releases. To ease development of the framework itself, we've created a special tool available from [yiisoft/yii-dev-tool](https://github.com/yiisoft/yii-dev-tool)." +msgstr "No Yii3, o número de pacotes aumentou bastante para permitir mais reuso e releases independentes. Para facilitar o desenvolvimento do próprio framework, criamos uma ferramenta especial, disponível em [yiisoft/yii-dev-tool](https://github.com/yiisoft/yii-dev-tool)." + +#. type: Fenced code block +#: ../src/en/internals/005-development-tool.md +#, no-wrap +msgid "" +"$ ./yii-dev\n" +" _ _ _ _\n" +" | | | |(_)(_) Development Tool\n" +" | |_| || || |\n" +" \\__, ||_||_| for Yii 3.0\n" +" |___/\n" +"\n" +"This tool helps with setting up a development environment for Yii 3 packages.\n" +"\n" +"Usage:\n" +" command [options] [arguments]\n" +"\n" +"Options:\n" +" -h, --help Display this help message\n" +"\n" +"Available commands:\n" +" checkout-branch Creates, if not exists, and checkout a git branch\n" +" commit Add and commit changes into each package repository\n" +" install Install packages\n" +" lint Check packages according to PSR12 standard\n" +" pull Pull changes from package repositories\n" +" push Push changes into package repositories\n" +" replicate Copy files specified in replicate.php into each package\n" +" status Show git status of packages\n" +" update Update packages\n" +msgstr "" +"$ ./yii-dev\n" +" _ _ _ _\n" +" | | | |(_)(_) Development Tool\n" +" | |_| || || |\n" +" \\__, ||_||_| for Yii 3.0\n" +" |___/\n" +"\n" +"This tool helps with setting up a development environment for Yii 3 packages.\n" +"\n" +"Usage:\n" +" command [options] [arguments]\n" +"\n" +"Options:\n" +" -h, --help Display this help message\n" +"\n" +"Available commands:\n" +" checkout-branch Creates, if not exists, and checkout a git branch\n" +" commit Add and commit changes into each package repository\n" +" install Install packages\n" +" lint Check packages according to PSR12 standard\n" +" pull Pull changes from package repositories\n" +" push Push changes into package repositories\n" +" replicate Copy files specified in replicate.php into each package\n" +" status Show git status of packages\n" +" update Update packages\n" + +#. type: Plain text +#: ../src/en/internals/005-development-tool.md +msgid "There are many commands available. The most important ones are `install` and `update`. What it does is:" +msgstr "Há muitos comandos disponíveis. Os mais importantes são `install` e `update`. O que eles fazem:" + +#. type: Bullet: '1. ' +#: ../src/en/internals/005-development-tool.md +msgid "Install/update all packages listed in [`packages.php`](https://github.com/yiisoft/yii-dev-tool/blob/master/packages.php) or individual package from that list if specified." +msgstr "Instalam/atualizam todos os pacotes listados em [`packages.php`](https://github.com/yiisoft/yii-dev-tool/blob/master/packages.php) ou um pacote específico dessa lista, se informado." + +#. type: Bullet: '2. ' +#: ../src/en/internals/005-development-tool.md +msgid "For every package installed check `vendor` directory for packages listed in `packages.php`. If there is any, replace the package directory with a symlink to another package source." +msgstr "Para cada pacote instalado, verificam no diretório `vendor` se há pacotes listados em `packages.php`. Se houver, substituem o diretório do pacote por um symlink para o código-fonte do outro pacote." + +#. type: Plain text +#: ../src/en/internals/005-development-tool.md +msgid "As a result, you will have many packages using each other, so there is no need to `git push` and `composer install` / `composer update` during development." +msgstr "Como resultado, você terá muitos pacotes usando uns aos outros, sem precisar de `git push` e `composer install` / `composer update` durante o desenvolvimento." + +#. type: Plain text +#: ../src/en/internals/005-development-tool.md +msgid "A [detailed example](https://github.com/yiisoft/yii-dev-tool#usage-example) of using the tool is available in its README." +msgstr "Um [exemplo detalhado](https://github.com/yiisoft/yii-dev-tool#usage-example) de uso da ferramenta está disponível no README dela." diff --git a/_translations/po/pt-BR/internals_006-git-commit-messages.md.po b/_translations/po/pt-BR/internals_006-git-commit-messages.md.po new file mode 100644 index 00000000..ad343a12 --- /dev/null +++ b/_translations/po/pt-BR/internals_006-git-commit-messages.md.po @@ -0,0 +1,74 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 08:02+0000\n" +"PO-Revision-Date: 2025-12-24 08:02+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/en/guide/runtime/request.md ../src/en/guide/runtime/response.md ../src/en/internals/006-git-commit-messages.md +#, no-wrap +msgid "Body" +msgstr "Corpo" + +#. type: Title # +#: ../src/en/internals/006-git-commit-messages.md +#, no-wrap +msgid "006 — Git commit messages" +msgstr "006 — Mensagens de commit do Git" + +#. type: Title ## +#: ../src/en/internals/006-git-commit-messages.md +#, no-wrap +msgid "Subject line" +msgstr "Linha de assunto" + +#. type: Bullet: '- ' +#: ../src/en/internals/006-git-commit-messages.md +msgid "Use `#123` to reference issue by number" +msgstr "Use `#123` para referenciar uma issue pelo número" + +#. type: Bullet: '- ' +#: ../src/en/internals/006-git-commit-messages.md +msgid "Use imperative mood that's `Fix`, not `Fixed`" +msgstr "Use o modo imperativo, ou seja, `Fix`, e não `Fixed`" + +#. type: Bullet: '- ' +#: ../src/en/internals/006-git-commit-messages.md +msgid "Don't add a period at the end" +msgstr "Não coloque ponto final" + +#. type: Bullet: '- ' +#: ../src/en/internals/006-git-commit-messages.md +msgid "Use `[skip ci]` if there is no need to run unit tests" +msgstr "Use `[skip ci]` se não houver necessidade de rodar os testes unitários" + +#. type: Bullet: '- ' +#: ../src/en/internals/006-git-commit-messages.md +msgid "Start with a capital letter" +msgstr "Comece com letra maiúscula" + +#. type: Bullet: '- ' +#: ../src/en/internals/006-git-commit-messages.md +msgid "Limit to 50 characters" +msgstr "Limite a 50 caracteres" + +#. type: Plain text +#: ../src/en/internals/006-git-commit-messages.md +msgid "Use the message body **if** you need an extra explanation. Explain why, not how." +msgstr "Use o corpo da mensagem **se** precisar de uma explicação extra. Explique o porquê, não o como." + +#. type: Bullet: '- ' +#: ../src/en/internals/006-git-commit-messages.md +msgid "Limit line length to 72 characters" +msgstr "Limite o tamanho das linhas a 72 caracteres" diff --git a/_translations/po/pt-BR/internals_007-exceptions.md.po b/_translations/po/pt-BR/internals_007-exceptions.md.po new file mode 100644 index 00000000..bcb25445 --- /dev/null +++ b/_translations/po/pt-BR/internals_007-exceptions.md.po @@ -0,0 +1,63 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 08:02+0000\n" +"PO-Revision-Date: 2025-12-24 08:02+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/en/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md ../src/en/guide/concept/autoloading.md ../src/en/guide/security/best-practices.md ../src/en/guide/structure/domain.md ../src/en/guide/tutorial/console-applications.md ../src/en/internals/004-namespaces.md ../src/en/internals/007-exceptions.md ../src/en/internals/008-interfaces.md +#, no-wrap +msgid "References" +msgstr "Referências" + +#. type: Title # +#: ../src/en/internals/007-exceptions.md +#, no-wrap +msgid "007 — Exceptions" +msgstr "007 — Exceções" + +#. type: Bullet: '- ' +#: ../src/en/internals/007-exceptions.md +msgid "Throw exceptions instead of returning an error code." +msgstr "Lance exceções em vez de retornar um código de erro." + +#. type: Bullet: '- ' +#: ../src/en/internals/007-exceptions.md +msgid "Exception class name must be suffixed with `Exception`." +msgstr "O nome da classe de exceção deve ter o sufixo `Exception`." + +#. type: Bullet: '- ' +#: ../src/en/internals/007-exceptions.md +msgid "Use grammatically correct error messages including ending punctuation, that's most exceptions must end with a period." +msgstr "Use mensagens de erro gramaticalmente corretas, incluindo a pontuação final, ou seja, a maioria das exceções deve terminar com ponto." + +#. type: Bullet: '- ' +#: ../src/en/internals/007-exceptions.md +msgid "`\\InvalidArgumentException` must be used directly. There should be no exceptions inherited from it." +msgstr "`\\InvalidArgumentException` deve ser usada diretamente. Não deve haver exceções herdadas dela." + +#. type: Bullet: '- ' +#: ../src/en/internals/007-exceptions.md +msgid "`\\InvalidArgumentException` must never be caught." +msgstr "`\\InvalidArgumentException` nunca deve ser capturada." + +#. type: Bullet: '- ' +#: ../src/en/internals/007-exceptions.md +msgid "[International community discussion and poll](https://forum.yiiframework.com/t/naming-exceptions/126613/6)" +msgstr "[Discussão e enquete na comunidade internacional](https://forum.yiiframework.com/t/naming-exceptions/126613/6)" + +#. type: Bullet: '- ' +#: ../src/en/internals/007-exceptions.md +msgid "[Russian community discussion and poll](https://yiiframework.ru/forum/viewtopic.php?f=39&t=51290)" +msgstr "[Discussão e enquete na comunidade russa](https://yiiframework.ru/forum/viewtopic.php?f=39&t=51290)" diff --git a/_translations/po/pt-BR/internals_008-interfaces.md.po b/_translations/po/pt-BR/internals_008-interfaces.md.po new file mode 100644 index 00000000..5e5ec5c3 --- /dev/null +++ b/_translations/po/pt-BR/internals_008-interfaces.md.po @@ -0,0 +1,43 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 08:02+0000\n" +"PO-Revision-Date: 2025-12-24 08:02+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/en/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md ../src/en/guide/concept/autoloading.md ../src/en/guide/security/best-practices.md ../src/en/guide/structure/domain.md ../src/en/guide/tutorial/console-applications.md ../src/en/internals/004-namespaces.md ../src/en/internals/007-exceptions.md ../src/en/internals/008-interfaces.md +#, no-wrap +msgid "References" +msgstr "Referências" + +#. type: Title # +#: ../src/en/internals/008-interfaces.md +#, no-wrap +msgid "008 — Interfaces" +msgstr "008 — Interfaces" + +#. type: Bullet: '- ' +#: ../src/en/internals/008-interfaces.md +msgid "Interface name should be suffixed with `Interface`." +msgstr "O nome da interface deve ter o sufixo `Interface`." + +#. type: Bullet: '- ' +#: ../src/en/internals/008-interfaces.md +msgid "[International community discussion and poll](https://forum.yiiframework.com/t/naming-interfaces/126612/5)" +msgstr "[Discussão e enquete na comunidade internacional](https://forum.yiiframework.com/t/naming-interfaces/126612/5)" + +#. type: Bullet: '- ' +#: ../src/en/internals/008-interfaces.md +msgid "[Russian community discussion and poll](https://yiiframework.ru/forum/viewtopic.php?f=39&t=51289)" +msgstr "[Discussão e enquete na comunidade russa](https://yiiframework.ru/forum/viewtopic.php?f=39&t=51289)" diff --git a/_translations/po/pt-BR/internals_009-design-decisions.md.po b/_translations/po/pt-BR/internals_009-design-decisions.md.po new file mode 100644 index 00000000..468d8dac --- /dev/null +++ b/_translations/po/pt-BR/internals_009-design-decisions.md.po @@ -0,0 +1,195 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 08:02+0000\n" +"PO-Revision-Date: 2025-12-24 08:02+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/en/internals/009-design-decisions.md +#, no-wrap +msgid "009 — Design Decisions" +msgstr "009 — Decisões de design" + +#. type: Plain text +#: ../src/en/internals/009-design-decisions.md +msgid "In this document, we list important design decisions taken during Yii3 development." +msgstr "Neste documento, listamos decisões de design importantes tomadas durante o desenvolvimento do Yii3." + +#. type: Title ## +#: ../src/en/internals/009-design-decisions.md +#, no-wrap +msgid "Remove magic properties" +msgstr "Remover propriedades mágicas" + +#. type: Plain text +#: ../src/en/internals/009-design-decisions.md +msgid "Magic properties in Yii 2 were an interesting idea that allowed a developer to start with public property and then seamlessly migrate to using getter/setter called via magic methods without changing the code." +msgstr "As propriedades mágicas do Yii 2 eram uma ideia interessante: permitiam ao desenvolvedor começar com uma propriedade pública e depois migrar de forma transparente para getter/setter chamados via métodos mágicos, sem mudar o código." + +#. type: Plain text +#: ../src/en/internals/009-design-decisions.md +msgid "The main reason for removal in Yii 3 is that it resulted in using public properties everywhere, thus lack of encapsulation and code fragility." +msgstr "O principal motivo da remoção no Yii 3 é que isso levava ao uso de propriedades públicas em todo lugar, resultando em falta de encapsulamento e código frágil." + +#. type: Title ## +#: ../src/en/internals/009-design-decisions.md +#, no-wrap +msgid "Remove the service locator" +msgstr "Remover o service locator" + +#. type: Plain text +#: ../src/en/internals/009-design-decisions.md +msgid "Service locator both Yii 1 and Yii 2 was convenient but was also abused a lot. Although a dependency injection container was available in Yii 2, service locator was generally preferred to cause both a dependency on the service locator itself, high coupling, hard to test code." +msgstr "O service locator, tanto no Yii 1 quanto no Yii 2, era conveniente, mas também muito abusado. Embora o Yii 2 tivesse um container de injeção de dependência, o service locator costumava ser preferido, o que causava dependência do próprio service locator, alto acoplamento e código difícil de testar." + +#. type: Plain text +#: ../src/en/internals/009-design-decisions.md +msgid "Yii 3 relies on dependency injection only lowering coupling significantly and making code way more testable." +msgstr "O Yii 3 usa apenas injeção de dependência, o que reduz bastante o acoplamento e torna o código muito mais testável." + +#. type: Title ## +#: ../src/en/internals/009-design-decisions.md +#, no-wrap +msgid "Extract general packages" +msgstr "Extrair pacotes de uso geral" + +#. type: Plain text +#: ../src/en/internals/009-design-decisions.md +msgid "Yii 1 and Yii 2 were fully closed communities. All the code we had wasn't useful outside Yii, and most of the \"external\" code wasn't useful in Yii without wrappers. It was noted many times by communities external to Yii that many parts of Yii are well-designed and unique, and they'd use these if these were available as standalone packages." +msgstr "O Yii 1 e o Yii 2 eram comunidades totalmente fechadas. Todo o código que tínhamos não era útil fora do Yii, e a maior parte do código \"externo\" não era útil no Yii sem wrappers. Comunidades de fora do Yii comentaram muitas vezes que várias partes do Yii são bem projetadas e únicas, e que as usariam se estivessem disponíveis como pacotes independentes." + +#. type: Plain text +#: ../src/en/internals/009-design-decisions.md +msgid "As part of Yii 3 packages such as cache, RBAC, view, etc. were extracted into framework-independent packages. Benefits are:" +msgstr "Como parte do Yii 3, pacotes como cache, RBAC, view etc. foram extraídos para pacotes independentes de framework. Os benefícios são:" + +#. type: Bullet: '- ' +#: ../src/en/internals/009-design-decisions.md +msgid "Increased usage and contribution" +msgstr "Mais uso e mais contribuições" + +#. type: Bullet: '- ' +#: ../src/en/internals/009-design-decisions.md +msgid "Yii team could delegate maintenance" +msgstr "O time do Yii pode delegar a manutenção" + +#. type: Bullet: '- ' +#: ../src/en/internals/009-design-decisions.md +msgid "Independent releases are possible" +msgstr "Releases independentes passam a ser possíveis" + +#. type: Title ## +#: ../src/en/internals/009-design-decisions.md +#, no-wrap +msgid "Adopt PSRs" +msgstr "Adotar PSRs" + +#. type: Plain text +#: ../src/en/internals/009-design-decisions.md +msgid "The team adopted some PSRs in Yii 2, such as PSR-4 and PSR-2. Interfaces in general weren't, although Yii is part of PHP-FIG. Mainly because when Yii 2 was released, these were either in the making or not adopted enough." +msgstr "O time adotou algumas PSRs no Yii 2, como a PSR-4 e a PSR-2. As interfaces, em geral, não foram adotadas, embora o Yii faça parte do PHP-FIG. Principalmente porque, quando o Yii 2 foi lançado, elas ainda estavam em elaboração ou não tinham adoção suficiente." + +#. type: Plain text +#: ../src/en/internals/009-design-decisions.md +msgid "Yii3 benefits from PSRs since there are nowadays many ready-to-use libraries that one can get via Composer: cache backends, middleware, loggers, DI containers, etc." +msgstr "O Yii3 se beneficia das PSRs, já que hoje existem muitas bibliotecas prontas para uso que você instala via Composer: backends de cache, middlewares, loggers, containers de DI etc." + +#. type: Plain text +#: ../src/en/internals/009-design-decisions.md +msgid "By implementing PSRs in general packages, we allow these to be used in more projects, thus raising the contribution level." +msgstr "Ao implementar PSRs nos pacotes de uso geral, permitimos que eles sejam usados em mais projetos, aumentando o nível de contribuição." + +#. type: Title ## +#: ../src/en/internals/009-design-decisions.md +#, no-wrap +msgid "Improve DI container" +msgstr "Melhorar o container de DI" + +#. type: Plain text +#: ../src/en/internals/009-design-decisions.md +msgid "The problem with the Yii 2 container was that it's tailored to be used with Yii 2 components. API isn't well-designed to be used with general PHP classes." +msgstr "O problema do container do Yii 2 era que ele foi feito sob medida para os componentes do Yii 2. A API não foi bem projetada para uso com classes PHP em geral." + +#. type: Plain text +#: ../src/en/internals/009-design-decisions.md +msgid "In Yii3, we ensured that container can be used to conveniently configure any PHP class." +msgstr "No Yii3, garantimos que o container possa ser usado para configurar qualquer classe PHP de forma conveniente." + +#. type: Plain text +#: ../src/en/internals/009-design-decisions.md +msgid "That should result in the absence of Yii-specific wrapper packages and more direct usages of Composer packages." +msgstr "Isso deve resultar na ausência de pacotes wrapper específicos do Yii e em mais uso direto de pacotes do Composer." + +#. type: Title ## +#: ../src/en/internals/009-design-decisions.md +#, no-wrap +msgid "Adopt strict types" +msgstr "Adotar strict types" + +#. type: Plain text +#: ../src/en/internals/009-design-decisions.md +msgid "Strict types were introduced because:" +msgstr "Os strict types foram introduzidos porque:" + +#. type: Bullet: '- ' +#: ../src/en/internals/009-design-decisions.md +msgid "PHP 7 is now mainstream" +msgstr "O PHP 7 agora é o padrão do mercado" + +#. type: Bullet: '- ' +#: ../src/en/internals/009-design-decisions.md +msgid "While they solve no significant Yii 2 problems, they help to avoid many day-to-day development issues" +msgstr "Embora não resolvam nenhum problema significativo do Yii 2, ajudam a evitar muitos problemas do dia a dia de desenvolvimento" + +#. type: Title ## +#: ../src/en/internals/009-design-decisions.md +#, no-wrap +msgid "Adopt SemVer" +msgstr "Adotar SemVer" + +#. type: Plain text +#: ../src/en/internals/009-design-decisions.md +msgid "Yii 2 has its own version policy. Problems:" +msgstr "O Yii 2 tem sua própria política de versões. Problemas:" + +#. type: Bullet: '- ' +#: ../src/en/internals/009-design-decisions.md +msgid "It wasn't standard" +msgstr "Não era um padrão" + +#. type: Bullet: '- ' +#: ../src/en/internals/009-design-decisions.md +msgid "Composer relies on SemVer" +msgstr "O Composer se baseia em SemVer" + +#. type: Bullet: '- ' +#: ../src/en/internals/009-design-decisions.md +msgid "It's hard to support a framework built on top of packages if the versioning policy isn't strict" +msgstr "É difícil manter um framework construído sobre pacotes se a política de versionamento não for rígida" + +#. type: Title ## +#: ../src/en/internals/009-design-decisions.md +#, no-wrap +msgid "Prevent validators mutating data" +msgstr "Impedir que validadores alterem dados" + +#. type: Plain text +#: ../src/en/internals/009-design-decisions.md +msgid "In Yii 1 and Yii 2, validators such as \"date\" were mutating data. It was confusing for a validation process not initially meant to mutate data it validates." +msgstr "No Yii 1 e no Yii 2, validadores como \"date\" alteravam os dados. Era confuso que um processo de validação, que a princípio não deveria alterar os dados que valida, fizesse isso." + +#. type: Plain text +#: ../src/en/internals/009-design-decisions.md +msgid "[See related discussion](https://forum.yiiframework.com/t/saving-or-killing-non-validation-in-validators/126086)." +msgstr "[Veja a discussão relacionada](https://forum.yiiframework.com/t/saving-or-killing-non-validation-in-validators/126086)." diff --git a/_translations/po/pt-BR/internals_010-code-style.md.po b/_translations/po/pt-BR/internals_010-code-style.md.po new file mode 100644 index 00000000..996d6064 --- /dev/null +++ b/_translations/po/pt-BR/internals_010-code-style.md.po @@ -0,0 +1,519 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-09-25 14:35+0000\n" +"PO-Revision-Date: 2026-09-25 14:35+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/guide/databases/db-migrations.md ../src/internals/010-code-style.md +#, no-wrap +msgid "Strings" +msgstr "Strings" + +#. type: Title # +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "010 — Code style" +msgstr "010 — Estilo de código" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Code formatting used in Yii 3 packages is based on [PER Coding Style 3.0](https://www.php-fig.org/per/coding-style/) with extra rules added on top of it." +msgstr "A formatação de código usada nos pacotes do Yii 3 é baseada no [PER Coding Style 3.0](https://www.php-fig.org/per/coding-style/) com regras extras adicionadas por cima." + +#. type: Title ### +#: ../src/internals/010-code-style.md ../src/internals/017-tags.md ../src/internals/018-widgets.md +#, no-wrap +msgid "Names" +msgstr "Nomes" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "Use English only." +msgstr "Use apenas inglês." + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "Use camelCase notation, including abbreviations (e.g., `enableIdn`)." +msgstr "Use a notação camelCase, inclusive em abreviações (por exemplo, `enableIdn`)." + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "Use the shortest possible, but an explanatory name." +msgstr "Use o nome mais curto possível, mas que seja explicativo." + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "Never trim or abbreviate a name." +msgstr "Nunca corte ou abrevie um nome." + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "Postfix classes, interfaces, traits and variables, which is a [collection](https://en.wikipedia.org/wiki/Collection_(abstract_data_type)), with `Collection`." +msgstr "Adicione o sufixo `Collection` a classes, interfaces, traits e variáveis que sejam uma [coleção](https://en.wikipedia.org/wiki/Collection_(abstract_data_type))." + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "Postfix middleware classes with `Middleware`." +msgstr "Adicione o sufixo `Middleware` às classes de middleware." + +#. type: Title ## +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Types" +msgstr "Tipos" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "Declare [argument and return types](https://www.php.net/manual/en/migration70.new-features.php) where possible." +msgstr "Declare [tipos de argumento e de retorno](https://www.php.net/manual/en/migration70.new-features.php) sempre que possível." + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "[Use types for properties](https://wiki.php.net/rfc/typed_properties_v2)." +msgstr "[Use tipos nas propriedades](https://wiki.php.net/rfc/typed_properties_v2)." + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "Use strict typing. Avoid mixed and union types where possible except compatible types such as `string|Stringable`." +msgstr "Use tipagem estrita. Evite tipos mixed e union sempre que possível, exceto tipos compatíveis como `string|Stringable`." + +#. type: Title ## +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Comments" +msgstr "Comentários" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Inline comments are to be avoided unless code couldn't be understood without them. A good example is a workaround for a bug in a certain PHP version." +msgstr "Evite comentários inline, a menos que o código não possa ser entendido sem eles. Um bom exemplo é um contorno para um bug em determinada versão do PHP." + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Method comment is necessary except it adds nothing to what method name and signature already has." +msgstr "O comentário de método é necessário, exceto quando não acrescenta nada ao que o nome e a assinatura do método já dizem." + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Class comment should describe the purpose of the class." +msgstr "O comentário de classe deve descrever o propósito da classe." + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "See [PHPDoc](014-docs.md#phpdoc)." +msgstr "Veja [PHPDoc](014-docs.md#phpdoc)." + +#. type: Title ## +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Formatting" +msgstr "Formatação" + +#. type: Title ### +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Line length" +msgstr "Tamanho da linha" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "The maximum line length is 120 characters." +msgstr "O tamanho máximo da linha é de 120 caracteres." + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "When a function or method call exceeds the limit, split arguments into separate lines:" +msgstr "Quando uma chamada de função ou método excede o limite, separe os argumentos em linhas distintas:" + +#. type: Fenced code block (php) +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "" +"$this->assertSame(\n" +" ['' => ['Value must be no less than 5.']],\n" +" $result->getErrorMessagesIndexedByPath(),\n" +");\n" +msgstr "" +"$this->assertSame(\n" +" ['' => ['Value must be no less than 5.']],\n" +" $result->getErrorMessagesIndexedByPath(),\n" +");\n" + +#. type: Title ### +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "No alignment" +msgstr "Sem alinhamento" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Property, variable and constant value assignments shouldn't be aligned. The same applies to phpdoc tags. The reason is that aligned statements often cause larger diff and even conflicts." +msgstr "Atribuições de valores a propriedades, variáveis e constantes não devem ser alinhadas. O mesmo vale para as tags phpdoc. O motivo é que instruções alinhadas costumam gerar diffs maiores e até conflitos." + +#. type: Fenced code block (php) +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "" +"final class X\n" +"{\n" +" const A = 'test';\n" +" const BBB = 'test';\n" +" \n" +" private int $property = 42;\n" +" private int $test = 123;\n" +" \n" +" /**\n" +" * @param int $number Just a number.\n" +" * @param array $options Well... options!\n" +" */\n" +" public function doIt(int $number, array $options): void\n" +" {\n" +" $test = 123;\n" +" $anotherTest = 123;\n" +" }\n" +"}\n" +msgstr "" +"final class X\n" +"{\n" +" const A = 'test';\n" +" const BBB = 'test';\n" +" \n" +" private int $property = 42;\n" +" private int $test = 123;\n" +" \n" +" /**\n" +" * @param int $number Just a number.\n" +" * @param array $options Well... options!\n" +" */\n" +" public function doIt(int $number, array $options): void\n" +" {\n" +" $test = 123;\n" +" $anotherTest = 123;\n" +" }\n" +"}\n" + +#. type: Title ### +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Chain calls" +msgstr "Chamadas encadeadas" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Chained calls should be formatted for better readability. If it's a long chain that doesn't fit the line length of 120 characters, then each call should on a new line:" +msgstr "Chamadas encadeadas devem ser formatadas para melhor legibilidade. Se for uma cadeia longa que não cabe no limite de 120 caracteres por linha, cada chamada deve ficar em uma nova linha:" + +#. type: Fenced code block (php) +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "" +"$object\n" +" ->withName('test')\n" +" ->withValue(87)\n" +" ->withStatus(Status::NEW)\n" +" ->withAuthor($author)\n" +" ->withDeadline($deadline);\n" +msgstr "" +"$object\n" +" ->withName('test')\n" +" ->withValue(87)\n" +" ->withStatus(Status::NEW)\n" +" ->withAuthor($author)\n" +" ->withDeadline($deadline);\n" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "If it's a short chain, it's alright for it to be on a single line:" +msgstr "Se for uma cadeia curta, não há problema em deixá-la em uma única linha:" + +#. type: Fenced code block (php) +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "$object = $object->withName('test');\n" +msgstr "$object = $object->withName('test');\n" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "When no variables involved, use `'Hello!'`" +msgstr "Quando não houver variáveis envolvidas, use `'Hello!'`" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "To get variables into string prefer `\"Hello, $username!\"`" +msgstr "Para inserir variáveis na string, prefira `\"Hello, $username!\"`" + +#. type: Title ## +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Classes and interfaces" +msgstr "Classes e interfaces" + +#. type: Title ### +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Final by default" +msgstr "Final por padrão" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Classes should be `final` by default." +msgstr "As classes devem ser `final` por padrão." + +#. type: Title ### +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Private by default" +msgstr "Private por padrão" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Constants, properties and methods should be private by default." +msgstr "Constantes, propriedades e métodos devem ser private por padrão." + +#. type: Title ### +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Composition over inheritance" +msgstr "Composição em vez de herança" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Prefer [composition to inheritance](../guide/concept/di-container.md)." +msgstr "Prefira [composição a herança](../guide/concept/di-container.md)." + +#. type: Title ### +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Property, constant and method order" +msgstr "Ordem de propriedades, constantes e métodos" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Order should be the following:" +msgstr "A ordem deve ser a seguinte:" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "Constants" +msgstr "Constantes" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "Properties" +msgstr "Propriedades" + +#. type: Title ## +#: ../src/internals/010-code-style.md ../src/internals/017-tags.md ../src/internals/018-widgets.md +#, no-wrap +msgid "Methods" +msgstr "Métodos" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Within each category, items should be sorted by visibility:" +msgstr "Dentro de cada categoria, os itens devem ser ordenados por visibilidade:" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "public" +msgstr "public" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "protected" +msgstr "protected" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "private" +msgstr "private" + +#. type: Title ### +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Abstract classes" +msgstr "Classes abstratas" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Abstract classes *shouldn't* be prefixed or postfixed with `Abstract`." +msgstr "Classes abstratas *não devem* ter o prefixo ou sufixo `Abstract`." + +#. type: Title #### +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Immutable methods" +msgstr "Métodos imutáveis" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Immutable method convention is the following:" +msgstr "A convenção para métodos imutáveis é a seguinte:" + +#. type: Fenced code block (php) +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "" +"public function withName(string $name): self\n" +"{\n" +" $new = clone $this;\n" +" $new->name = $name;\n" +" return $new; \n" +"}\n" +msgstr "" +"public function withName(string $name): self\n" +"{\n" +" $new = clone $this;\n" +" $new->name = $name;\n" +" return $new; \n" +"}\n" + +#. type: Bullet: '1. ' +#: ../src/internals/010-code-style.md +msgid "Cloned object name is `$new`." +msgstr "O nome do objeto clonado é `$new`." + +#. type: Bullet: '2. ' +#: ../src/internals/010-code-style.md +msgid "Return type is `self`." +msgstr "O tipo de retorno é `self`." + +#. type: Title #### +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Boolean check methods" +msgstr "Métodos de verificação booleana" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Methods that are there to check if something is true should be named like the following:" +msgstr "Métodos que servem para verificar se algo é verdadeiro devem ser nomeados assim:" + +#. type: Fenced code block (php) +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "" +"public function isDeleted(): bool;\n" +"public function hasName(): bool;\n" +"public function canDoIt(): bool;\n" +msgstr "" +"public function isDeleted(): bool;\n" +"public function hasName(): bool;\n" +"public function canDoIt(): bool;\n" + +#. type: Title #### +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Flags in methods " +msgstr "Flags em métodos " + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Boolean flags in methods are better to be avoided. It's a sign the method may be doing too much, and there should be two methods instead of one." +msgstr "É melhor evitar flags booleanas em métodos. Elas são um sinal de que o método pode estar fazendo coisas demais e de que deveria haver dois métodos em vez de um." + +#. type: Fenced code block (php) +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "public function login(bool $refreshPage = true): void;\n" +msgstr "public function login(bool $refreshPage = true): void;\n" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "It is better to be two methods:" +msgstr "É melhor que sejam dois métodos:" + +#. type: Fenced code block (php) +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "" +"public function login(): void;\n" +"public function refreshPage(): void;\n" +msgstr "" +"public function login(): void;\n" +"public function refreshPage(): void;\n" + +#. type: Title ## +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Variables" +msgstr "Variáveis" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Add an underscore (`_`) prefix for unused variables. For example:" +msgstr "Adicione o prefixo sublinhado (`_`) em variáveis não usadas. Por exemplo:" + +#. type: Fenced code block (php) +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "" +"foreach ($items as $key => $_value) {\n" +" echo $key;\n" +"}\n" +msgstr "" +"foreach ($items as $key => $_value) {\n" +" echo $key;\n" +"}\n" + +#. type: Title ## +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Imports" +msgstr "Imports" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Prefer importing classes and functions to using fully qualified names:" +msgstr "Prefira importar classes e funções a usar nomes totalmente qualificados:" + +#. type: Fenced code block (php) +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "" +"use Yiisoft\\Arrays\\ArrayHelper;\n" +"use Yiisoft\\Validator\\DataSetInterface;\n" +"use Yiisoft\\Validator\\HasValidationErrorMessage;\n" +"use Yiisoft\\Validator\\Result;\n" +"\n" +"use function is_iterable;\n" +msgstr "" +"use Yiisoft\\Arrays\\ArrayHelper;\n" +"use Yiisoft\\Validator\\DataSetInterface;\n" +"use Yiisoft\\Validator\\HasValidationErrorMessage;\n" +"use Yiisoft\\Validator\\Result;\n" +"\n" +"use function is_iterable;\n" + +#. type: Title ## +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Additional conventions" +msgstr "Convenções adicionais" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "[Namespaces](004-namespaces.md)" +msgstr "[Namespaces](004-namespaces.md)" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "[Exceptions](007-exceptions.md)" +msgstr "[Exceções](007-exceptions.md)" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "[Interfaces](008-interfaces.md)" +msgstr "[Interfaces](008-interfaces.md)" diff --git a/_translations/po/pt-BR/internals_011-error-correction.md.po b/_translations/po/pt-BR/internals_011-error-correction.md.po new file mode 100644 index 00000000..a413d3c0 --- /dev/null +++ b/_translations/po/pt-BR/internals_011-error-correction.md.po @@ -0,0 +1,27 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 08:02+0000\n" +"PO-Revision-Date: 2025-12-24 08:02+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/en/internals/011-error-correction.md +#, no-wrap +msgid "011 — Error correction" +msgstr "011 — Correção de erros" + +#. type: Plain text +#: ../src/en/internals/011-error-correction.md +msgid "If it's unambiguous within a class what the developer who incorrectly used the class meant, it's OK to correct the error. Otherwise, the error MUST NOT be corrected." +msgstr "Se, dentro de uma classe, não houver ambiguidade sobre o que o desenvolvedor que usou a classe de forma incorreta quis dizer, não há problema em corrigir o erro. Caso contrário, o erro NÃO DEVE ser corrigido." diff --git a/_translations/po/pt-BR/internals_012-tests.md.po b/_translations/po/pt-BR/internals_012-tests.md.po new file mode 100644 index 00000000..a14be574 --- /dev/null +++ b/_translations/po/pt-BR/internals_012-tests.md.po @@ -0,0 +1,72 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 08:02+0000\n" +"PO-Revision-Date: 2025-12-24 08:02+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/en/internals/012-tests.md +#, no-wrap +msgid "012 — Tests" +msgstr "012 — Testes" + +#. type: Plain text +#: ../src/en/internals/012-tests.md +msgid "For each package, we're adding unit-tests that are run via [PHPUnit](https://phpunit.de/). When designing tests, the following guidelines should be taken into account." +msgstr "Para cada pacote, adicionamos testes unitários executados com o [PHPUnit](https://phpunit.de/). Ao projetar os testes, leve em conta as diretrizes a seguir." + +#. type: Bullet: '- ' +#: ../src/en/internals/012-tests.md +msgid "Test class should be marked as `final` by default." +msgstr "A classe de teste deve ser marcada como `final` por padrão." + +#. type: Bullet: '- ' +#: ../src/en/internals/012-tests.md +msgid "`@test` annotation must not be used, prefix methods with `test`." +msgstr "A anotação `@test` não deve ser usada; use o prefixo `test` nos métodos." + +#. type: Bullet: '- ' +#: ../src/en/internals/012-tests.md +msgid "The test method name must reflect the purpose of the test." +msgstr "O nome do método de teste deve refletir o propósito do teste." + +#. type: Bullet: '- ' +#: ../src/en/internals/012-tests.md +msgid "\"should\" must not be used in the test method name." +msgstr "\"should\" não deve ser usado no nome do método de teste." + +#. type: Bullet: '- ' +#: ../src/en/internals/012-tests.md +msgid "If necessary, the test method phpdoc may describe the desired behavior." +msgstr "Se necessário, o phpdoc do método de teste pode descrever o comportamento esperado." + +#. type: Bullet: '- ' +#: ../src/en/internals/012-tests.md +msgid "The test must follow AAA: first arrange the necessary preconditions, then act, then assert expected results." +msgstr "O teste deve seguir o AAA: primeiro prepare (arrange) as pré-condições necessárias, depois aja (act) e, por fim, verifique (assert) os resultados esperados." + +#. type: Bullet: '- ' +#: ../src/en/internals/012-tests.md +msgid "There must be one test case per test method that's a single AAA." +msgstr "Deve haver um caso de teste por método de teste, ou seja, um único AAA." + +#. type: Bullet: '- ' +#: ../src/en/internals/012-tests.md +msgid "Test must use public API. Private properties or methods shouldn't be accessed, assumptions on internals of the class tested shouldn't be made." +msgstr "O teste deve usar a API pública. Não se deve acessar propriedades ou métodos privados, nem fazer suposições sobre os detalhes internos da classe testada." + +#. type: Bullet: '- ' +#: ../src/en/internals/012-tests.md +msgid "Tests shouldn't rely on composer-config-plugin and DI container unless necessary." +msgstr "Os testes não devem depender do composer-config-plugin nem do container de DI, a menos que seja necessário." diff --git a/_translations/po/pt-BR/internals_013-code-review.md.po b/_translations/po/pt-BR/internals_013-code-review.md.po new file mode 100644 index 00000000..60c30b75 --- /dev/null +++ b/_translations/po/pt-BR/internals_013-code-review.md.po @@ -0,0 +1,119 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 08:02+0000\n" +"PO-Revision-Date: 2025-12-24 08:02+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/en/internals/013-code-review.md +#, no-wrap +msgid "013 — Code review" +msgstr "013 — Code review" + +#. type: Plain text +#: ../src/en/internals/013-code-review.md +msgid "Code reviews are essential for the success of the project and are as important as contributing code." +msgstr "Code reviews são essenciais para o sucesso do projeto e tão importantes quanto contribuir com código." + +#. type: Plain text +#: ../src/en/internals/013-code-review.md +msgid "Reviews are handled via GitHub pull requests. When the request is ready for review, the \"status: code review\" label is added to it." +msgstr "As revisões são feitas por meio de pull requests no GitHub. Quando o pull request está pronto para revisão, recebe o label \"status: code review\"." + +#. type: Plain text +#: ../src/en/internals/013-code-review.md +msgid "[A full list of pull requests that need review](https://github.com/search?q=org%3Ayiisoft+label%3A\"status%3Acode+review\"&state=open&type=Issues) is available at GitHub." +msgstr "[A lista completa de pull requests que precisam de revisão](https://github.com/search?q=org%3Ayiisoft+label%3A\"status%3Acode+review\"&state=open&type=Issues) está disponível no GitHub." + +#. type: Title ## +#: ../src/en/internals/013-code-review.md +#, no-wrap +msgid "Guidelines" +msgstr "Diretrizes" + +#. type: Bullet: '- ' +#: ../src/en/internals/013-code-review.md +msgid "Check out the pull request branch, open the project in the IDE, get a big picture." +msgstr "Faça checkout do branch do pull request, abra o projeto na IDE e tenha uma visão geral." + +#. type: Bullet: '- ' +#: ../src/en/internals/013-code-review.md +msgid "Does the pull request make sense overall?" +msgstr "O pull request faz sentido como um todo?" + +#. type: Bullet: '- ' +#: ../src/en/internals/013-code-review.md +msgid "Run tests and/or application using code from the pull request. Are these OK?" +msgstr "Rode os testes e/ou a aplicação usando o código do pull request. Está tudo certo?" + +#. type: Bullet: '- ' +#: ../src/en/internals/013-code-review.md +msgid "Read all lines of code in the pull request." +msgstr "Leia todas as linhas de código do pull request." + +#. type: Bullet: '- ' +#: ../src/en/internals/013-code-review.md +msgid "Could it be done simpler?" +msgstr "Daria para fazer de forma mais simples?" + +#. type: Bullet: '- ' +#: ../src/en/internals/013-code-review.md +msgid "Are there security issues?" +msgstr "Há problemas de segurança?" + +#. type: Bullet: '- ' +#: ../src/en/internals/013-code-review.md +msgid "Are there performance issues?" +msgstr "Há problemas de desempenho?" + +#. type: Bullet: '- ' +#: ../src/en/internals/013-code-review.md +msgid "When leaving comments, be polite." +msgstr "Ao deixar comentários, seja educado." + +#. type: Bullet: '- ' +#: ../src/en/internals/013-code-review.md +msgid "Avoid code-formatting comments." +msgstr "Evite comentários sobre formatação de código." + +#. type: Title ## +#: ../src/en/internals/013-code-review.md +#, no-wrap +msgid "Mandatory parts" +msgstr "Itens obrigatórios" + +#. type: Bullet: '- ' +#: ../src/en/internals/013-code-review.md +msgid "[ ] Tests that fail without code and pass with code." +msgstr "[ ] Testes que falham sem o código e passam com ele." + +#. type: Bullet: '- ' +#: ../src/en/internals/013-code-review.md +msgid "[ ] Type hints." +msgstr "[ ] Type hints." + +#. type: Bullet: '- ' +#: ../src/en/internals/013-code-review.md +msgid "[ ] `declare(strict_types=1)`." +msgstr "[ ] `declare(strict_types=1)`." + +#. type: Bullet: '- ' +#: ../src/en/internals/013-code-review.md +msgid "[ ] Documentation: phpdoc, yiisoft/docs." +msgstr "[ ] Documentação: phpdoc, yiisoft/docs." + +#. type: Bullet: '- ' +#: ../src/en/internals/013-code-review.md +msgid "[ ] Changelog entry (if package is stable)." +msgstr "[ ] Entrada no changelog (se o pacote for estável)." diff --git a/_translations/po/pt-BR/internals_014-docs.md.po b/_translations/po/pt-BR/internals_014-docs.md.po new file mode 100644 index 00000000..8ee3df95 --- /dev/null +++ b/_translations/po/pt-BR/internals_014-docs.md.po @@ -0,0 +1,478 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-05-05 22:22+0000\n" +"PO-Revision-Date: 2026-05-05 22:22+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/internals/014-docs.md +#, no-wrap +msgid "014 — Documentation" +msgstr "014 — Documentação" + +#. type: Plain text +#: ../src/internals/014-docs.md +msgid "Documentation is one of the most important parts of Yii." +msgstr "A documentação é uma das partes mais importantes do Yii." + +#. type: Title ## +#: ../src/internals/014-docs.md +#, no-wrap +msgid "Package documentation" +msgstr "Documentação de pacotes" + +#. type: Plain text +#: ../src/internals/014-docs.md +msgid "Documentation for a package could either be in `README.md` or `docs/{language}/{type}` where `{language}` is a language code and `{type}` could be \"guide,\" \"cookbook\" or something else. Usually `docs` is there if the package usage or configuration isn't trivial or there's a need for translation." +msgstr "A documentação de um pacote pode ficar no `README.md` ou em `docs/{language}/{type}`, onde `{language}` é um código de idioma e `{type}` pode ser \"guide\", \"cookbook\" ou outra coisa. Normalmente, `docs` existe quando o uso ou a configuração do pacote não é trivial ou quando há necessidade de tradução." + +#. type: Plain text +#: ../src/internals/014-docs.md +msgid "Some indicators that it's time to create `docs`:" +msgstr "Alguns indícios de que é hora de criar `docs`:" + +#. type: Bullet: '1. ' +#: ../src/internals/014-docs.md +msgid "There is a need for translation." +msgstr "Há necessidade de tradução." + +#. type: Bullet: '2. ' +#: ../src/internals/014-docs.md +msgid "Many topics exist. Each of these is big by itself." +msgstr "Existem muitos tópicos, e cada um deles é grande por si só." + +#. type: Plain text +#: ../src/internals/014-docs.md +msgid "If the total length of readme is less than about 200 lines, it's fine to keep documentation in the readme." +msgstr "Se o tamanho total do readme for menor que cerca de 200 linhas, não há problema em manter a documentação no readme." + +#. type: Title ## +#: ../src/internals/014-docs.md +#, no-wrap +msgid "Definitive guide" +msgstr "Guia definitivo" + +#. type: Plain text +#: ../src/internals/014-docs.md +msgid "The definitive guide, [yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/src/guide) aims at covering usage of packages as a whole framework. Unlike package documentation, it isn't focused on a single package but is covering certain use-cases." +msgstr "O guia definitivo, [yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/src/guide) tem como objetivo cobrir o uso dos pacotes como um framework completo. Diferente da documentação dos pacotes, ele não se concentra em um único pacote, e sim em determinados casos de uso." + +#. type: Plain text +#: ../src/internals/014-docs.md +msgid "The guide should follow [Microsoft style guide](https://learn.microsoft.com/en-us/style-guide/welcome/)." +msgstr "O guia deve seguir o [guia de estilo da Microsoft](https://learn.microsoft.com/en-us/style-guide/welcome/)." + +#. type: Title ### +#: ../src/internals/014-docs.md +#, no-wrap +msgid "Translation" +msgstr "Tradução" + +#. type: Plain text +#: ../src/internals/014-docs.md +#, no-wrap +msgid "The definitive guide uses [po4a](https://github.com/mquinson/po4a) in GitHub Action for translations. \n" +msgstr "O guia definitivo usa o [po4a](https://github.com/mquinson/po4a) em uma GitHub Action para as traduções. \n" + +#. type: Plain text +#: ../src/internals/014-docs.md +msgid "Translation algorithm:" +msgstr "Algoritmo de tradução:" + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "Install an application for working with `.po` translation files. For example, [Poedit](https://poedit.net/), [Lokalize](https://apps.kde.org/ru/lokalize/), [Gtranslator](https://wiki.gnome.org/Apps/Gtranslator) or another." +msgstr "Instale uma aplicação para trabalhar com arquivos de tradução `.po`. Por exemplo, [Poedit](https://poedit.net/), [Lokalize](https://apps.kde.org/ru/lokalize/), [Gtranslator](https://wiki.gnome.org/Apps/Gtranslator) ou outra." + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "Find file what you want to translate in `_translations/guide/{lang}`. Note that if the source file is in a subfolder, the subfolder name is appended to the file name and separated by an underscore, for example, for translating `guide/en/concept/aliases.md` file find `_translations/guide/{lang}/concept_aliases.md.po` file." +msgstr "Encontre o arquivo que você quer traduzir em `_translations/guide/{lang}`. Observe que, se o arquivo original estiver em uma subpasta, o nome da subpasta é adicionado ao nome do arquivo, separado por um sublinhado. Por exemplo, para traduzir o arquivo `guide/en/concept/aliases.md`, procure o arquivo `_translations/guide/{lang}/concept_aliases.md.po`." + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "Open the file with the `.po` extension in `Poedit` from the folder with the desired localization, for example `_translations/guide/ru/intro_what-is-yii.md.po`. If there is no localization yet, create an issue." +msgstr "Abra o arquivo com extensão `.po` no `Poedit` a partir da pasta com a localização desejada, por exemplo `_translations/guide/ru/intro_what-is-yii.md.po`. Se ainda não existir a localização, crie uma issue." + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "Translate necessary strings and push the changes" +msgstr "Traduza as strings necessárias e faça push das alterações" + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "Open a pull request to the main repository" +msgstr "Abra um pull request para o repositório principal" + +#. type: Plain text +#: ../src/internals/014-docs.md +#, no-wrap +msgid "" +"> [!CAUTION]\n" +"> Do not change the translation in files in `/guide/{lang}` manually.\n" +msgstr "" +"> [!CAUTION]\n" +"> Não altere manualmente a tradução nos arquivos em `/guide/{lang}`.\n" + +#. type: Plain text +#: ../src/internals/014-docs.md +msgid "If you have changed English and want to update translations:" +msgstr "Se você alterou o texto em inglês e quer atualizar as traduções:" + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "Pull updated branch after successful completion of workflow `Update docs translation` in GitHub Action" +msgstr "Faça pull do branch atualizado depois que o workflow `Update docs translation` da GitHub Action terminar com sucesso" + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "Update translation in `.po` files by `Poedit`" +msgstr "Atualize a tradução nos arquivos `.po` com o `Poedit`" + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "Push changes" +msgstr "Faça push das alterações" + +#. type: Title ## +#: ../src/internals/014-docs.md +#, no-wrap +msgid "Blocks" +msgstr "Blocos" + +#. type: Plain text +#: ../src/internals/014-docs.md +msgid "Blocks are in the [GitHub Alerts format](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts):" +msgstr "Os blocos usam o [formato GitHub Alerts](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts):" + +#. type: Fenced code block +#: ../src/internals/014-docs.md +#, no-wrap +msgid "" +"> [!NOTE]\n" +"> Useful information that users should know, even when skimming content.\n" +"\n" +"> [!TIP]\n" +"> Helpful advice for doing things better or more easily.\n" +"\n" +"> [!IMPORTANT]\n" +"> Key information users need to know to achieve their goal.\n" +"\n" +"> [!WARNING]\n" +"> Urgent info that needs immediate user attention to avoid problems.\n" +"\n" +"> [!CAUTION]\n" +"> Advises about risks or negative outcomes of certain actions.\n" +msgstr "" +"> [!NOTE]\n" +"> Informação útil que os usuários devem saber, mesmo lendo o conteúdo por alto.\n" +"\n" +"> [!TIP]\n" +"> Conselho útil para fazer as coisas melhor ou com mais facilidade.\n" +"\n" +"> [!IMPORTANT]\n" +"> Informação essencial que os usuários precisam saber para alcançar o objetivo.\n" +"\n" +"> [!WARNING]\n" +"> Informação urgente que exige atenção imediata do usuário para evitar problemas.\n" +"\n" +"> [!CAUTION]\n" +"> Alerta sobre riscos ou consequências negativas de certas ações.\n" + +#. type: Plain text +#: ../src/internals/014-docs.md +msgid "When translating documentation, these Block indicators should not be translated. Keeps them intact as they are and only translate the block content. For translating the label for the block, each guide translation should have a `blocktypes.json` file containing the translations. The following shows an example for German:" +msgstr "Ao traduzir a documentação, esses indicadores de bloco não devem ser traduzidos. Mantenha-os intactos e traduza apenas o conteúdo do bloco. Para traduzir o rótulo do bloco, cada tradução do guia deve ter um arquivo `blocktypes.json` com as traduções. Veja a seguir um exemplo para o alemão:" + +#. type: Fenced code block (json) +#: ../src/internals/014-docs.md +#, no-wrap +msgid "" +"{\n" +" \"Note\": \"Hinweis\",\n" +" \"Tip\": \"Tipp\",\n" +" \"Important\": \"Wichtig\",\n" +" \"Warning\": \"Achtung\",\n" +" \"Caution\": \"Vorsicht\"\n" +"}\n" +msgstr "" +"{\n" +" \"Note\": \"Hinweis\",\n" +" \"Tip\": \"Tipp\",\n" +" \"Important\": \"Wichtig\",\n" +" \"Warning\": \"Achtung\",\n" +" \"Caution\": \"Vorsicht\"\n" +"}\n" + +#. type: Title ## +#: ../src/internals/014-docs.md +#, no-wrap +msgid "PHPDoc" +msgstr "PHPDoc" + +#. type: Plain text +#: ../src/internals/014-docs.md +msgid "PHPDoc mustn't be added if it doesn't add anything to what it describes. The following is a bad example:" +msgstr "Não se deve adicionar PHPDoc se ele não acrescentar nada ao que descreve. Este é um mau exemplo:" + +#. type: Fenced code block (php) +#: ../src/internals/014-docs.md +#, no-wrap +msgid "" +"use Psr\\Log\\LoggerInterface;\n" +"\n" +"/**\n" +" * MyService class\n" +" */\n" +"final class MyService extends MyServiceBase\n" +"{\n" +" /**\n" +" * @var LoggerInterface logger \n" +" */\n" +" private LoggerInterface $logger;\n" +"\n" +" /**\n" +" * MyService constructor.\n" +" * @param LoggerInterface $logger\n" +" */\n" +" public function __construct(LoggerInterface $logger)\n" +" {\n" +" $this->logger = $logger;\n" +" }\n" +"\n" +" /**\n" +" * @inheritDoc\n" +" */\n" +" public function doit(): bool\n" +" {\n" +" return parent::doit(); \n" +" }\n" +"}\n" +msgstr "" +"use Psr\\Log\\LoggerInterface;\n" +"\n" +"/**\n" +" * MyService class\n" +" */\n" +"final class MyService extends MyServiceBase\n" +"{\n" +" /**\n" +" * @var LoggerInterface logger \n" +" */\n" +" private LoggerInterface $logger;\n" +"\n" +" /**\n" +" * MyService constructor.\n" +" * @param LoggerInterface $logger\n" +" */\n" +" public function __construct(LoggerInterface $logger)\n" +" {\n" +" $this->logger = $logger;\n" +" }\n" +"\n" +" /**\n" +" * @inheritDoc\n" +" */\n" +" public function doit(): bool\n" +" {\n" +" return parent::doit(); \n" +" }\n" +"}\n" + +#. type: Plain text +#: ../src/internals/014-docs.md +msgid "PHPDoc, if present, should describe the purpose of the element it's added for." +msgstr "O PHPDoc, quando presente, deve descrever o propósito do elemento ao qual foi adicionado." + +#. type: Plain text +#: ../src/internals/014-docs.md +msgid "Skip default values in PHPDoc when PHP already shows them in a parameter default, promoted property default, or property initializer. The declaration is the source of truth, and repeating the value in text can become outdated after code changes." +msgstr "Omita valores padrão no PHPDoc quando o PHP já os mostra no valor padrão de um parâmetro, no valor padrão de uma propriedade promovida ou no inicializador de uma propriedade. A declaração é a fonte da verdade, e repetir o valor no texto pode ficar desatualizado após mudanças no código." + +#. type: Plain text +#: ../src/internals/014-docs.md +msgid "Example of incorrect code:" +msgstr "Exemplo de código incorreto:" + +#. type: Fenced code block (php) +#: ../src/internals/014-docs.md +#, no-wrap +msgid "" +"/**\n" +" * @param bool $skipOnEmpty Whether to skip validation when the value is empty. Defaults to true.\n" +" */\n" +"public function __construct(\n" +" private bool $skipOnEmpty = true,\n" +") {\n" +"}\n" +msgstr "" +"/**\n" +" * @param bool $skipOnEmpty Whether to skip validation when the value is empty. Defaults to true.\n" +" */\n" +"public function __construct(\n" +" private bool $skipOnEmpty = true,\n" +") {\n" +"}\n" + +#. type: Plain text +#: ../src/internals/014-docs.md +msgid "Example of a valid code:" +msgstr "Exemplo de código válido:" + +#. type: Fenced code block (php) +#: ../src/internals/014-docs.md +#, no-wrap +msgid "" +"/**\n" +" * @param bool $skipOnEmpty Whether to skip validation when the value is empty.\n" +" */\n" +"public function __construct(\n" +" private bool $skipOnEmpty = true,\n" +") {\n" +"}\n" +msgstr "" +"/**\n" +" * @param bool $skipOnEmpty Whether to skip validation when the value is empty.\n" +" */\n" +"public function __construct(\n" +" private bool $skipOnEmpty = true,\n" +") {\n" +"}\n" + +#. type: Plain text +#: ../src/internals/014-docs.md +msgid "The `@see` tags must explicitly refer to class methods, properties, and constants. This is necessary for the correct display of links in IDEs, as well as for the correct display of links in API documentation." +msgstr "As tags `@see` devem referenciar explicitamente métodos, propriedades e constantes da classe. Isso é necessário para que os links sejam exibidos corretamente nas IDEs e na documentação da API." + +#. type: Fenced code block (php) +#: ../src/internals/014-docs.md +#, no-wrap +msgid "" +"/**\n" +" * @see SOME_CONST\n" +" * @see $prop\n" +" * @see doSomething()\n" +" */\n" +"final class Example\n" +"{\n" +" public const SOME_CONST = '';\n" +" public int $prop;\n" +" public function doSomething(): void {}\n" +"}\n" +msgstr "" +"/**\n" +" * @see SOME_CONST\n" +" * @see $prop\n" +" * @see doSomething()\n" +" */\n" +"final class Example\n" +"{\n" +" public const SOME_CONST = '';\n" +" public int $prop;\n" +" public function doSomething(): void {}\n" +"}\n" + +#. type: Fenced code block (php) +#: ../src/internals/014-docs.md +#, no-wrap +msgid "" +"/**\n" +" * @see Example::SOME_CONST\n" +" * @see Example::$prop\n" +" * @see Example::doSomething()\n" +" */\n" +"final class Example\n" +"{\n" +" public const SOME_CONST = '';\n" +" public int $prop;\n" +" public function doSomething(): void {}\n" +"}\n" +msgstr "" +"/**\n" +" * @see Example::SOME_CONST\n" +" * @see Example::$prop\n" +" * @see Example::doSomething()\n" +" */\n" +"final class Example\n" +"{\n" +" public const SOME_CONST = '';\n" +" public int $prop;\n" +" public function doSomething(): void {}\n" +"}\n" + +#. type: Title ## +#: ../src/internals/014-docs.md +#, no-wrap +msgid "Readme checklist" +msgstr "Checklist do readme" + +#. type: Plain text +#: ../src/internals/014-docs.md +msgid "Each package readme should be placed into `README.md` and contain the following:" +msgstr "O readme de cada pacote deve ficar em `README.md` e conter o seguinte:" + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "[ ] Logo." +msgstr "[ ] Logo." + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "[ ] Short description of the package. What does it do?" +msgstr "[ ] Descrição curta do pacote. O que ele faz?" + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "[ ] Quality badges (build, code coverage)." +msgstr "[ ] Badges de qualidade (build, cobertura de código)." + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "[ ] Screenshot (if applicable)." +msgstr "[ ] Captura de tela (se aplicável)." + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "[ ] Requirements." +msgstr "[ ] Requisitos." + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "[ ] Installation. Usually `composer require`." +msgstr "[ ] Instalação. Normalmente `composer require`." + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "[ ] Getting started. One or two common usage examples are demonstrated." +msgstr "[ ] Primeiros passos. Um ou dois exemplos de uso comuns." + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "[ ] Configuration." +msgstr "[ ] Configuração." + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "[ ] Contributing. It should contain a link to guidelines." +msgstr "[ ] Contribuindo. Deve conter um link para as diretrizes." + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "[ ] Running tests." +msgstr "[ ] Executando os testes." + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "[ ] License." +msgstr "[ ] Licença." diff --git a/_translations/po/pt-BR/internals_015-phpstorm.md.po b/_translations/po/pt-BR/internals_015-phpstorm.md.po new file mode 100644 index 00000000..49aa1618 --- /dev/null +++ b/_translations/po/pt-BR/internals_015-phpstorm.md.po @@ -0,0 +1,157 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 08:02+0000\n" +"PO-Revision-Date: 2025-12-24 08:02+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/en/internals/015-phpstorm.md +#, no-wrap +msgid "015 — PhpStorm metadata and attributes" +msgstr "015 — Metadados e atributos do PhpStorm" + +#. type: Title ## +#: ../src/en/internals/015-phpstorm.md +#, no-wrap +msgid "PhpStorm metadata" +msgstr "Metadados do PhpStorm" + +#. type: Plain text +#: ../src/en/internals/015-phpstorm.md +msgid "[PhpStorm metadata](https://www.jetbrains.com/help/phpstorm/ide-advanced-metadata.html) helps the IDE to understand code better in cases when regular types and PHPDoc tags don't help." +msgstr "Os [metadados do PhpStorm](https://www.jetbrains.com/help/phpstorm/ide-advanced-metadata.html) ajudam a IDE a entender melhor o código nos casos em que os tipos comuns e as tags PHPDoc não ajudam." + +#. type: Plain text +#: ../src/en/internals/015-phpstorm.md +msgid "We use the following set of coding styles for metadata." +msgstr "Usamos o seguinte conjunto de convenções de estilo para os metadados." + +#. type: Title ### +#: ../src/en/internals/015-phpstorm.md +#, no-wrap +msgid "Metadata location" +msgstr "Localização dos metadados" + +#. type: Bullet: '- ' +#: ../src/en/internals/015-phpstorm.md +msgid "Metadata should be placed in `/.phpstorm.meta.php` directory." +msgstr "Os metadados devem ficar no diretório `/.phpstorm.meta.php`." + +#. type: Bullet: '- ' +#: ../src/en/internals/015-phpstorm.md +msgid "Configuration should be split into files. Each file should be named after a class it configures." +msgstr "A configuração deve ser dividida em arquivos. Cada arquivo deve ter o nome da classe que configura." + +#. type: Plain text +#: ../src/en/internals/015-phpstorm.md +#, no-wrap +msgid "" +"> [!NOTE]\n" +"> There is no support for subdirectories in PhpStorm yet.\n" +msgstr "" +"> [!NOTE]\n" +"> O PhpStorm ainda não suporta subdiretórios.\n" + +#. type: Title ### +#: ../src/en/internals/015-phpstorm.md +#, no-wrap +msgid "Constants " +msgstr "Constantes " + +#. type: Plain text +#: ../src/en/internals/015-phpstorm.md +msgid "All constant dictionaries should be named as `{Class FQN}::{Group name}`. Group name should be short and written in capital letters. Use underscore as a word separator that's `\\Yiisoft\\Http\\Status::STATUSES`. For example:" +msgstr "Todos os dicionários de constantes devem ser nomeados como `{Class FQN}::{Group name}`. O nome do grupo deve ser curto e escrito em letras maiúsculas. Use sublinhado como separador de palavras, por exemplo `\\Yiisoft\\Http\\Status::STATUSES`. Por exemplo:" + +#. type: Fenced code block (php) +#: ../src/en/internals/015-phpstorm.md +#, no-wrap +msgid "" +"expectedReturnValues(\n" +" \\Psr\\Http\\Message\\RequestInterface::getMethod(),\n" +" argumentsSet('\\Yiisoft\\Http\\Method::METHODS'),\n" +");\n" +"\n" +"registerArgumentsSet(\n" +" '\\Yiisoft\\Http\\Method::METHODS',\n" +" \\Yiisoft\\Http\\Method::GET,\n" +" \\Yiisoft\\Http\\Method::POST,\n" +" \\Yiisoft\\Http\\Method::PUT,\n" +" \\Yiisoft\\Http\\Method::DELETE,\n" +" \\Yiisoft\\Http\\Method::PATCH,\n" +" \\Yiisoft\\Http\\Method::HEAD,\n" +" \\Yiisoft\\Http\\Method::OPTIONS,\n" +");\n" +msgstr "" +"expectedReturnValues(\n" +" \\Psr\\Http\\Message\\RequestInterface::getMethod(),\n" +" argumentsSet('\\Yiisoft\\Http\\Method::METHODS'),\n" +");\n" +"\n" +"registerArgumentsSet(\n" +" '\\Yiisoft\\Http\\Method::METHODS',\n" +" \\Yiisoft\\Http\\Method::GET,\n" +" \\Yiisoft\\Http\\Method::POST,\n" +" \\Yiisoft\\Http\\Method::PUT,\n" +" \\Yiisoft\\Http\\Method::DELETE,\n" +" \\Yiisoft\\Http\\Method::PATCH,\n" +" \\Yiisoft\\Http\\Method::HEAD,\n" +" \\Yiisoft\\Http\\Method::OPTIONS,\n" +");\n" + +#. type: Title ## +#: ../src/en/internals/015-phpstorm.md +#, no-wrap +msgid "PhpStorm attributes" +msgstr "Atributos do PhpStorm" + +#. type: Plain text +#: ../src/en/internals/015-phpstorm.md +msgid "[PhpStorm attributes](https://github.com/JetBrains/phpstorm-attributes) CAN be used in code, but package `jetbrains/phpstorm-attributes` MUST be added as a dev dependency:" +msgstr "Os [atributos do PhpStorm](https://github.com/JetBrains/phpstorm-attributes) PODEM ser usados no código, mas o pacote `jetbrains/phpstorm-attributes` DEVE ser adicionado como dependência de desenvolvimento:" + +#. type: Fenced code block (shell) +#: ../src/en/internals/015-phpstorm.md +#, no-wrap +msgid "composer require --dev jetbrains/phpstorm-attributes\n" +msgstr "composer require --dev jetbrains/phpstorm-attributes\n" + +#. type: Title ### +#: ../src/en/internals/015-phpstorm.md +#, no-wrap +msgid "Using with ComposerRequireChecker" +msgstr "Usando com o ComposerRequireChecker" + +#. type: Plain text +#: ../src/en/internals/015-phpstorm.md +msgid "When [ComposerRequireChecker](https://github.com/maglnet/ComposerRequireChecker) is also used within the same package, add involved attributes' class names to whitelist in config. For example:" +msgstr "Quando o [ComposerRequireChecker](https://github.com/maglnet/ComposerRequireChecker) também é usado no mesmo pacote, adicione os nomes das classes dos atributos envolvidos à whitelist na configuração. Por exemplo:" + +#. type: Fenced code block (json) +#: ../src/en/internals/015-phpstorm.md +#, no-wrap +msgid "" +"{\n" +" \"symbol-whitelist\": [\n" +" \"JetBrains\\\\PhpStorm\\\\ExpectedValues\",\n" +" \"JetBrains\\\\PhpStorm\\\\Pure\"\n" +" ]\n" +"}\n" +msgstr "" +"{\n" +" \"symbol-whitelist\": [\n" +" \"JetBrains\\\\PhpStorm\\\\ExpectedValues\",\n" +" \"JetBrains\\\\PhpStorm\\\\Pure\"\n" +" ]\n" +"}\n" diff --git a/_translations/po/pt-BR/internals_016-security-workflow.md.po b/_translations/po/pt-BR/internals_016-security-workflow.md.po new file mode 100644 index 00000000..0f5ae7c4 --- /dev/null +++ b/_translations/po/pt-BR/internals_016-security-workflow.md.po @@ -0,0 +1,176 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-05-09 18:47+0000\n" +"PO-Revision-Date: 2026-05-09 18:47+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/internals/016-security-workflow.md +#, no-wrap +msgid "016 — Security workflow" +msgstr "016 — Fluxo de segurança" + +#. type: Plain text +#: ../src/internals/016-security-workflow.md +msgid "Security issues are typically sent via [a security form](https://www.yiiframework.com/security)." +msgstr "Problemas de segurança normalmente são enviados pelo [formulário de segurança](https://www.yiiframework.com/security)." + +#. type: Plain text +#: ../src/internals/016-security-workflow.md +#, no-wrap +msgid "" +"If an issue is reported directly to a public page such as a repository issue or a forum topic, get the message\n" +"and delete the issue. Say thanks to the reporter and point to the security form for next time. \n" +msgstr "" +"Se um problema for relatado diretamente em uma página pública, como uma issue do repositório ou um tópico do fórum, copie a mensagem\n" +"e apague a issue. Agradeça a quem relatou e indique o formulário de segurança para a próxima vez. \n" + +#. type: Fenced code block (mermaid) +#: ../src/internals/016-security-workflow.md +#, no-wrap +msgid "" +"flowchart TD\n" +" form[Security form report] --> verify[Verify issue]\n" +" public[Public report] --> remove[Save details and delete public issue]\n" +" remove --> redirect[Point reporter to the security form]\n" +" redirect --> verify\n" +" verify -->|needs details| requestInfo[Request more information]\n" +" requestInfo --> verify\n" +" verify -->|valid| advisory[Create draft security advisory]\n" +" advisory --> severity[Set CVSS severity]\n" +" severity --> credit[Ask about reporter credit]\n" +" credit --> cve[Request CVE number]\n" +" cve --> patch[Prepare patch pull request]\n" +" patch --> wait[Wait for CVE allocation]\n" +" wait --> release[Release]\n" +" release --> publish[Publish advisory and submit FriendsOfPHP entry]\n" +msgstr "" +"flowchart TD\n" +" form[Relato pelo formulário de segurança] --> verify[Verificar o problema]\n" +" public[Relato público] --> remove[Salvar os detalhes e apagar a issue pública]\n" +" remove --> redirect[Indicar o formulário de segurança a quem relatou]\n" +" redirect --> verify\n" +" verify -->|precisa de detalhes| requestInfo[Pedir mais informações]\n" +" requestInfo --> verify\n" +" verify -->|válido| advisory[Criar rascunho de security advisory]\n" +" advisory --> severity[Definir a severidade CVSS]\n" +" severity --> credit[Perguntar sobre o crédito a quem relatou]\n" +" credit --> cve[Solicitar número CVE]\n" +" cve --> patch[Preparar pull request com o patch]\n" +" patch --> wait[Aguardar a atribuição do CVE]\n" +" wait --> release[Release]\n" +" release --> publish[Publicar o advisory e enviar entrada ao FriendsOfPHP]\n" + +#. type: Title ## +#: ../src/internals/016-security-workflow.md +#, no-wrap +msgid "Verify" +msgstr "Verificar" + +#. type: Plain text +#: ../src/internals/016-security-workflow.md +msgid "Verify that the issue is valid. Request more information if needed." +msgstr "Verifique se o problema é válido. Peça mais informações, se necessário." + +#. type: Title ## +#: ../src/internals/016-security-workflow.md +#, no-wrap +msgid "Add security advisory" +msgstr "Adicionar security advisory" + +#. type: Plain text +#: ../src/internals/016-security-workflow.md +msgid "Create a draft GitHub security advisory." +msgstr "Crie um rascunho de security advisory no GitHub." + +#. type: Title ### +#: ../src/internals/016-security-workflow.md +#, no-wrap +msgid "Find out severity" +msgstr "Descobrir a severidade" + +#. type: Bullet: '1. ' +#: ../src/internals/016-security-workflow.md +msgid "Get CVSS score using [NVD calculator](https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator)." +msgstr "Obtenha a pontuação CVSS usando a [calculadora do NVD](https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator)." + +#. type: Bullet: '2. ' +#: ../src/internals/016-security-workflow.md +msgid "Choose severity based on the [rating scale](https://www.first.org/cvss/specification-document#Qualitative-Severity-Rating-Scale)." +msgstr "Escolha a severidade com base na [escala de classificação](https://www.first.org/cvss/specification-document#Qualitative-Severity-Rating-Scale)." + +#. type: Title ### +#: ../src/internals/016-security-workflow.md +#, no-wrap +msgid "Give credit to the reporter" +msgstr "Dar crédito a quem relatou" + +#. type: Plain text +#: ../src/internals/016-security-workflow.md +msgid "Ask the reporter if he wants a credit for finding the issue. If so, point to his GitHub account." +msgstr "Pergunte a quem relatou se deseja receber crédito por ter encontrado o problema. Se sim, indique a conta dessa pessoa no GitHub." + +#. type: Title ## +#: ../src/internals/016-security-workflow.md +#, no-wrap +msgid "Request a CVE number" +msgstr "Solicitar um número CVE" + +#. type: Plain text +#: ../src/internals/016-security-workflow.md +msgid "When you're ready, request a CVE." +msgstr "Quando estiver pronto, solicite um CVE." + +#. type: Title ## +#: ../src/internals/016-security-workflow.md +#, no-wrap +msgid "Prepare a patch" +msgstr "Preparar um patch" + +#. type: Plain text +#: ../src/internals/016-security-workflow.md +msgid "Prepare a pull request fixing the issue. GitHub allows doing it in a private fork." +msgstr "Prepare um pull request que corrija o problema. O GitHub permite fazer isso em um fork privado." + +#. type: Title ## +#: ../src/internals/016-security-workflow.md +#, no-wrap +msgid "Wait till the CVE number is allocated " +msgstr "Aguardar a atribuição do número CVE " + +#. type: Plain text +#: ../src/internals/016-security-workflow.md +msgid "It usually takes several days." +msgstr "Normalmente leva alguns dias." + +#. type: Title ## +#: ../src/internals/016-security-workflow.md +#, no-wrap +msgid "Release" +msgstr "Release" + +#. type: Bullet: '- ' +#: ../src/internals/016-security-workflow.md +msgid "Merge the patch pull request right before tagging the next package release." +msgstr "Faça o merge do pull request com o patch logo antes de criar a tag do próximo release do pacote." + +#. type: Bullet: '- ' +#: ../src/internals/016-security-workflow.md +msgid "Publish security advisory." +msgstr "Publique o security advisory." + +#. type: Bullet: '- ' +#: ../src/internals/016-security-workflow.md +msgid "Add CVE to [FriendsOfPHP/security-advisories](https://github.com/FriendsOfPHP/security-advisories). See [#488](https://github.com/FriendsOfPHP/security-advisories/pull/488) as an example." +msgstr "Adicione o CVE em [FriendsOfPHP/security-advisories](https://github.com/FriendsOfPHP/security-advisories). Veja [#488](https://github.com/FriendsOfPHP/security-advisories/pull/488) como exemplo." diff --git a/_translations/po/pt-BR/internals_017-tags.md.po b/_translations/po/pt-BR/internals_017-tags.md.po new file mode 100644 index 00000000..d0c5b186 --- /dev/null +++ b/_translations/po/pt-BR/internals_017-tags.md.po @@ -0,0 +1,123 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 08:02+0000\n" +"PO-Revision-Date: 2025-12-24 08:02+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/en/guide/concept/immutability.md ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +#, no-wrap +msgid "Immutability" +msgstr "Imutabilidade" + +#. type: Title ### +#: ../src/en/internals/010-code-style.md ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +#, no-wrap +msgid "Names" +msgstr "Nomes" + +#. type: Title ## +#: ../src/en/internals/010-code-style.md ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +#, no-wrap +msgid "Methods" +msgstr "Métodos" + +#. type: Title # +#: ../src/en/internals/017-tags.md +#, no-wrap +msgid "017 - Tags" +msgstr "017 - Tags" + +#. type: Plain text +#: ../src/en/internals/017-tags.md +msgid "Unlike regular classes, tags are used in view templates, so syntax is important. It should be both easy to write, easy to read and not too verbose because similar constructs are meant to be used over and over again." +msgstr "Diferente das classes comuns, as tags são usadas em templates de view, então a sintaxe é importante. Ela deve ser fácil de escrever, fácil de ler e não muito verbosa, porque construções parecidas são usadas repetidas vezes." + +#. type: Title ## +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +#, no-wrap +msgid "Class names" +msgstr "Nomes de classes" + +#. type: Bullet: '- ' +#: ../src/en/internals/017-tags.md +msgid "Tags aren't postfixed or prefixed unless it's an abstract base class." +msgstr "As tags não têm prefixo nem sufixo, a menos que sejam uma classe base abstrata." + +#. type: Bullet: '- ' +#: ../src/en/internals/017-tags.md +msgid "If the tag represents a specification, use a name used in the specification." +msgstr "Se a tag representa uma especificação, use o nome usado na especificação." + +#. type: Title ## +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +#, no-wrap +msgid "Inheritance" +msgstr "Herança" + +#. type: Plain text +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +msgid "Inheritance is allowed with some restrictions:" +msgstr "A herança é permitida com algumas restrições:" + +#. type: Bullet: '- ' +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +msgid "If a class isn't abstract, it should be final." +msgstr "Se uma classe não é abstrata, ela deve ser final." + +#. type: Bullet: '- ' +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +msgid "Hierarchy should be kept as linear as possible." +msgstr "A hierarquia deve ser mantida o mais linear possível." + +#. type: Plain text +#: ../src/en/internals/017-tags.md +msgid "Tags should:" +msgstr "As tags devem:" + +#. type: Bullet: '- ' +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +msgid "Have no state." +msgstr "Não ter estado." + +#. type: Bullet: '- ' +#: ../src/en/internals/017-tags.md +msgid "Be immutable. Every method that modifies a setting returns a clone with the setting changed." +msgstr "Ser imutáveis. Todo método que modifica uma configuração retorna um clone com a configuração alterada." + +#. type: Bullet: '- ' +#: ../src/en/internals/017-tags.md +msgid "Be free of side effects. Many calls of the same method with the same argument should give the same result." +msgstr "Não ter efeitos colaterais. Várias chamadas do mesmo método com o mesmo argumento devem dar o mesmo resultado." + +#. type: Bullet: '- ' +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +msgid "Unlike other classes, methods that return a clone of the object with some properties modified aren't prefixed." +msgstr "Diferente de outras classes, os métodos que retornam um clone do objeto com algumas propriedades modificadas não têm prefixo." + +#. type: Bullet: '- ' +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +msgid "Keep method names as short as possible but don't hurt readability." +msgstr "Mantenha os nomes dos métodos o mais curtos possível, sem prejudicar a legibilidade." + +#. type: Title ### +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +#, no-wrap +msgid "Boolean flags" +msgstr "Flags booleanas" + +#. type: Plain text +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +msgid "The method that corresponds to the boolean attribute should be named after the attribute and accept a boolean flag argument." +msgstr "O método que corresponde a um atributo booleano deve ter o nome do atributo e aceitar um argumento booleano como flag." diff --git a/_translations/po/pt-BR/internals_018-widgets.md.po b/_translations/po/pt-BR/internals_018-widgets.md.po new file mode 100644 index 00000000..a7c1ab59 --- /dev/null +++ b/_translations/po/pt-BR/internals_018-widgets.md.po @@ -0,0 +1,113 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 08:02+0000\n" +"PO-Revision-Date: 2025-12-24 08:02+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/en/guide/concept/immutability.md ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +#, no-wrap +msgid "Immutability" +msgstr "Imutabilidade" + +#. type: Title ### +#: ../src/en/internals/010-code-style.md ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +#, no-wrap +msgid "Names" +msgstr "Nomes" + +#. type: Title ## +#: ../src/en/internals/010-code-style.md ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +#, no-wrap +msgid "Methods" +msgstr "Métodos" + +#. type: Title ## +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +#, no-wrap +msgid "Class names" +msgstr "Nomes de classes" + +#. type: Title ## +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +#, no-wrap +msgid "Inheritance" +msgstr "Herança" + +#. type: Plain text +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +msgid "Inheritance is allowed with some restrictions:" +msgstr "A herança é permitida com algumas restrições:" + +#. type: Bullet: '- ' +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +msgid "If a class isn't abstract, it should be final." +msgstr "Se uma classe não é abstrata, ela deve ser final." + +#. type: Bullet: '- ' +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +msgid "Hierarchy should be kept as linear as possible." +msgstr "A hierarquia deve ser mantida o mais linear possível." + +#. type: Bullet: '- ' +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +msgid "Have no state." +msgstr "Não ter estado." + +#. type: Bullet: '- ' +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +msgid "Unlike other classes, methods that return a clone of the object with some properties modified aren't prefixed." +msgstr "Diferente de outras classes, os métodos que retornam um clone do objeto com algumas propriedades modificadas não têm prefixo." + +#. type: Bullet: '- ' +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +msgid "Keep method names as short as possible but don't hurt readability." +msgstr "Mantenha os nomes dos métodos o mais curtos possível, sem prejudicar a legibilidade." + +#. type: Title ### +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +#, no-wrap +msgid "Boolean flags" +msgstr "Flags booleanas" + +#. type: Plain text +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +msgid "The method that corresponds to the boolean attribute should be named after the attribute and accept a boolean flag argument." +msgstr "O método que corresponde a um atributo booleano deve ter o nome do atributo e aceitar um argumento booleano como flag." + +#. type: Title # +#: ../src/en/internals/018-widgets.md +#, no-wrap +msgid "018 - Widgets" +msgstr "018 - Widgets" + +#. type: Plain text +#: ../src/en/internals/018-widgets.md +msgid "Unlike regular classes, widgets are used in view templates, so syntax is important. It should be both easy to write, easy to read and not too verbose because similar constructs are meant to be used over and over again." +msgstr "Diferente das classes comuns, os widgets são usados em templates de view, então a sintaxe é importante. Ela deve ser fácil de escrever, fácil de ler e não muito verbosa, porque construções parecidas são usadas repetidas vezes." + +#. type: Plain text +#: ../src/en/internals/018-widgets.md +msgid "Widgets aren't postfixed or prefixed." +msgstr "Os widgets não têm prefixo nem sufixo." + +#. type: Plain text +#: ../src/en/internals/018-widgets.md +msgid "Widgets should:" +msgstr "Os widgets devem:" + +#. type: Bullet: '- ' +#: ../src/en/internals/018-widgets.md +msgid "Be immutable." +msgstr "Ser imutáveis." diff --git a/_translations/po/pt-BR/internals_019-view-code-style.md.po b/_translations/po/pt-BR/internals_019-view-code-style.md.po new file mode 100644 index 00000000..5ff805f2 --- /dev/null +++ b/_translations/po/pt-BR/internals_019-view-code-style.md.po @@ -0,0 +1,113 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 08:02+0000\n" +"PO-Revision-Date: 2025-12-24 08:02+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/en/internals/019-view-code-style.md +#, no-wrap +msgid "019 — View code style" +msgstr "019 — Estilo de código das views" + +#. type: Plain text +#: ../src/en/internals/019-view-code-style.md +msgid "The PHP code in the view files shouldn't be complicated. The code must contain the logic responsible for formatting the data, but not the logic for requesting this data." +msgstr "O código PHP nos arquivos de view não deve ser complicado. O código deve conter a lógica responsável por formatar os dados, mas não a lógica para buscar esses dados." + +#. type: Title ## +#: ../src/en/internals/019-view-code-style.md +#, no-wrap +msgid "Heading" +msgstr "Cabeçalho" + +#. type: Plain text +#: ../src/en/internals/019-view-code-style.md +msgid "View file heading is used to place phpdoc describing variables available and to import classes:" +msgstr "O cabeçalho do arquivo de view é usado para colocar o phpdoc que descreve as variáveis disponíveis e para importar classes:" + +#. type: Fenced code block (php) +#: ../src/en/internals/019-view-code-style.md +#, no-wrap +msgid "" +" \n" +"

getTitle()) ?>

\n" +"

getDescription()) ?>

\n" +"\n" +msgstr "" +" \n" +"

getTitle()) ?>

\n" +"

getDescription()) ?>

\n" +"\n" + +#. type: Title ## +#: ../src/en/internals/019-view-code-style.md +#, no-wrap +msgid "Short echo" +msgstr "Short echo" + +#. type: Plain text +#: ../src/en/internals/019-view-code-style.md +msgid "Short echo is preferred:" +msgstr "Prefira o short echo:" + +#. type: Fenced code block (php) +#: ../src/en/internals/019-view-code-style.md +#, no-wrap +msgid "\n" +msgstr "\n" + +#. type: Title ## +#: ../src/en/internals/019-view-code-style.md +#, no-wrap +msgid "Class methods" +msgstr "Métodos de classe" + +#. type: Plain text +#: ../src/en/internals/019-view-code-style.md +msgid "All class methods used in view files must be public regardless if the view is rendered by the class itself." +msgstr "Todos os métodos de classe usados em arquivos de view devem ser públicos, mesmo que a view seja renderizada pela própria classe." diff --git a/_translations/po/pt-BR/internals_020-package-release.md.po b/_translations/po/pt-BR/internals_020-package-release.md.po new file mode 100644 index 00000000..07c8cb51 --- /dev/null +++ b/_translations/po/pt-BR/internals_020-package-release.md.po @@ -0,0 +1,161 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-05-29 09:48+0000\n" +"PO-Revision-Date: 2026-05-29 09:48+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/internals/020-package-release.md +#, no-wrap +msgid "020 — Package release" +msgstr "020 — Release de pacotes" + +#. type: Title ## +#: ../src/internals/020-package-release.md +#, no-wrap +msgid "Criteria" +msgstr "Critérios" + +#. type: Bullet: '- ' +#: ../src/internals/020-package-release.md +msgid "No critical issues." +msgstr "Nenhuma issue crítica." + +#. type: Bullet: '- ' +#: ../src/internals/020-package-release.md +msgid "Public API changes aren't likely. Some time passed w/o issues reported that may require API changes." +msgstr "Mudanças na API pública são improváveis. Já passou algum tempo sem issues relatadas que possam exigir mudanças na API." + +#. type: Bullet: '- ' +#: ../src/internals/020-package-release.md +msgid "All dependencies are stable." +msgstr "Todas as dependências são estáveis." + +#. type: Bullet: '- ' +#: ../src/internals/020-package-release.md +msgid "Close to 100% test coverage with, ideally, a 100% MSI score." +msgstr "Cobertura de testes próxima de 100% e, idealmente, score MSI de 100%." + +#. type: Bullet: '- ' +#: ../src/internals/020-package-release.md +msgid "README is alright." +msgstr "O README está em ordem." + +#. type: Bullet: '- ' +#: ../src/internals/020-package-release.md +msgid "Everything is type-hinted unless special cases." +msgstr "Tudo tem type hints, exceto em casos especiais." + +#. type: Bullet: '- ' +#: ../src/internals/020-package-release.md +msgid "Psalm analysis passes on at least level 2." +msgstr "A análise do Psalm passa pelo menos no nível 2." + +#. type: Bullet: '- ' +#: ../src/internals/020-package-release.md +msgid "phpdoc is alright." +msgstr "O phpdoc está em ordem." + +#. type: Bullet: '- ' +#: ../src/internals/020-package-release.md +msgid "Public API is alright." +msgstr "A API pública está em ordem." + +#. type: Title ## +#: ../src/internals/020-package-release.md +#, no-wrap +msgid "Release branch policy" +msgstr "Política de branches de release" + +#. type: Plain text +#: ../src/internals/020-package-release.md +msgid "Use `master` for all regular releases." +msgstr "Use `master` para todos os releases regulares." + +#. type: Plain text +#: ../src/internals/020-package-release.md +msgid "Create a separate branch only when releasing a new version for a previous major version. In this case, create the branch from the latest tag in that previous major version line and apply only the changes needed for the release." +msgstr "Crie um branch separado apenas ao lançar uma nova versão de uma versão major anterior. Nesse caso, crie o branch a partir da tag mais recente dessa linha de versão major anterior e aplique apenas as mudanças necessárias para o release." + +#. type: Title ## +#: ../src/internals/020-package-release.md +#, no-wrap +msgid "Release instruction" +msgstr "Instruções de release" + +#. type: Plain text +#: ../src/internals/020-package-release.md +msgid "Release a package via [Yii Development Tool](005-development-tool.md)." +msgstr "Faça o release de um pacote com a [Ferramenta de desenvolvimento do Yii](005-development-tool.md)." + +#. type: Plain text +#: ../src/internals/020-package-release.md +#, no-wrap +msgid "" +"1. Check that you can sign commits locally (see \n" +"[Signing commits](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits)).\n" +msgstr "" +"1. Verifique se você consegue assinar commits localmente (veja \n" +"[Assinando commits](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits)).\n" + +#. type: Bullet: '2. ' +#: ../src/internals/020-package-release.md +msgid "For regular releases, pull last changes from the `master` branch:" +msgstr "Para releases regulares, faça pull das últimas mudanças do branch `master`:" + +#. type: Fenced code block (shell) +#: ../src/internals/020-package-release.md +#, no-wrap +msgid "" +"./yii-dev git/checkout master package-name\n" +"./yii-dev git/pull package-name\n" +msgstr "" +"./yii-dev git/checkout master package-name\n" +"./yii-dev git/pull package-name\n" + +#. type: Plain text +#: ../src/internals/020-package-release.md +msgid "For previous major version releases, use the branch created according to the release branch policy instead of `master`." +msgstr "Para releases de versões major anteriores, use o branch criado de acordo com a política de branches de release, em vez de `master`." + +#. type: Bullet: '3. ' +#: ../src/internals/020-package-release.md +msgid "Check the package for compliance with the criteria above." +msgstr "Verifique se o pacote atende aos critérios acima." + +#. type: Bullet: '4. ' +#: ../src/internals/020-package-release.md +msgid "Run `release/make` command:" +msgstr "Execute o comando `release/make`:" + +#. type: Fenced code block (shell) +#: ../src/internals/020-package-release.md +#, no-wrap +msgid "./yii-dev release/make package-name\n" +msgstr "./yii-dev release/make package-name\n" + +#. type: Bullet: '5. ' +#: ../src/internals/020-package-release.md +msgid "Select the version type (major, minor or patch)." +msgstr "Selecione o tipo de versão (major, minor ou patch)." + +#. type: Bullet: '6. ' +#: ../src/internals/020-package-release.md +msgid "On the question \"Push commits and tags, and release on GitHub?\" check a diff. If the diff is alright, answer \"yes.\"" +msgstr "Na pergunta \"Push commits and tags, and release on GitHub?\", confira o diff. Se o diff estiver correto, responda \"yes\"." + +#. type: Bullet: '7. ' +#: ../src/internals/020-package-release.md +msgid "For major and minor releases, add a record with release notes on [Yii Framework News](https://www.yiiframework.com/news)." +msgstr "Para releases major e minor, adicione um registro com as notas de release em [Yii Framework News](https://www.yiiframework.com/news)." diff --git a/_translations/po/pt-BR/internals_021-changelog-upgrade.md.po b/_translations/po/pt-BR/internals_021-changelog-upgrade.md.po new file mode 100644 index 00000000..bf33f29e --- /dev/null +++ b/_translations/po/pt-BR/internals_021-changelog-upgrade.md.po @@ -0,0 +1,159 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-01-08 08:54+0000\n" +"PO-Revision-Date: 2026-01-08 08:54+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/internals/021-changelog-upgrade.md +#, no-wrap +msgid "021 — Changelog and upgrade" +msgstr "021 — Changelog e upgrade" + +#. type: Plain text +#: ../src/internals/021-changelog-upgrade.md +msgid "For all released packages, we've a detailed changelog and upgrade guide." +msgstr "Para todos os pacotes lançados, mantemos um changelog detalhado e um guia de upgrade." + +#. type: Title ## +#: ../src/internals/021-changelog-upgrade.md +#, no-wrap +msgid "Changelog" +msgstr "Changelog" + +#. type: Plain text +#: ../src/internals/021-changelog-upgrade.md +msgid "Changelog is written for each version released. The file name is `CHANGELOG.md`. The format is the following:" +msgstr "O changelog é escrito para cada versão lançada. O nome do arquivo é `CHANGELOG.md`. O formato é o seguinte:" + +#. type: Fenced code block (markdown) +#: ../src/internals/021-changelog-upgrade.md +#, no-wrap +msgid "" +"# My package Change Log\n" +"\n" +"## 1.0.2 under development\n" +"\n" +"- no changes in this release.\n" +"\n" +"## 1.0.1 March 23, 2021\n" +"\n" +"- Bug #42: Short description of the change (@author1, @author2)\n" +"\n" +"## 1.0.0 February 02, 2021\n" +"\n" +"- Initial release.\n" +msgstr "" +"# My package Change Log\n" +"\n" +"## 1.0.2 under development\n" +"\n" +"- no changes in this release.\n" +"\n" +"## 1.0.1 March 23, 2021\n" +"\n" +"- Bug #42: Short description of the change (@author1, @author2)\n" +"\n" +"## 1.0.0 February 02, 2021\n" +"\n" +"- Initial release.\n" + +#. type: Plain text +#: ../src/internals/021-changelog-upgrade.md +msgid "There \"My package\" is the name of the package, `1.0.1` is the version released followed by release date. For each version, there are a number of lines listing the changes. \"Bug\" refers to a change type. The following types are used:" +msgstr "Ali, \"My package\" é o nome do pacote, `1.0.1` é a versão lançada, seguida da data de release. Para cada versão, há algumas linhas listando as mudanças. \"Bug\" indica o tipo da mudança. São usados os seguintes tipos:" + +#. type: Bullet: '- ' +#: ../src/internals/021-changelog-upgrade.md +msgid "New — New features." +msgstr "New — Novas funcionalidades." + +#. type: Bullet: '- ' +#: ../src/internals/021-changelog-upgrade.md +msgid "Chg — General changes." +msgstr "Chg — Mudanças gerais." + +#. type: Bullet: '- ' +#: ../src/internals/021-changelog-upgrade.md +msgid "Enh — Existing feature enhancements." +msgstr "Enh — Melhorias em funcionalidades existentes." + +#. type: Bullet: '- ' +#: ../src/internals/021-changelog-upgrade.md +msgid "Bug — Bug fixes." +msgstr "Bug — Correções de bugs." + +#. type: Plain text +#: ../src/internals/021-changelog-upgrade.md +msgid "In the changelog file lines should be ordered as New, Chg, Enh, Bug." +msgstr "No arquivo de changelog, as linhas devem ser ordenadas como New, Chg, Enh, Bug." + +#. type: Plain text +#: ../src/internals/021-changelog-upgrade.md +msgid "\"#42\" above is the number of issue or pull requests corresponding to the change. \"author1\" is the GitHub nickname of the code author. \"author2\" is an additional author. An author's nickname MUST be prefixed with `@`." +msgstr "\"#42\" acima é o número da issue ou do pull request correspondente à mudança. \"author1\" é o nickname no GitHub do autor do código. \"author2\" é um autor adicional. O nickname de um autor DEVE ter o prefixo `@`." + +#. type: Title ## +#: ../src/internals/021-changelog-upgrade.md +#, no-wrap +msgid "Upgrade" +msgstr "Upgrade" + +#. type: Plain text +#: ../src/internals/021-changelog-upgrade.md +msgid "Upgrade guide is created when there is a new major version that isn't compatible with the previous one. It describes steps necessary to upgrade application code." +msgstr "O guia de upgrade é criado quando há uma nova versão major que não é compatível com a anterior. Ele descreve os passos necessários para fazer o upgrade do código da aplicação." + +#. type: Plain text +#: ../src/internals/021-changelog-upgrade.md +msgid "The file name is `UPGRADE.md`. The format is the following:" +msgstr "O nome do arquivo é `UPGRADE.md`. O formato é o seguinte:" + +#. type: Fenced code block (markdown) +#: ../src/internals/021-changelog-upgrade.md +#, no-wrap +msgid "" +"# Upgrading Instructions for my package\n" +"\n" +"This file contains the upgrade notes. These notes highlight changes that could break your\n" +"application when you upgrade the package from one version to another.\n" +"\n" +"> **Important!** The following upgrading instructions are cumulative. That is, if you want\n" +"> to upgrade from version A to version C and there is version B between A and C, you need\n" +"> to follow the instructions for both A and B.\n" +"\n" +"## Upgrade from 2.x\n" +"\n" +"- Public method `test()` was removed. Use `perform()` instead.\n" +"\n" +"## Upgrade from 1.x\n" +"\n" +"- Clean up the cache after upgrading. Old cache is not compatible with new code.\n" +msgstr "" +"# Upgrading Instructions for my package\n" +"\n" +"This file contains the upgrade notes. These notes highlight changes that could break your\n" +"application when you upgrade the package from one version to another.\n" +"\n" +"> **Important!** The following upgrading instructions are cumulative. That is, if you want\n" +"> to upgrade from version A to version C and there is version B between A and C, you need\n" +"> to follow the instructions for both A and B.\n" +"\n" +"## Upgrade from 2.x\n" +"\n" +"- Public method `test()` was removed. Use `perform()` instead.\n" +"\n" +"## Upgrade from 1.x\n" +"\n" +"- Clean up the cache after upgrading. Old cache is not compatible with new code.\n" diff --git a/_translations/po/pt-BR/internals_022-config-groups.md.po b/_translations/po/pt-BR/internals_022-config-groups.md.po new file mode 100644 index 00000000..30ce8ac8 --- /dev/null +++ b/_translations/po/pt-BR/internals_022-config-groups.md.po @@ -0,0 +1,242 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2025-12-24 08:02+0000\n" +"PO-Revision-Date: 2025-12-24 08:02+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title ## +#: ../src/en/guide/concept/configuration.md ../src/en/guide/concept/events.md ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Events" +msgstr "Eventos" + +#. type: Title ## +#: ../src/en/guide/concept/configuration.md ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Parameters" +msgstr "Parâmetros" + +#. type: Title ## +#: ../src/en/internals/003-roadmap.md ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Others" +msgstr "Outros" + +#. type: Title # +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "022 — Config groups" +msgstr "022 — Grupos de configuração" + +#. type: Plain text +#: ../src/en/internals/022-config-groups.md +msgid "This document defines naming convention for the framework groups used with [yiisoft/config](https://github.com/yiisoft/config). Note that this isn't a naming convention for config files. These could be anything and are mapped to group names via `composer.json`." +msgstr "Este documento define a convenção de nomes para os grupos do framework usados com o [yiisoft/config](https://github.com/yiisoft/config). Observe que esta não é uma convenção de nomes para arquivos de configuração. Eles podem ter qualquer nome e são mapeados para os nomes de grupo via `composer.json`." + +#. type: Title ## +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Config group name postfixes" +msgstr "Sufixos dos nomes de grupos de configuração" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "\"web\" postfix applies to web only that's classic server HTML generation, REST, RPC, etc." +msgstr "O sufixo \"web\" se aplica apenas à web, ou seja, geração clássica de HTML no servidor, REST, RPC etc." + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "\"console\" postfix applies to console" +msgstr "O sufixo \"console\" se aplica ao console" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "If there's no postfix, it's \"common\" and applies to both web and console" +msgstr "Se não houver sufixo, o grupo é \"common\" e se aplica tanto à web quanto ao console" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "\"web\" and \"console\" may override what's defined in \"common\"" +msgstr "\"web\" e \"console\" podem sobrescrever o que está definido em \"common\"" + +#. type: Plain text +#: ../src/en/internals/022-config-groups.md +msgid "Application config parameters that are used in all configs." +msgstr "Parâmetros de configuração da aplicação usados em todas as configurações." + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`params` — common parameters" +msgstr "`params` — parâmetros comuns" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`params-web` — web application parameters" +msgstr "`params-web` — parâmetros da aplicação web" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`params-console` — console application parameters" +msgstr "`params-console` — parâmetros da aplicação de console" + +#. type: Title ## +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Container" +msgstr "Container" + +#. type: Plain text +#: ../src/en/internals/022-config-groups.md +msgid "Configuration for [yiisoft/di](https://github.com/yiisoft/di)." +msgstr "Configuração do [yiisoft/di](https://github.com/yiisoft/di)." + +#. type: Title ### +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Definitions" +msgstr "Definições" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di` — common container definitions" +msgstr "`di` — definições comuns do container" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-web` — web container definitions" +msgstr "`di-web` — definições do container para web" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-console` — console container definitions" +msgstr "`di-console` — definições do container para console" + +#. type: Title ### +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Providers" +msgstr "Providers" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-providers` — common container providers" +msgstr "`di-providers` — providers comuns do container" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-providers-web` — web container providers" +msgstr "`di-providers-web` — providers do container para web" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-providers-console` — console container providers" +msgstr "`di-providers-console` — providers do container para console" + +#. type: Title ### +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Delegates" +msgstr "Delegates" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-delegates` — common container delegates" +msgstr "`di-delegates` — delegates comuns do container" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-delegates-web` — web container delegates" +msgstr "`di-delegates-web` — delegates do container para web" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-delegates-console` — console container delegates" +msgstr "`di-delegates-console` — delegates do container para console" + +#. type: Title ### +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Tags" +msgstr "Tags" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-tags` — common container tags" +msgstr "`di-tags` — tags comuns do container" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-tags-web` — web container tags" +msgstr "`di-tags-web` — tags do container para web" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-tags-console` — console container tags" +msgstr "`di-tags-console` — tags do container para console" + +#. type: Plain text +#: ../src/en/internals/022-config-groups.md +msgid "Configuration for [yiisoft/yii-event](https://github.com/yiisoft/yii-event)." +msgstr "Configuração do [yiisoft/yii-event](https://github.com/yiisoft/yii-event)." + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`events` — common events" +msgstr "`events` — eventos comuns" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`events-web` — web events" +msgstr "`events-web` — eventos da web" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`events-console` — console events" +msgstr "`events-console` — eventos do console" + +#. type: Title ## +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Bootstrap" +msgstr "Bootstrap" + +#. type: Plain text +#: ../src/en/internals/022-config-groups.md +msgid "Application bootstrapping for [yiisoft/yii-runner](https://github.com/yiisoft/yii-runner)." +msgstr "Bootstrap da aplicação para o [yiisoft/yii-runner](https://github.com/yiisoft/yii-runner)." + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`bootstrap` — common bootstrap" +msgstr "`bootstrap` — bootstrap comum" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`bootstrap-web` — web bootstrap" +msgstr "`bootstrap-web` — bootstrap da web" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`bootstrap-console` — console bootstrap" +msgstr "`bootstrap-console` — bootstrap do console" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`routes` — [yiisoft/router](https://github.com/yiisoft/router) routes" +msgstr "`routes` — rotas do [yiisoft/router](https://github.com/yiisoft/router)" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`widgets` — [yiisoft/widget](https://github.com/yiisoft/widget) default widgets configuration" +msgstr "`widgets` — configuração padrão de widgets do [yiisoft/widget](https://github.com/yiisoft/widget)" diff --git a/_translations/po/pt-BR/internals_023-github-actions.md.po b/_translations/po/pt-BR/internals_023-github-actions.md.po new file mode 100644 index 00000000..240c47b7 --- /dev/null +++ b/_translations/po/pt-BR/internals_023-github-actions.md.po @@ -0,0 +1,88 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-04-05 07:15+0000\n" +"PO-Revision-Date: 2026-04-05 07:15+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/internals/023-github-actions.md +#, no-wrap +msgid "023 — GitHub Actions" +msgstr "023 — GitHub Actions" + +#. type: Plain text +#: ../src/internals/023-github-actions.md +msgid "This document defines naming convention for the GitHub actions configuration files." +msgstr "Este documento define a convenção de nomes para os arquivos de configuração das GitHub Actions." + +#. type: Title ## +#: ../src/internals/023-github-actions.md +#, no-wrap +msgid "Inputs and Outputs" +msgstr "Inputs e outputs" + +#. type: Plain text +#: ../src/internals/023-github-actions.md +msgid "Input names and output names must use kebab-case format." +msgstr "Os nomes de inputs e de outputs devem usar o formato kebab-case." + +#. type: Plain text +#: ../src/internals/023-github-actions.md +msgid "For example:" +msgstr "Por exemplo:" + +#. type: Fenced code block (yaml) +#: ../src/internals/023-github-actions.md +#, no-wrap +msgid "" +"inputs:\n" +" my-input:\n" +" description: 'My input'\n" +msgstr "" +"inputs:\n" +" my-input:\n" +" description: 'My input'\n" + +#. type: Title ## +#: ../src/internals/023-github-actions.md +#, no-wrap +msgid "Secrets and Environment Variables" +msgstr "Secrets e variáveis de ambiente" + +#. type: Plain text +#: ../src/internals/023-github-actions.md +msgid "Secret names and environment variable names must use SCREAMING_SNAKE_CASE format." +msgstr "Os nomes de secrets e de variáveis de ambiente devem usar o formato SCREAMING_SNAKE_CASE." + +#. type: Fenced code block (yaml) +#: ../src/internals/023-github-actions.md +#, no-wrap +msgid "" +"secrets:\n" +" MY_SECRET:\n" +" description: 'My secret'\n" +msgstr "" +"secrets:\n" +" MY_SECRET:\n" +" description: 'My secret'\n" + +#. type: Fenced code block (yaml) +#: ../src/internals/023-github-actions.md +#, no-wrap +msgid "" +"env:\n" +" MY_ENV_VAR: 1\n" +msgstr "" +"env:\n" +" MY_ENV_VAR: 1\n" diff --git a/_translations/po/pt-BR/internals_index.md.po b/_translations/po/pt-BR/internals_index.md.po new file mode 100644 index 00000000..7cbca58c --- /dev/null +++ b/_translations/po/pt-BR/internals_index.md.po @@ -0,0 +1,153 @@ +# Language pt-BR translations for PACKAGE package +# Copyright (C) 2026 Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# Automatically generated, 2026. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2026-04-05 07:15+0000\n" +"PO-Revision-Date: 2026-04-05 07:15+0000\n" +"Last-Translator: Yuri Neves \n" +"Language-Team: Portuguese (Brazil)\n" +"Language: pt-BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. type: Title # +#: ../src/internals/index.md +#, no-wrap +msgid "Yii Framework Internals" +msgstr "Detalhes internos do Yii Framework" + +#. type: Plain text +#: ../src/internals/index.md +msgid "This section contains documentation for developers contributing to the Yii framework itself. It covers guidelines, workflows, and best practices for maintaining and developing Yii packages." +msgstr "Esta seção contém documentação para quem contribui com o próprio framework Yii. Ela cobre diretrizes, fluxos de trabalho e boas práticas para manter e desenvolver os pacotes do Yii." + +#. type: Title ## +#: ../src/internals/index.md +#, no-wrap +msgid "Table of Contents" +msgstr "Sumário" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[000 — Packages](000-packages.md) - Package structure and naming conventions" +msgstr "[000 — Pacotes](000-packages.md) - Estrutura e convenções de nomes dos pacotes" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[001 — Yii goal and values](001-yii-values.md) - Project goals and core values" +msgstr "[001 — Objetivo e valores do Yii](001-yii-values.md) - Objetivos e valores centrais do projeto" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[002 — Issue workflow](002-issue-workflow.md) - How to handle issues" +msgstr "[002 — Fluxo de issues](002-issue-workflow.md) - Como lidar com issues" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[003 — Roadmap](003-roadmap.md) - Development roadmap and future plans" +msgstr "[003 — Roadmap](003-roadmap.md) - Roadmap de desenvolvimento e planos futuros" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[004 — Namespaces](004-namespaces.md) - Namespace conventions" +msgstr "[004 — Namespaces](004-namespaces.md) - Convenções de namespaces" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[005 — Yii development tool](005-development-tool.md) - Development tools for Yii packages" +msgstr "[005 — Ferramenta de desenvolvimento do Yii](005-development-tool.md) - Ferramentas de desenvolvimento para pacotes do Yii" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[006 — Git commit messages](006-git-commit-messages.md) - Commit message format" +msgstr "[006 — Mensagens de commit no Git](006-git-commit-messages.md) - Formato das mensagens de commit" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[007 — Exceptions](007-exceptions.md) - Exception handling guidelines" +msgstr "[007 — Exceções](007-exceptions.md) - Diretrizes para exceções" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[008 — Interfaces](008-interfaces.md) - Interface design principles" +msgstr "[008 — Interfaces](008-interfaces.md) - Princípios de design de interfaces" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[009 — Design Decisions](009-design-decisions.md) - Architectural and design decisions" +msgstr "[009 — Decisões de design](009-design-decisions.md) - Decisões de arquitetura e design" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[010 — Code style](010-code-style.md) - PHP code style guidelines" +msgstr "[010 — Estilo de código](010-code-style.md) - Diretrizes de estilo de código PHP" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[011 — Error correction](011-error-correction.md) - Error handling and correction" +msgstr "[011 — Correção de erros](011-error-correction.md) - Tratamento e correção de erros" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[012 — Tests](012-tests.md) - Testing guidelines and practices" +msgstr "[012 — Testes](012-tests.md) - Diretrizes e práticas de testes" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[013 — Code review](013-code-review.md) - Code review process and guidelines" +msgstr "[013 — Code review](013-code-review.md) - Processo e diretrizes de code review" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[014 — Documentation](014-docs.md) - Documentation writing guidelines" +msgstr "[014 — Documentação](014-docs.md) - Diretrizes para escrever documentação" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[015 — PhpStorm metadata and attributes](015-phpstorm.md) - PhpStorm integration" +msgstr "[015 — Metadados e atributos do PhpStorm](015-phpstorm.md) - Integração com o PhpStorm" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[016 — Security workflow](016-security-workflow.md) - Security issue handling" +msgstr "[016 — Fluxo de segurança](016-security-workflow.md) - Tratamento de problemas de segurança" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[017 — Tags](017-tags.md) - Git tagging conventions" +msgstr "[017 — Tags](017-tags.md) - Convenções de tags no Git" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[018 — Widgets](018-widgets.md) - Widget development guidelines" +msgstr "[018 — Widgets](018-widgets.md) - Diretrizes para desenvolver widgets" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[019 — View code style](019-view-code-style.md) - Code style for view templates" +msgstr "[019 — Estilo de código de views](019-view-code-style.md) - Estilo de código para templates de view" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[020 — Package release](020-package-release.md) - Release process for packages" +msgstr "[020 — Release de pacotes](020-package-release.md) - Processo de release de pacotes" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[021 — Changelog and upgrade](021-changelog-upgrade.md) - Maintaining changelogs and upgrade notes" +msgstr "[021 — Changelog e upgrade](021-changelog-upgrade.md) - Mantendo changelogs e notas de upgrade" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[022 — Config groups](022-config-groups.md) - Configuration group organization" +msgstr "[022 — Grupos de configuração](022-config-groups.md) - Organização dos grupos de configuração" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[023 - GitHub Actions](023-github-actions.md) - GitHub actions configuration" +msgstr "[023 - GitHub Actions](023-github-actions.md) - Configuração do GitHub Actions" diff --git a/_translations/po/ru/cookbook_organizing-code_service.md.po b/_translations/po/ru/cookbook_organizing-code_service.md.po index 8c0e1c23..a0dea9e0 100644 --- a/_translations/po/ru/cookbook_organizing-code_service.md.po +++ b/_translations/po/ru/cookbook_organizing-code_service.md.po @@ -17,15 +17,13 @@ msgstr "" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" #. type: Bullet: '- ' -#: ../src/cookbook/organizing-code/domain.md -#: ../src/cookbook/organizing-code/service.md +#: ../src/cookbook/organizing-code/domain.md ../src/cookbook/organizing-code/service.md #, fuzzy, no-wrap msgid "Entity" msgstr "Сущность" #. type: Title ## -#: ../src/cookbook/organizing-code/domain.md -#: ../src/cookbook/organizing-code/service.md ../src/guide/start/databases.md +#: ../src/cookbook/organizing-code/domain.md ../src/cookbook/organizing-code/service.md ../src/guide/start/databases.md #, no-wrap msgid "Repository" msgstr "Репозиторий" @@ -238,5 +236,5 @@ msgstr "" #. type: Bullet: '- ' #: ../src/cookbook/organizing-code/service.md -msgid "[Middleware](middleware.md)" +msgid "[Middleware](../../guide/structure/middleware.md)" msgstr "" diff --git a/_translations/po/ru/guide_caching_data.md.po b/_translations/po/ru/guide_caching_data.md.po index 9e5206f9..67e48872 100644 --- a/_translations/po/ru/guide_caching_data.md.po +++ b/_translations/po/ru/guide_caching_data.md.po @@ -24,7 +24,7 @@ msgstr "" #. type: Plain text #: ../../guide/en/caching/data.md -msgid "Data caching is about storing some PHP variables in a cache and retrieving them later from the cache. It's also the foundation for more advanced caching features, such as [page caching](page.md)." +msgid "Data caching is about storing some PHP variables in a cache and retrieving them later from the cache. It's also the foundation for more advanced caching features, such as page caching." msgstr "" #. type: Plain text @@ -100,7 +100,7 @@ msgstr "" #. type: Bullet: '- ' #: ../../guide/en/caching/data.md -msgid "[APCu](https://github.com/yiisoft/cache-apcu) - uses a PHP [APC](https://secure.php.net/manual/en/book.apc.php) extension. You can consider this option as the fastest one when dealing with cache for a centralized thick application (e.g., one server, no dedicated load balancers, etc.)." +msgid "[APCu](https://github.com/yiisoft/cache-apcu) - uses a PHP [APC](https://www.php.net/manual/en/book.apcu.php) extension. You can consider this option as the fastest one when dealing with cache for a centralized thick application (e.g., one server, no dedicated load balancers, etc.)." msgstr "" #. type: Bullet: '- ' diff --git a/_translations/po/ru/guide_caching_overview.md.po b/_translations/po/ru/guide_caching_overview.md.po index c56ab7c7..c70dde04 100644 --- a/_translations/po/ru/guide_caching_overview.md.po +++ b/_translations/po/ru/guide_caching_overview.md.po @@ -44,15 +44,15 @@ msgstr "" #. type: Bullet: '* ' #: ../src/guide/caching/overview.md -msgid "[Fragment caching](fragment.md)" +msgid "Fragment caching" msgstr "" #. type: Bullet: '* ' #: ../src/guide/caching/overview.md -msgid "[Page caching](page.md)" +msgid "Page caching" msgstr "" #. type: Bullet: '* ' #: ../src/guide/caching/overview.md -msgid "[HTTP caching](http.md)" +msgid "HTTP caching" msgstr "" diff --git a/_translations/po/ru/guide_glossary.md.po b/_translations/po/ru/guide_glossary.md.po index e96f1d15..e8d07000 100644 --- a/_translations/po/ru/guide_glossary.md.po +++ b/_translations/po/ru/guide_glossary.md.po @@ -472,7 +472,7 @@ msgstr "" #. type: Plain text #: ../src/guide/glossary.md -msgid "Service is a focused object that performs application work or provides infrastructure behavior and is usually stored in the DI container. Read more in [\"Service components\"](structure/service.md)." +msgid "Service is a focused object that performs application work or provides infrastructure behavior and is usually stored in the DI container. Read more in [\"Service components\"](../cookbook/organizing-code/service.md)." msgstr "" #. type: Title ## diff --git a/_translations/po/ru/guide_security_best-practices.md.po b/_translations/po/ru/guide_security_best-practices.md.po index 3b2f48b1..60f78576 100644 --- a/_translations/po/ru/guide_security_best-practices.md.po +++ b/_translations/po/ru/guide_security_best-practices.md.po @@ -18,12 +18,7 @@ msgstr "" "X-Generator: Poedit 3.7\n" #. type: Title ## -#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md -#: ../src/guide/concept/autoloading.md ../src/guide/concept/di-container.md -#: ../src/guide/security/best-practices.md ../src/guide/structure/domain.md -#: ../src/guide/tutorial/console-applications.md -#: ../src/internals/004-namespaces.md ../src/internals/007-exceptions.md -#: ../src/internals/008-interfaces.md +#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md ../src/guide/concept/autoloading.md ../src/guide/concept/di-container.md ../src/guide/security/best-practices.md ../src/guide/structure/domain.md ../src/guide/tutorial/console-applications.md ../src/internals/004-namespaces.md ../src/internals/007-exceptions.md ../src/internals/008-interfaces.md #, no-wrap msgid "References" msgstr "Ссылки" @@ -273,9 +268,9 @@ msgstr "\n" #. type: Plain text #: ../src/guide/security/best-practices.md -msgid "If it should be HTML, you could get some help from [HtmlPurifier](http://htmlpurifier.org/). Note that HtmlPurifier processing is quite heavy, so consider adding caching." +msgid "If it should be HTML, you could get some help from [HtmlPurifier](https://github.com/ezyang/htmlpurifier). Note that HtmlPurifier processing is quite heavy, so consider adding caching." msgstr "" -"Если нужно вывести HTML, вам лучше воспользоваться [HtmlPurifier](http://htmlpurifier.org/).\n" +"Если нужно вывести HTML, вам лучше воспользоваться [HtmlPurifier](https://github.com/ezyang/htmlpurifier).\n" "Обратите внимание, что обработка с помощью HtmlPurifier довольно тяжела, поэтому рассмотрите возможность использования кеширования." #. type: Title ## @@ -425,13 +420,13 @@ msgstr "" #. type: Bullet: '- ' #: ../src/guide/security/best-practices.md -msgid "" -msgstr "" +msgid "" +msgstr "" #. type: Bullet: '- ' #: ../src/guide/security/best-practices.md -msgid "" -msgstr "" +msgid "" +msgstr "" #. type: Title ## #: ../src/guide/security/best-practices.md diff --git a/_translations/po/ru/guide_start_hello.md.po b/_translations/po/ru/guide_start_hello.md.po index 1330aa26..117561eb 100644 --- a/_translations/po/ru/guide_start_hello.md.po +++ b/_translations/po/ru/guide_start_hello.md.po @@ -18,9 +18,7 @@ msgstr "" "X-Generator: Poedit 3.9\n" #. type: Title ## -#: ../src/cookbook/deployment/docker-swarm-caddy.md -#: ../src/cookbook/deployment/docker-swarm-traefik.md -#: ../src/guide/start/forms.md ../src/guide/start/hello.md +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md ../src/guide/start/forms.md ../src/guide/start/hello.md #, no-wrap msgid "Summary" msgstr "Краткое содержание" @@ -44,8 +42,8 @@ msgstr "В этом разделе описывается, как создать #. type: Plain text #: ../src/guide/start/hello.md -msgid "To achieve this goal, you will define a route and create [a handler](../structure/handler.md) that does the job and forms the response. Then you will improve it to use [view](../views/view.md) for building the response." -msgstr "Чтобы этого добиться, вы определите маршрут и создадите [обработчик](../structure/handler.md), который выполнит задачу и сформирует ответ. Затем вы улучшите решение, используя [представление](../views/view.md) для построения ответа." +msgid "To achieve this goal, you will define a route and create [a handler](../structure/action.md) that does the job and forms the response. Then you will improve it to use [view](../views/view.md) for building the response." +msgstr "Чтобы этого добиться, вы определите маршрут и создадите [обработчик](../structure/action.md), который выполнит задачу и сформирует ответ. Затем вы улучшите решение, используя [представление](../views/view.md) для построения ответа." #. type: Plain text #: ../src/guide/start/hello.md diff --git a/_translations/po/ru/guide_structure_overview.md.po b/_translations/po/ru/guide_structure_overview.md.po index 3ba138d4..e1fc70fa 100644 --- a/_translations/po/ru/guide_structure_overview.md.po +++ b/_translations/po/ru/guide_structure_overview.md.po @@ -17,8 +17,7 @@ msgstr "" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" #. type: Title ## -#: ../src/en/guide/structure/overview.md -#: ../src/en/guide/views/script-style-meta.md +#: ../src/en/guide/structure/overview.md ../src/en/guide/views/script-style-meta.md #, no-wrap msgid "Overview" msgstr "" @@ -137,7 +136,7 @@ msgstr "" #. type: Plain text #: ../src/en/guide/structure/overview.md -msgid "A context may have [an entry point known as \"action\" or \"controller\"](action.md). Its job is to take [a request instance](../runtime/request.md), pass it to [domain layer](domain.md) in a suitable format, and create [a response](../runtime/response.md) based on domain layer return." +msgid "A context may have [an entry point known as \"action\" or \"controller\"](action.md). Its job is to take [a request instance](../runtime/request.md), pass it to [domain layer](../../cookbook/organizing-code/domain.md) in a suitable format, and create [a response](../runtime/response.md) based on domain layer return." msgstr "" #. type: Plain text @@ -152,7 +151,7 @@ msgstr "" #. type: Bullet: '* ' #: ../src/en/guide/structure/overview.md -msgid "[services](service.md): they're typically stateless objects registered within dependency container and provide various action methods." +msgid "[services](../../cookbook/organizing-code/service.md): they're typically stateless objects registered within dependency container and provide various action methods." msgstr "" #. type: Bullet: '* ' diff --git a/_translations/po/ru/internals_014-docs.md.po b/_translations/po/ru/internals_014-docs.md.po index e0c5139d..ff20d098 100644 --- a/_translations/po/ru/internals_014-docs.md.po +++ b/_translations/po/ru/internals_014-docs.md.po @@ -67,7 +67,7 @@ msgstr "" #. type: Plain text #: ../src/internals/014-docs.md -msgid "The definitive guide, [yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/guide/en) aims at covering usage of packages as a whole framework. Unlike package documentation, it isn't focused on a single package but is covering certain use-cases." +msgid "The definitive guide, [yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/src/guide) aims at covering usage of packages as a whole framework. Unlike package documentation, it isn't focused on a single package but is covering certain use-cases." msgstr "" #. type: Plain text diff --git a/_translations/po/zh-CN/cookbook_organizing-code_service.md.po b/_translations/po/zh-CN/cookbook_organizing-code_service.md.po index c3e1b36f..dd36e5d9 100644 --- a/_translations/po/zh-CN/cookbook_organizing-code_service.md.po +++ b/_translations/po/zh-CN/cookbook_organizing-code_service.md.po @@ -16,15 +16,13 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" #. type: Bullet: '- ' -#: ../src/cookbook/organizing-code/domain.md -#: ../src/cookbook/organizing-code/service.md +#: ../src/cookbook/organizing-code/domain.md ../src/cookbook/organizing-code/service.md #, fuzzy, no-wrap msgid "Entity" msgstr "实体" #. type: Title ## -#: ../src/cookbook/organizing-code/domain.md -#: ../src/cookbook/organizing-code/service.md ../src/guide/start/databases.md +#: ../src/cookbook/organizing-code/domain.md ../src/cookbook/organizing-code/service.md ../src/guide/start/databases.md #, no-wrap msgid "Repository" msgstr "仓库" @@ -199,5 +197,5 @@ msgstr "小部件" #: ../src/cookbook/organizing-code/service.md #, fuzzy #| msgid "[Middleware](structure/middleware.md)" -msgid "[Middleware](middleware.md)" +msgid "[Middleware](../../guide/structure/middleware.md)" msgstr "[中间件](structure/middleware.md)" diff --git a/_translations/po/zh-CN/guide_caching_data.md.po b/_translations/po/zh-CN/guide_caching_data.md.po index c079ff93..5991a85f 100644 --- a/_translations/po/zh-CN/guide_caching_data.md.po +++ b/_translations/po/zh-CN/guide_caching_data.md.po @@ -23,8 +23,8 @@ msgstr "数据缓存" #. type: Plain text #: ../../guide/en/caching/data.md -msgid "Data caching is about storing some PHP variables in a cache and retrieving them later from the cache. It's also the foundation for more advanced caching features, such as [page caching](page.md)." -msgstr "数据缓存是将一些 PHP 变量存储在缓存中,然后稍后从缓存中检索它们。它也是更高级缓存功能(如 [页面缓存](page.md))的基础。" +msgid "Data caching is about storing some PHP variables in a cache and retrieving them later from the cache. It's also the foundation for more advanced caching features, such as page caching." +msgstr "数据缓存是将一些 PHP 变量存储在缓存中,然后稍后从缓存中检索它们。它也是更高级缓存功能(如 页面缓存)的基础。" #. type: Plain text #: ../../guide/en/caching/data.md @@ -98,8 +98,8 @@ msgstr "`ArrayCache` — 通过将值存储在数组中,仅为当前请求提 #. type: Bullet: '- ' #: ../../guide/en/caching/data.md -msgid "[APCu](https://github.com/yiisoft/cache-apcu) - uses a PHP [APC](https://secure.php.net/manual/en/book.apc.php) extension. You can consider this option as the fastest one when dealing with cache for a centralized thick application (e.g., one server, no dedicated load balancers, etc.)." -msgstr "[APCu](https://github.com/yiisoft/cache-apcu) - 使用 PHP [APC](https://secure.php.net/manual/en/book.apc.php) 扩展。在处理集中式厚应用程序(例如,单服务器,无专用负载均衡器等)的缓存时,您可以将此选项视为最快的选项。" +msgid "[APCu](https://github.com/yiisoft/cache-apcu) - uses a PHP [APC](https://www.php.net/manual/en/book.apcu.php) extension. You can consider this option as the fastest one when dealing with cache for a centralized thick application (e.g., one server, no dedicated load balancers, etc.)." +msgstr "[APCu](https://github.com/yiisoft/cache-apcu) - 使用 PHP [APC](https://www.php.net/manual/en/book.apcu.php) 扩展。在处理集中式厚应用程序(例如,单服务器,无专用负载均衡器等)的缓存时,您可以将此选项视为最快的选项。" #. type: Bullet: '- ' #: ../../guide/en/caching/data.md diff --git a/_translations/po/zh-CN/guide_caching_overview.md.po b/_translations/po/zh-CN/guide_caching_overview.md.po index 57ebf1f7..5af10747 100644 --- a/_translations/po/zh-CN/guide_caching_overview.md.po +++ b/_translations/po/zh-CN/guide_caching_overview.md.po @@ -43,15 +43,15 @@ msgstr "[数据缓存](data.md)" #. type: Bullet: '* ' #: ../src/guide/caching/overview.md -msgid "[Fragment caching](fragment.md)" -msgstr "[片段缓存](fragment.md)" +msgid "Fragment caching" +msgstr "片段缓存" #. type: Bullet: '* ' #: ../src/guide/caching/overview.md -msgid "[Page caching](page.md)" -msgstr "[页面缓存](page.md)" +msgid "Page caching" +msgstr "页面缓存" #. type: Bullet: '* ' #: ../src/guide/caching/overview.md -msgid "[HTTP caching](http.md)" -msgstr "[HTTP 缓存](http.md)" +msgid "HTTP caching" +msgstr "HTTP 缓存" diff --git a/_translations/po/zh-CN/guide_glossary.md.po b/_translations/po/zh-CN/guide_glossary.md.po index 4ab8d76b..928cce6c 100644 --- a/_translations/po/zh-CN/guide_glossary.md.po +++ b/_translations/po/zh-CN/guide_glossary.md.po @@ -487,7 +487,7 @@ msgstr "服务" #. type: Plain text #: ../src/guide/glossary.md -msgid "Service is a focused object that performs application work or provides infrastructure behavior and is usually stored in the DI container. Read more in [\"Service components\"](structure/service.md)." +msgid "Service is a focused object that performs application work or provides infrastructure behavior and is usually stored in the DI container. Read more in [\"Service components\"](../cookbook/organizing-code/service.md)." msgstr "" #. type: Title ## diff --git a/_translations/po/zh-CN/guide_security_best-practices.md.po b/_translations/po/zh-CN/guide_security_best-practices.md.po index e8afe6de..9b1ef40a 100644 --- a/_translations/po/zh-CN/guide_security_best-practices.md.po +++ b/_translations/po/zh-CN/guide_security_best-practices.md.po @@ -16,12 +16,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" #. type: Title ## -#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md -#: ../src/guide/concept/autoloading.md ../src/guide/concept/di-container.md -#: ../src/guide/security/best-practices.md ../src/guide/structure/domain.md -#: ../src/guide/tutorial/console-applications.md -#: ../src/internals/004-namespaces.md ../src/internals/007-exceptions.md -#: ../src/internals/008-interfaces.md +#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md ../src/guide/concept/autoloading.md ../src/guide/concept/di-container.md ../src/guide/security/best-practices.md ../src/guide/structure/domain.md ../src/guide/tutorial/console-applications.md ../src/internals/004-namespaces.md ../src/internals/007-exceptions.md ../src/internals/008-interfaces.md #, no-wrap msgid "References" msgstr "参考资料" @@ -250,8 +245,8 @@ msgstr "" #. type: Plain text #: ../src/guide/security/best-practices.md -msgid "If it should be HTML, you could get some help from [HtmlPurifier](http://htmlpurifier.org/). Note that HtmlPurifier processing is quite heavy, so consider adding caching." -msgstr "如果它应该是 HTML,您可以从 [HtmlPurifier](http://htmlpurifier.org/) 获得一些帮助。请注意,HtmlPurifier 处理相当繁重,因此请考虑添加缓存。" +msgid "If it should be HTML, you could get some help from [HtmlPurifier](https://github.com/ezyang/htmlpurifier). Note that HtmlPurifier processing is quite heavy, so consider adding caching." +msgstr "如果它应该是 HTML,您可以从 [HtmlPurifier](https://github.com/ezyang/htmlpurifier) 获得一些帮助。请注意,HtmlPurifier 处理相当繁重,因此请考虑添加缓存。" #. type: Title ## #: ../src/guide/security/best-practices.md @@ -385,12 +380,12 @@ msgstr "除非必要,否则应避免在生产环境中使用调试工具栏。 #. type: Bullet: '- ' #: ../src/guide/security/best-practices.md -msgid "" +msgid "" msgstr "" #. type: Bullet: '- ' #: ../src/guide/security/best-practices.md -msgid "" +msgid "" msgstr "" #. type: Title ## diff --git a/_translations/po/zh-CN/guide_start_hello.md.po b/_translations/po/zh-CN/guide_start_hello.md.po index fdc2668a..fcbd1437 100644 --- a/_translations/po/zh-CN/guide_start_hello.md.po +++ b/_translations/po/zh-CN/guide_start_hello.md.po @@ -16,9 +16,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" #. type: Title ## -#: ../src/cookbook/deployment/docker-swarm-caddy.md -#: ../src/cookbook/deployment/docker-swarm-traefik.md -#: ../src/guide/start/forms.md ../src/guide/start/hello.md +#: ../src/cookbook/deployment/docker-swarm-caddy.md ../src/cookbook/deployment/docker-swarm-traefik.md ../src/guide/start/forms.md ../src/guide/start/hello.md #, no-wrap msgid "Summary" msgstr "总结" @@ -42,8 +40,8 @@ msgstr "本节描述如何在应用程序中创建一个新的“Hello”页面 #. type: Plain text #: ../src/guide/start/hello.md -msgid "To achieve this goal, you will define a route and create [a handler](../structure/handler.md) that does the job and forms the response. Then you will improve it to use [view](../views/view.md) for building the response." -msgstr "为实现这个目标,您将定义一个路由并创建一个 [处理器](../structure/handler.md) 来完成工作并形成响应。然后您将改进它,使用[视图](../views/view.md)来构建响应。" +msgid "To achieve this goal, you will define a route and create [a handler](../structure/action.md) that does the job and forms the response. Then you will improve it to use [view](../views/view.md) for building the response." +msgstr "为实现这个目标,您将定义一个路由并创建一个 [处理器](../structure/action.md) 来完成工作并形成响应。然后您将改进它,使用[视图](../views/view.md)来构建响应。" #. type: Plain text #: ../src/guide/start/hello.md diff --git a/_translations/po/zh-CN/guide_structure_overview.md.po b/_translations/po/zh-CN/guide_structure_overview.md.po index 67b21cc7..e1db7a9b 100644 --- a/_translations/po/zh-CN/guide_structure_overview.md.po +++ b/_translations/po/zh-CN/guide_structure_overview.md.po @@ -16,8 +16,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" #. type: Title ## -#: ../src/en/guide/structure/overview.md -#: ../src/en/guide/views/script-style-meta.md +#: ../src/en/guide/structure/overview.md ../src/en/guide/views/script-style-meta.md #, no-wrap msgid "Overview" msgstr "概述" @@ -152,8 +151,8 @@ msgstr "一个上下文可以包含子上下文。如果一个类被多个上下 #. type: Plain text #: ../src/en/guide/structure/overview.md -msgid "A context may have [an entry point known as \"action\" or \"controller\"](action.md). Its job is to take [a request instance](../runtime/request.md), pass it to [domain layer](domain.md) in a suitable format, and create [a response](../runtime/response.md) based on domain layer return." -msgstr "一个上下文可以有 [一个称为“动作”或“控制器”的入口点](action.md)。它的工作是获取[请求实例](../runtime/request.md),以适当的格式将其传递给 [领域层](domain.md),并根据领域层的返回创建 [响应](../runtime/response.md)。" +msgid "A context may have [an entry point known as \"action\" or \"controller\"](action.md). Its job is to take [a request instance](../runtime/request.md), pass it to [domain layer](../../cookbook/organizing-code/domain.md) in a suitable format, and create [a response](../runtime/response.md) based on domain layer return." +msgstr "一个上下文可以有 [一个称为“动作”或“控制器”的入口点](action.md)。它的工作是获取[请求实例](../runtime/request.md),以适当的格式将其传递给 [领域层](../../cookbook/organizing-code/domain.md),并根据领域层的返回创建 [响应](../runtime/response.md)。" #. type: Plain text #: ../src/en/guide/structure/overview.md @@ -167,8 +166,8 @@ msgstr "[入口脚本](entry-script.md):它们是最终用户可以直接访 #. type: Bullet: '* ' #: ../src/en/guide/structure/overview.md -msgid "[services](service.md): they're typically stateless objects registered within dependency container and provide various action methods." -msgstr "[服务](service.md):它们通常是在依赖容器中注册的无状态对象,并提供各种操作方法。" +msgid "[services](../../cookbook/organizing-code/service.md): they're typically stateless objects registered within dependency container and provide various action methods." +msgstr "[服务](../../cookbook/organizing-code/service.md):它们通常是在依赖容器中注册的无状态对象,并提供各种操作方法。" #. type: Bullet: '* ' #: ../src/en/guide/structure/overview.md diff --git a/_translations/po/zh-CN/internals_014-docs.md.po b/_translations/po/zh-CN/internals_014-docs.md.po index d0b52c1d..a58a2399 100644 --- a/_translations/po/zh-CN/internals_014-docs.md.po +++ b/_translations/po/zh-CN/internals_014-docs.md.po @@ -65,8 +65,8 @@ msgstr "权威指南" #. type: Plain text #: ../src/internals/014-docs.md -msgid "The definitive guide, [yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/guide/en) aims at covering usage of packages as a whole framework. Unlike package documentation, it isn't focused on a single package but is covering certain use-cases." -msgstr "权威指南 [yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/guide/en) 旨在涵盖作为整个框架的包的使用。与包文档不同,它不专注于单个包,而是涵盖某些用例。" +msgid "The definitive guide, [yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/src/guide) aims at covering usage of packages as a whole framework. Unlike package documentation, it isn't focused on a single package but is covering certain use-cases." +msgstr "权威指南 [yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/src/guide) 旨在涵盖作为整个框架的包的使用。与包文档不同,它不专注于单个包,而是涵盖某些用例。" #. type: Plain text #: ../src/internals/014-docs.md diff --git a/_translations/po4a-base.conf b/_translations/po4a-base.conf index 63e1aa0a..fe5ca0ae 100644 --- a/_translations/po4a-base.conf +++ b/_translations/po4a-base.conf @@ -1,4 +1,4 @@ -[po4a_langs] ru id it es zh-CN +[po4a_langs] ru id it es zh-CN pt-BR [po4a_paths] pot/$master.pot $lang:po/$lang/$master.po [options] opt:"--verbose" opt:"--addendum-charset=UTF-8" opt:"--localized-charset=UTF-8" opt:"--master-charset=UTF-8" opt:"--master-language=en_US" opt:"--porefs=file" opt:"--msgmerge-opt='--no-wrap'" opt:"--wrap-po=newlines" diff --git a/_translations/po4a.conf b/_translations/po4a.conf index 28219324..39894812 100644 --- a/_translations/po4a.conf +++ b/_translations/po4a.conf @@ -1,4 +1,4 @@ -[po4a_langs] ru id it es zh-CN +[po4a_langs] ru id it es zh-CN pt-BR [po4a_paths] pot/$master.pot $lang:po/$lang/$master.po [options] opt:"--verbose" opt:"--addendum-charset=UTF-8" opt:"--localized-charset=UTF-8" opt:"--master-charset=UTF-8" opt:"--master-language=en_US" opt:"--porefs=file" opt:"--msgmerge-opt='--no-wrap'" opt:"--wrap-po=newlines" diff --git a/_translations/pot/cookbook_organizing-code_service.md.pot b/_translations/pot/cookbook_organizing-code_service.md.pot index 48c070d6..03958078 100644 --- a/_translations/pot/cookbook_organizing-code_service.md.pot +++ b/_translations/pot/cookbook_organizing-code_service.md.pot @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2026-10-11 10:37+0000\n" +"POT-Creation-Date: 2026-10-23 18:03+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -225,5 +225,5 @@ msgstr "" #. type: Bullet: '- ' #: ../src/cookbook/organizing-code/service.md -msgid "[Middleware](middleware.md)" +msgid "[Middleware](../../guide/structure/middleware.md)" msgstr "" diff --git a/_translations/pot/guide_caching_data.md.pot b/_translations/pot/guide_caching_data.md.pot index 5b8f8591..b99982f6 100644 --- a/_translations/pot/guide_caching_data.md.pot +++ b/_translations/pot/guide_caching_data.md.pot @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2025-09-11 10:15+0500\n" +"POT-Creation-Date: 2026-10-23 18:03+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,41 +17,41 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" #. type: Title # -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md #, no-wrap msgid "Data caching" msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "Data caching is about storing some PHP variables in a cache and retrieving " "them later from the cache. It's also the foundation for more advanced " -"caching features, such as [page caching](page.md)." +"caching features, such as page caching." msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "To use cache, install [yiisoft/cache](https://github.com/yiisoft/cache) " "package:" msgstr "" #. type: Fenced code block (shell) -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md #, no-wrap msgid "composer require yiisoft/cache\n" msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "The following code is a typical usage pattern of data caching, where " "`$cache` refers to a `Cache` instance from the package:" msgstr "" #. type: Fenced code block (php) -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md #, no-wrap msgid "" "public function getTopProducts(\\Yiisoft\\Cache\\CacheInterface $cache): array\n" @@ -69,7 +69,7 @@ msgid "" msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "When cache has data associated with the `$key`, it returns the cached " "value. Otherwise, it executes the passed anonymous function to calculate " @@ -77,20 +77,20 @@ msgid "" msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "If the anonymous function requires some data from the outer scope, you can " "pass it with the `use` statement." msgstr "" #. type: Title ## -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md #, no-wrap msgid "Cache handlers" msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "The cache service uses [PSR-16](https://www.php-fig.org/psr/psr-16/) " "compatible cache handlers which represent various cache storages, such as " @@ -98,12 +98,12 @@ msgid "" msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "Yii provides the following handlers:" msgstr "" #. type: Bullet: '- ' -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "`NullCache` — a cache placeholder which does no real caching. The purpose of " "this handler is to simplify the code that needs to check the availability of " @@ -115,30 +115,30 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "`ArrayCache` — provides caching for the current request only by storing the " "values in an array." msgstr "" #. type: Bullet: '- ' -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "[APCu](https://github.com/yiisoft/cache-apcu) - uses a PHP [APC](https://" -"secure.php.net/manual/en/book.apc.php) extension. You can consider this " +"www.php.net/manual/en/book.apcu.php) extension. You can consider this " "option as the fastest one when dealing with cache for a centralized thick " "application (e.g., one server, no dedicated load balancers, etc.)." msgstr "" #. type: Bullet: '- ' -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "[Database](https://github.com/yiisoft/cache-db) — uses a database table to " "store cached data." msgstr "" #. type: Bullet: '- ' -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "[File](https://github.com/yiisoft/cache-file) — uses standard files to store " "cached data. This is particularly suitable to cache large chunks of data, " @@ -146,7 +146,7 @@ msgid "" msgstr "" #. type: Bullet: '- ' -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "[Memcached](https://github.com/yiisoft/cache-memcached) — uses a PHP " "[memcached](https://secure.php.net/manual/en/book.memcached.php) extension. " @@ -155,7 +155,7 @@ msgid "" msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md #, no-wrap msgid "" " (e.g., with several servers, load balancers, etc.)\n" @@ -164,14 +164,14 @@ msgid "" msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "[You could find more handlers at packagist.org](https://packagist.org/" "providers/psr/simple-cache-implementation)." msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md #, no-wrap msgid "" "> [!TIP]\n" @@ -181,7 +181,7 @@ msgid "" msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "Cache handlers are usually set up in a [dependency injection container](../" "concept/di-container.md) so that they can be globally configurable and " @@ -189,7 +189,7 @@ msgid "" msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "Because all cache handlers support the same set of APIs, you can swap the " "underlying cache handler with a different one. You can do it by " @@ -197,13 +197,13 @@ msgid "" msgstr "" #. type: Title ### -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md #, no-wrap msgid "Cache keys" msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "A key uniquely identifies each data item stored in the cache. When you store " "a data item, you have to specify a key for it. Later, when you retrieve the " @@ -211,21 +211,21 @@ msgid "" msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "You may use a string or an arbitrary value as a cache key. When a key isn't " "a string, it will be automatically serialized into a string." msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "A common strategy of defining a cache key is to include all determining " "factors in terms of an array." msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "When different applications use the same cache storage, you should specify a " "unique cache key prefix for each application to avoid conflicts of cache " @@ -233,7 +233,7 @@ msgid "" msgstr "" #. type: Fenced code block (php) -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md #, no-wrap msgid "" "$arrayCacheWithPrefix = new \\Yiisoft\\Cache\\PrefixedCache(new \\Yiisoft\\Cache\\ArrayCache(), 'myapp_');\n" @@ -241,13 +241,13 @@ msgid "" msgstr "" #. type: Title ### -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md #, no-wrap msgid "Cache expiration" msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "A data item stored in a cache will remain there forever unless it's removed " "because of some caching policy enforcement. For example, caching space is " @@ -256,7 +256,7 @@ msgid "" msgstr "" #. type: Fenced code block (php) -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md #, no-wrap msgid "" "$ttl = 3600;\n" @@ -266,7 +266,7 @@ msgid "" msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "The `$ttl` parameter indicates for how many seconds the data item can remain " "valid in the cache. When you retrieve the data item, if it has passed the " @@ -275,35 +275,35 @@ msgid "" msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "You may set the default TTL for the cache:" msgstr "" #. type: Fenced code block (php) -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md #, no-wrap msgid "$cache = new \\Yiisoft\\Cache\\Cache($arrayCache, 60 * 60); // 1 hour\n" msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "Additionally, you can invalidate a cache key explicitly:" msgstr "" #. type: Fenced code block (php) -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md #, no-wrap msgid "$cache->remove($key);\n" msgstr "" #. type: Title ### -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md #, no-wrap msgid "Invalidation dependencies" msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "Besides the expiration setting, changes of the so-called **invalidation " "dependencies** may also invalidate cached data item. For example, " @@ -314,7 +314,7 @@ msgid "" msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "Cache dependencies are objects of `\\Yiisoft\\Cache\\Dependency\\Dependency` " "descendant classes. When you store a data item in the cache, you can pass " @@ -322,7 +322,7 @@ msgid "" msgstr "" #. type: Fenced code block (php) -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md #, no-wrap msgid "" "/**\n" @@ -341,33 +341,33 @@ msgid "" msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "Below is a summary of the available cache dependencies:" msgstr "" #. type: Bullet: '- ' -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "`\\Yiisoft\\Cache\\Dependency\\ValueDependency`: invalidates the cache when " "specified value changes." msgstr "" #. type: Bullet: '- ' -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "`\\Yiisoft\\Cache\\Dependency\\CallbackDependency`: invalidates the cache " "when the result of the specified PHP callback is different." msgstr "" #. type: Bullet: '- ' -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "`\\Yiisoft\\Cache\\Dependency\\FileDependency`: invalidates the cache when " "the file's last modification time is different." msgstr "" #. type: Bullet: '- ' -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "`\\Yiisoft\\Cache\\Dependency\\TagDependency`: associates a cached data item " "with one or many tags. You may invalidate the cached data items with the " @@ -375,7 +375,7 @@ msgid "" msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "You may combine many dependencies using " "`\\Yiisoft\\Cache\\Dependency\\AnyDependency` or " @@ -383,20 +383,20 @@ msgid "" msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "To implement your own dependency, extend from " "`\\Yiisoft\\Cache\\Dependency\\Dependency`." msgstr "" #. type: Title ### -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md #, no-wrap msgid "Cache stampede prevention" msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "[A cache stampede](https://en.wikipedia.org/wiki/Cache_stampede) is a type " "of cascading failure that can occur when massively parallel computing " @@ -405,7 +405,7 @@ msgid "" msgstr "" #. type: Plain text -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md msgid "" "The `\\Yiisoft\\Cache\\Cache` uses a built-in \"Probably early expiration\" " "algorithm that prevents cache stampede. This algorithm randomly fakes a " @@ -416,7 +416,7 @@ msgid "" msgstr "" #. type: Fenced code block (php) -#: ../../guide/en/caching/data.md +#: ../src/guide/caching/data.md #, no-wrap msgid "" "/**\n" diff --git a/_translations/pot/guide_caching_overview.md.pot b/_translations/pot/guide_caching_overview.md.pot index 05f5893f..b1578150 100644 --- a/_translations/pot/guide_caching_overview.md.pot +++ b/_translations/pot/guide_caching_overview.md.pot @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2025-12-24 08:23+0000\n" +"POT-Creation-Date: 2026-10-23 18:03+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -55,15 +55,15 @@ msgstr "" #. type: Bullet: '* ' #: ../src/guide/caching/overview.md -msgid "[Fragment caching](fragment.md)" +msgid "Fragment caching" msgstr "" #. type: Bullet: '* ' #: ../src/guide/caching/overview.md -msgid "[Page caching](page.md)" +msgid "Page caching" msgstr "" #. type: Bullet: '* ' #: ../src/guide/caching/overview.md -msgid "[HTTP caching](http.md)" +msgid "HTTP caching" msgstr "" diff --git a/_translations/pot/guide_glossary.md.pot b/_translations/pot/guide_glossary.md.pot index 146a2a64..0b5533f1 100644 --- a/_translations/pot/guide_glossary.md.pot +++ b/_translations/pot/guide_glossary.md.pot @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2026-05-30 06:43+0000\n" +"POT-Creation-Date: 2026-10-23 18:03+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -551,7 +551,7 @@ msgstr "" msgid "" "Service is a focused object that performs application work or provides " "infrastructure behavior and is usually stored in the DI container. Read " -"more in [\"Service components\"](structure/service.md)." +"more in [\"Service components\"](../cookbook/organizing-code/service.md)." msgstr "" #. type: Title ## diff --git a/_translations/pot/guide_security_best-practices.md.pot b/_translations/pot/guide_security_best-practices.md.pot index c1e37d3f..7575cd7b 100644 --- a/_translations/pot/guide_security_best-practices.md.pot +++ b/_translations/pot/guide_security_best-practices.md.pot @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2026-06-29 17:10+0000\n" +"POT-Creation-Date: 2026-10-23 18:03+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,9 +17,10 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" #. type: Title ## +#: ../src/cookbook/organizing-code/domain.md #: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md #: ../src/guide/concept/autoloading.md ../src/guide/concept/di-container.md -#: ../src/guide/security/best-practices.md ../src/guide/structure/domain.md +#: ../src/guide/security/best-practices.md #: ../src/guide/tutorial/console-applications.md #: ../src/internals/004-namespaces.md ../src/internals/007-exceptions.md #: ../src/internals/008-interfaces.md @@ -272,9 +273,9 @@ msgstr "" #. type: Plain text #: ../src/guide/security/best-practices.md msgid "" -"If it should be HTML, you could get some help from [HtmlPurifier](http://" -"htmlpurifier.org/). Note that HtmlPurifier processing is quite heavy, so " -"consider adding caching." +"If it should be HTML, you could get some help from [HtmlPurifier](https://" +"github.com/ezyang/htmlpurifier). Note that HtmlPurifier processing is quite " +"heavy, so consider adding caching." msgstr "" #. type: Title ## @@ -419,12 +420,14 @@ msgstr "" #. type: Bullet: '- ' #: ../src/guide/security/best-practices.md -msgid "" +msgid "" +"" msgstr "" #. type: Bullet: '- ' #: ../src/guide/security/best-practices.md -msgid "" +msgid "" msgstr "" #. type: Title ## diff --git a/_translations/pot/guide_start_hello.md.pot b/_translations/pot/guide_start_hello.md.pot index d3f7726c..53ea7256 100644 --- a/_translations/pot/guide_start_hello.md.pot +++ b/_translations/pot/guide_start_hello.md.pot @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2026-06-05 20:33+0000\n" +"POT-Creation-Date: 2026-10-23 18:03+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -48,7 +48,7 @@ msgstr "" #: ../src/guide/start/hello.md msgid "" "To achieve this goal, you will define a route and create [a handler](../" -"structure/handler.md) that does the job and forms the response. Then you " +"structure/action.md) that does the job and forms the response. Then you " "will improve it to use [view](../views/view.md) for building the response." msgstr "" diff --git a/_translations/pot/guide_structure_overview.md.pot b/_translations/pot/guide_structure_overview.md.pot index 1a624f5d..58ad2663 100644 --- a/_translations/pot/guide_structure_overview.md.pot +++ b/_translations/pot/guide_structure_overview.md.pot @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2025-12-24 08:02+0000\n" +"POT-Creation-Date: 2026-10-23 18:03+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,104 +17,103 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" #. type: Title ## -#: ../src/en/guide/structure/overview.md -#: ../src/en/guide/views/script-style-meta.md +#: ../src/guide/structure/overview.md ../src/guide/views/script-style-meta.md #, no-wrap msgid "Overview" msgstr "" #. type: Plain text -#: ../src/en/guide/structure/overview.md +#: ../src/guide/structure/overview.md msgid "" "Yii applications code is typically grouped into modules by context. In each " "module there could be grouping by type." msgstr "" #. type: Plain text -#: ../src/en/guide/structure/overview.md +#: ../src/guide/structure/overview.md msgid "" "For example, if the application is an online store, the context could be:" msgstr "" #. type: Bullet: '- ' -#: ../src/en/guide/structure/overview.md +#: ../src/guide/structure/overview.md msgid "Customer" msgstr "" #. type: Bullet: ' - ' -#: ../src/en/guide/structure/overview.md +#: ../src/guide/structure/overview.md msgid "Profile" msgstr "" #. type: Bullet: ' - ' -#: ../src/en/guide/structure/overview.md +#: ../src/guide/structure/overview.md msgid "Products list" msgstr "" #. type: Bullet: ' - ' -#: ../src/en/guide/structure/overview.md +#: ../src/guide/structure/overview.md msgid "Checkout" msgstr "" #. type: Bullet: '- ' -#: ../src/en/guide/structure/overview.md +#: ../src/guide/structure/overview.md msgid "Logistics" msgstr "" #. type: Bullet: '- ' -#: ../src/en/guide/structure/overview.md +#: ../src/guide/structure/overview.md msgid "Delivery" msgstr "" #. type: Bullet: ' - ' -#: ../src/en/guide/structure/overview.md +#: ../src/guide/structure/overview.md msgid "Addresses" msgstr "" #. type: Bullet: '- ' -#: ../src/en/guide/structure/overview.md +#: ../src/guide/structure/overview.md msgid "Helpdesk" msgstr "" #. type: Bullet: ' - ' -#: ../src/en/guide/structure/overview.md +#: ../src/guide/structure/overview.md msgid "Support" msgstr "" #. type: Bullet: ' - ' -#: ../src/en/guide/structure/overview.md +#: ../src/guide/structure/overview.md msgid "Claims" msgstr "" #. type: Bullet: ' - ' -#: ../src/en/guide/structure/overview.md +#: ../src/guide/structure/overview.md msgid "Returns" msgstr "" #. type: Bullet: '- ' -#: ../src/en/guide/structure/overview.md +#: ../src/guide/structure/overview.md msgid "Accounting" msgstr "" #. type: Bullet: ' - ' -#: ../src/en/guide/structure/overview.md +#: ../src/guide/structure/overview.md msgid "Transactions" msgstr "" #. type: Bullet: ' - ' -#: ../src/en/guide/structure/overview.md +#: ../src/guide/structure/overview.md msgid "Taxes" msgstr "" #. type: Plain text -#: ../src/en/guide/structure/overview.md +#: ../src/guide/structure/overview.md msgid "" "For a \"Customer\" context, residing under `App\\Customer` namespace, " "structure would be:" msgstr "" #. type: Fenced code block -#: ../src/en/guide/structure/overview.md +#: ../src/guide/structure/overview.md #, no-wrap msgid "" "App/\n" @@ -136,28 +135,29 @@ msgid "" msgstr "" #. type: Plain text -#: ../src/en/guide/structure/overview.md +#: ../src/guide/structure/overview.md msgid "" "A context may include sub-contexts. If a class is shared by multiple " "contexts, it's moved to the ancestor of both contexts." msgstr "" #. type: Plain text -#: ../src/en/guide/structure/overview.md +#: ../src/guide/structure/overview.md msgid "" "A context may have [an entry point known as \"action\" or \"controller\"]" "(action.md). Its job is to take [a request instance](../runtime/request.md), " -"pass it to [domain layer](domain.md) in a suitable format, and create [a " -"response](../runtime/response.md) based on domain layer return." +"pass it to [domain layer](../../cookbook/organizing-code/domain.md) in a " +"suitable format, and create [a response](../runtime/response.md) based on " +"domain layer return." msgstr "" #. type: Plain text -#: ../src/en/guide/structure/overview.md +#: ../src/guide/structure/overview.md msgid "Besides, Yii applications also have the following:" msgstr "" #. type: Bullet: '* ' -#: ../src/en/guide/structure/overview.md +#: ../src/guide/structure/overview.md msgid "" "[entry scripts](entry-script.md): they're PHP scripts that are directly " "accessible by end users. They're responsible for starting a request " @@ -166,14 +166,15 @@ msgid "" msgstr "" #. type: Bullet: '* ' -#: ../src/en/guide/structure/overview.md +#: ../src/guide/structure/overview.md msgid "" -"[services](service.md): they're typically stateless objects registered " -"within dependency container and provide various action methods." +"[services](../../cookbook/organizing-code/service.md): they're typically " +"stateless objects registered within dependency container and provide various " +"action methods." msgstr "" #. type: Bullet: '* ' -#: ../src/en/guide/structure/overview.md +#: ../src/guide/structure/overview.md msgid "" "[middleware](middleware.md): they represent a code that needs to be invoked " "before and after the actual handling of each request by action handlers." diff --git a/_translations/pot/internals_014-docs.md.pot b/_translations/pot/internals_014-docs.md.pot index b46c2ade..eff7fb85 100644 --- a/_translations/pot/internals_014-docs.md.pot +++ b/_translations/pot/internals_014-docs.md.pot @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2026-05-05 22:22+0000\n" +"POT-Creation-Date: 2026-10-23 18:03+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -75,7 +75,7 @@ msgstr "" #: ../src/internals/014-docs.md msgid "" "The definitive guide, [yiisoft/docs/guide](https://github.com/yiisoft/docs/" -"tree/master/guide/en) aims at covering usage of packages as a whole " +"tree/master/src/guide) aims at covering usage of packages as a whole " "framework. Unlike package documentation, it isn't focused on a single " "package but is covering certain use-cases." msgstr "" diff --git a/src/.vitepress/config.js b/src/.vitepress/config.js index 056dc216..f80cfd26 100644 --- a/src/.vitepress/config.js +++ b/src/.vitepress/config.js @@ -1320,6 +1320,291 @@ export default { } } } + }, + 'pt-BR': { + title: 'Documentação do Yii3', + label: 'Português (Brasil)', + lang: 'pt-BR', + link: '/pt-BR/', + themeConfig: { + nav: [ + {text: 'Guia', link: '/pt-BR/guide/'}, + {text: 'Cookbook', link: '/pt-BR/cookbook/'}, + {text: 'Detalhes internos', link: '/pt-BR/internals/'}, + {text: 'Site', link: 'https://www.yiiframework.com'} + ], + sidebar: { + '/pt-BR/guide/': [ + { + text: 'Introdução', + items: [ + {text: 'Sobre o Yii', link: '/pt-BR/guide/intro/what-is-yii'}, + {text: 'Migrando da versão 1.1', link: '/pt-BR/guide/intro/upgrade-from-v1'}, + {text: 'Migrando da versão 2.0', link: '/pt-BR/guide/intro/upgrade-from-v2'} + ] + }, + { + text: 'Primeiros passos', + items: [ + {text: 'O que você precisa saber', link: '/pt-BR/guide/start/prerequisites'}, + {text: 'Criando um projeto', link: '/pt-BR/guide/start/creating-project'}, + {text: 'Fluxo da aplicação', link: '/pt-BR/guide/start/workflow'}, + {text: 'Dizendo olá', link: '/pt-BR/guide/start/hello'}, + {text: 'Trabalhando com formulários', link: '/pt-BR/guide/start/forms'}, + {text: 'Trabalhando com bancos de dados', link: '/pt-BR/guide/start/databases'}, + {text: 'Gerando código com o Gii', link: '/pt-BR/guide/start/gii'}, + {text: 'Seguindo em frente', link: '/pt-BR/guide/start/looking-ahead'}, + {text: 'Aplicações de demonstração', link: '/pt-BR/guide/start/demo-apps'} + ] + }, + { + text: 'Conceitos principais', + items: [ + {text: 'Aliases', link: '/pt-BR/guide/concept/aliases'}, + {text: 'Autoload', link: '/pt-BR/guide/concept/autoloading'}, + {text: 'Configuração', link: '/pt-BR/guide/concept/configuration'}, + {text: 'Container de DI', link: '/pt-BR/guide/concept/di-container'}, + {text: 'Eventos', link: '/pt-BR/guide/concept/events'}, + {text: 'Imutabilidade', link: '/pt-BR/guide/concept/immutability'} + ] + }, + { + text: 'Estrutura da aplicação', + items: [ + {text: 'Visão geral', link: '/pt-BR/guide/structure/overview'}, + {text: 'Script de entrada', link: '/pt-BR/guide/structure/entry-script'}, + {text: 'Aplicação', link: '/pt-BR/guide/structure/application'}, + {text: 'Módulo', link: '/pt-BR/guide/structure/module'}, + {text: 'Action', link: '/pt-BR/guide/structure/action'}, + {text: 'Middleware', link: '/pt-BR/guide/structure/middleware'} + ] + }, + { + text: 'Pacotes', + items: [ + {text: 'Usando pacotes', link: '/pt-BR/guide/structure/package'}, + {text: 'Projetando pacotes', link: '/pt-BR/guide/structure/designing-packages'} + ] + }, + { + text: 'Tratando requisições', + items: [ + {text: 'Roteamento', link: '/pt-BR/guide/runtime/routing'}, + {text: 'Requisição', link: '/pt-BR/guide/runtime/request'}, + {text: 'Resposta', link: '/pt-BR/guide/runtime/response'}, + {text: 'Sessões', link: '/pt-BR/guide/runtime/sessions'}, + {text: 'Cookies', link: '/pt-BR/guide/runtime/cookies'}, + {text: 'Tratamento de erros', link: '/pt-BR/guide/runtime/handling-errors'}, + {text: 'Logs', link: '/pt-BR/guide/runtime/logging'} + ] + }, + { + text: 'APIs REST', + items: [ + {text: 'Início rápido', link: '/pt-BR/guide/rest/quick-start'} + ] + }, + { + text: 'Segurança', + items: [ + {text: 'Visão geral', link: '/pt-BR/guide/security/overview'}, + {text: 'Autenticação', link: '/pt-BR/guide/security/authentication'}, + {text: 'Autorização', link: '/pt-BR/guide/security/authorization'}, + {text: 'Trabalhando com senhas', link: '/pt-BR/guide/security/passwords'}, + {text: 'Criptografia', link: '/pt-BR/guide/security/cryptography'}, + {text: 'Requisição confiável', link: '/pt-BR/guide/security/trusted-request'}, + {text: 'Boas práticas', link: '/pt-BR/guide/security/best-practices'} + ] + }, + { + text: 'Cache', + items: [ + {text: 'Visão geral', link: '/pt-BR/guide/caching/overview'}, + {text: 'Cache de dados', link: '/pt-BR/guide/caching/data'} + ] + }, + { + text: 'Trabalhando com bancos de dados', + items: [ + {text: 'Yii DB', link: 'https://github.com/yiisoft/db/blob/master/docs/guide/en/README.md'}, + {text: 'Active Record', link: 'https://github.com/yiisoft/active-record/blob/master/README.md'}, + {text: 'Migrations de banco de dados', link: '/pt-BR/guide/databases/db-migrations'} + ] + }, + { + text: 'Views', + items: [ + {text: 'Views', link: '/pt-BR/guide/views/view'}, + {text: 'Assets', link: '/pt-BR/guide/views/asset'}, + {text: 'Scripts, estilos e meta tags', link: '/pt-BR/guide/views/script-style-meta'}, + {text: 'Template engines', link: '/pt-BR/guide/views/template-engines'}, + {text: 'Injeções de view', link: '/pt-BR/guide/views/view-injections'}, + {text: 'Widgets', link: '/pt-BR/guide/views/widget'} + ] + }, + { + text: 'Testes', + items: [ + {text: 'Visão geral de testes', link: '/pt-BR/guide/testing/overview'}, + {text: 'Configurando o ambiente de testes', link: '/pt-BR/guide/testing/environment-setup'}, + {text: 'Testes unitários', link: '/pt-BR/guide/testing/unit'}, + {text: 'Testes funcionais', link: '/pt-BR/guide/testing/functional'}, + {text: 'Testes end-to-end', link: '/pt-BR/guide/testing/end-to-end'}, + {text: 'Análise estática e testes de mutação', link: '/pt-BR/guide/testing/quality-tools'} + ] + }, + { + text: 'Tutorial', + items: [ + {text: 'Aplicações de console', link: '/pt-BR/guide/tutorial/console-applications'}, + {text: 'Envio de e-mails', link: '/pt-BR/guide/tutorial/mailing'}, + {text: 'Ajuste de desempenho', link: '/pt-BR/guide/tutorial/performance-tuning'}, + {text: 'Usando com event loop', link: '/pt-BR/guide/tutorial/using-with-event-loop'}, + {text: 'Usando o Yii com FrankenPHP', link: '/pt-BR/guide/tutorial/using-yii-with-frankenphp'}, + {text: 'Usando o Yii com Rapira', link: '/pt-BR/guide/tutorial/using-yii-with-rapira'}, + {text: 'Usando o Yii com RoadRunner', link: '/pt-BR/guide/tutorial/using-yii-with-roadrunner'}, + {text: 'Usando o Yii com Swoole', link: '/pt-BR/guide/tutorial/using-yii-with-swoole'}, + {text: 'Docker nos templates de aplicação', link: '/pt-BR/guide/tutorial/docker'}, + {text: 'Internacionalização', link: '/pt-BR/guide/tutorial/i18n'} + ] + }, + { + text: 'Helpers', + items: [ + {text: 'Arrays', link: 'https://github.com/yiisoft/arrays/'}, + {text: 'Arquivos', link: 'https://github.com/yiisoft/files/'}, + {text: 'Html', link: 'https://github.com/yiisoft/html/'}, + {text: 'Json', link: 'https://github.com/yiisoft/json'}, + {text: 'Utilitários de rede', link: 'https://github.com/yiisoft/network-utilities/'}, + {text: 'VarDumper', link: 'https://github.com/yiisoft/var-dumper'}, + {text: 'Strings', link: 'https://github.com/yiisoft/strings'} + ] + }, + { + text: 'Glossário', + link: '/pt-BR/guide/glossary' + } + ], + '/pt-BR/cookbook/': [ + { + text: 'Cookbook', + items: [ + {text: 'Prefácio', link: '/pt-BR/cookbook/preface'}, + {text: 'Fazendo requisições HTTP', link: '/pt-BR/cookbook/making-http-requests'}, + {text: 'Usando htmx para recarregar partes da página', link: '/pt-BR/cookbook/using-htmx-for-partial-reloads'}, + {text: 'Desativando a proteção CSRF', link: '/pt-BR/cookbook/disabling-csrf-protection'}, + {text: 'Integração com o Sentry', link: '/pt-BR/cookbook/sentry-integration'}, + {text: 'Usando um template de migration personalizado', link: '/pt-BR/cookbook/custom-migration-template'}, + {text: 'Type casters personalizados para o hydrator', link: '/pt-BR/cookbook/custom-hydrator-type-casters'}, + {text: 'Usando o Yii em aplicações de terceiros', link: '/pt-BR/cookbook/using-yii-in-third-party-apps'}, + {text: 'Integrações com terceiros', link: '/pt-BR/cookbook/third-party-integrations/'} + ] + }, + { + text: 'Ambiente de desenvolvimento', + collapsed: false, + items: [ + {text: 'Trabalhando no Windows', link: '/pt-BR/cookbook/working-on-windows'}, + {text: 'Abrindo arquivos no PhpStorm', link: '/pt-BR/cookbook/opening-files-in-phpstorm'}, + {text: 'Configurando o Xdebug', link: '/pt-BR/cookbook/configuring-xdebug'} + ] + }, + { + text: 'Configurando servidores web', + collapsed: false, + items: [ + {text: 'Geral', link: '/pt-BR/cookbook/configuring-webservers/general'}, + {text: 'Apache', link: '/pt-BR/cookbook/configuring-webservers/apache'}, + {text: 'Nginx', link: '/pt-BR/cookbook/configuring-webservers/nginx'}, + {text: 'Nginx Unit', link: '/pt-BR/cookbook/configuring-webservers/nginx-unit'}, + {text: 'IIS', link: '/pt-BR/cookbook/configuring-webservers/iis'}, + {text: 'Lighttpd', link: '/pt-BR/cookbook/configuring-webservers/lighttpd'} + ] + }, + { + text: 'Organizando o código', + items: [ + {text: 'Vertical slices', link: '/pt-BR/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices'}, + {text: 'Domínio', link: '/pt-BR/cookbook/organizing-code/domain'}, + {text: 'Serviço', link: '/pt-BR/cookbook/organizing-code/service'} + ] + }, + { + text: 'Deploy', + items: [ + {text: 'Docker Swarm', link: '/pt-BR/cookbook/deployment/docker-swarm'}, + {text: 'Angie Docker Proxy', link: '/pt-BR/cookbook/deployment/angie-docker-proxy'}, + {text: 'Autoscaling', link: '/pt-BR/cookbook/deployment/autoscaling'}, + {text: 'Migrations em rolling updates', link: '/pt-BR/cookbook/deployment/rolling-update-migrations'} + ] + } + ], + '/pt-BR/internals/': [ + { + text: 'Detalhes internos', + items: [ + {text: 'Pacotes', link: '/pt-BR/internals/000-packages'}, + {text: 'Valores do Yii', link: '/pt-BR/internals/001-yii-values'}, + {text: 'Fluxo de issues', link: '/pt-BR/internals/002-issue-workflow'}, + {text: 'Roadmap', link: '/pt-BR/internals/003-roadmap'}, + {text: 'Namespaces', link: '/pt-BR/internals/004-namespaces'}, + {text: 'Ferramenta de desenvolvimento', link: '/pt-BR/internals/005-development-tool'}, + {text: 'Mensagens de commit no Git', link: '/pt-BR/internals/006-git-commit-messages'}, + {text: 'Exceções', link: '/pt-BR/internals/007-exceptions'}, + {text: 'Interfaces', link: '/pt-BR/internals/008-interfaces'}, + {text: 'Decisões de design', link: '/pt-BR/internals/009-design-decisions'}, + {text: 'Estilo de código', link: '/pt-BR/internals/010-code-style'}, + {text: 'Correção de erros', link: '/pt-BR/internals/011-error-correction'}, + {text: 'Testes', link: '/pt-BR/internals/012-tests'}, + {text: 'Code review', link: '/pt-BR/internals/013-code-review'}, + {text: 'Documentação', link: '/pt-BR/internals/014-docs'}, + {text: 'PHPStorm', link: '/pt-BR/internals/015-phpstorm'}, + {text: 'Fluxo de segurança', link: '/pt-BR/internals/016-security-workflow'}, + {text: 'Tags', link: '/pt-BR/internals/017-tags'}, + {text: 'Widgets', link: '/pt-BR/internals/018-widgets'}, + {text: 'Estilo de código de views', link: '/pt-BR/internals/019-view-code-style'}, + {text: 'Release de pacotes', link: '/pt-BR/internals/020-package-release'}, + {text: 'Changelog e upgrade', link: '/pt-BR/internals/021-changelog-upgrade'}, + {text: 'Grupos de configuração', link: '/pt-BR/internals/022-config-groups'}, + {text: 'GitHub Actions', link: '/pt-BR/internals/023-github-actions'} + ] + } + ] + }, + footer: { + message: 'Publicado sob a Licença BSD-3-Clause.', + copyright: `Copyright © 2008-${currentYear} Yii` + }, + docFooter: { + prev: 'Página anterior', + next: 'Próxima página', + }, + outline: { + label: 'Nesta página' + }, + lastUpdated: { + text: 'Atualizado em' + }, + search: { + options: { + translations: { + button: { + buttonText: 'Pesquisar', + buttonAriaLabel: 'Pesquisar' + }, + modal: { + noResultsText: 'Nenhum resultado para', + resetButtonTitle: 'Limpar pesquisa', + footer: { + selectText: 'selecionar', + navigateText: 'navegar', + closeText: 'fechar' + } + } + } + } + } + } } } } diff --git a/src/cookbook/organizing-code/service.md b/src/cookbook/organizing-code/service.md index 725393c6..ddfe25c2 100644 --- a/src/cookbook/organizing-code/service.md +++ b/src/cookbook/organizing-code/service.md @@ -105,5 +105,5 @@ Often it makes sense to choose another class type to place your code into. Check - Repository - Widget -- [Middleware](middleware.md) +- [Middleware](../../guide/structure/middleware.md) - Entity diff --git a/src/es/cookbook/organizing-code/service.md b/src/es/cookbook/organizing-code/service.md index 0baee5d5..98a99d1d 100644 --- a/src/es/cookbook/organizing-code/service.md +++ b/src/es/cookbook/organizing-code/service.md @@ -115,5 +115,5 @@ into. Check: - Repository - Widget -- [Middleware](middleware.md) +- [Middleware](../../guide/structure/middleware.md) - Entity diff --git a/src/es/guide/caching/data.md b/src/es/guide/caching/data.md index 0b7d1a62..86d7aee1 100644 --- a/src/es/guide/caching/data.md +++ b/src/es/guide/caching/data.md @@ -2,7 +2,7 @@ Data caching is about storing some PHP variables in a cache and retrieving them later from the cache. It's also the foundation for more advanced -caching features, such as [page caching](page.md). +caching features, such as page caching. To use cache, install [yiisoft/cache](https://github.com/yiisoft/cache) package: @@ -54,7 +54,7 @@ Yii provides the following handlers: - `ArrayCache` — provides caching for the current request only by storing the values in an array. - [APCu](https://github.com/yiisoft/cache-apcu) - uses a PHP - [APC](https://secure.php.net/manual/en/book.apc.php) extension. You can + [APC](https://www.php.net/manual/en/book.apcu.php) extension. You can consider this option as the fastest one when dealing with cache for a centralized thick application (e.g., one server, no dedicated load balancers, etc.). diff --git a/src/es/guide/caching/overview.md b/src/es/guide/caching/overview.md index 2e2d4845..bf15f442 100644 --- a/src/es/guide/caching/overview.md +++ b/src/es/guide/caching/overview.md @@ -16,6 +16,6 @@ content in the browser cache. Yii supports all these caching mechanisms: * [Data caching](data.md) -* [Fragment caching](fragment.md) -* [Page caching](page.md) -* [HTTP caching](http.md) +* Fragment caching +* Page caching +* HTTP caching diff --git a/src/es/guide/glossary.md b/src/es/guide/glossary.md index bbf357a0..da4a6971 100644 --- a/src/es/guide/glossary.md +++ b/src/es/guide/glossary.md @@ -213,7 +213,7 @@ does the actual processing. Service is a focused object that performs application work or provides infrastructure behavior and is usually stored in the DI container. Read -more in ["Service components"](structure/service.md). +more in ["Service components"](../cookbook/organizing-code/service.md). ## service provider diff --git a/src/es/guide/security/best-practices.md b/src/es/guide/security/best-practices.md index 6f21dcaa..fc558947 100644 --- a/src/es/guide/security/best-practices.md +++ b/src/es/guide/security/best-practices.md @@ -121,8 +121,8 @@ If all you need is plain text, then escaping is as easy as the following: ``` If it should be HTML, you could get some help from -[HtmlPurifier](http://htmlpurifier.org/). Note that HtmlPurifier processing -is quite heavy, so consider adding caching. +[HtmlPurifier](https://github.com/ezyang/htmlpurifier). Note that +HtmlPurifier processing is quite heavy, so consider adding caching. Further reading on the topic: @@ -202,8 +202,8 @@ need it, check twice you restrict access to your IP only. Further reading on the topic: -- -- +- +- ## Using secure connection over TLS diff --git a/src/es/guide/start/hello.md b/src/es/guide/start/hello.md index d3e506e5..08eaf058 100644 --- a/src/es/guide/start/hello.md +++ b/src/es/guide/start/hello.md @@ -5,7 +5,7 @@ application. It's a simple page that will echo back whatever you pass to it or, if nothing passed, will just say "Hello!". To achieve this goal, you will define a route and create [a -handler](../structure/handler.md) that does the job and forms the response. +handler](../structure/action.md) that does the job and forms the response. Then you will improve it to use [view](../views/view.md) for building the response. diff --git a/src/es/guide/structure/overview.md b/src/es/guide/structure/overview.md index 3d8f5d9d..19195461 100644 --- a/src/es/guide/structure/overview.md +++ b/src/es/guide/structure/overview.md @@ -48,9 +48,9 @@ contexts, it's moved to the ancestor of both contexts. A context may have [an entry point known as "action" or "controller"](action.md). Its job is to take [a request -instance](../runtime/request.md), pass it to [domain layer](domain.md) in a -suitable format, and create [a response](../runtime/response.md) based on -domain layer return. +instance](../runtime/request.md), pass it to [domain +layer](../../cookbook/organizing-code/domain.md) in a suitable format, and +create [a response](../runtime/response.md) based on domain layer return. Besides, Yii applications also have the following: @@ -58,8 +58,9 @@ Besides, Yii applications also have the following: accessible by end users. They're responsible for starting a request handling cycle. Typically, a single entry script is handling the whole application. -* [services](service.md): they're typically stateless objects registered - within dependency container and provide various action methods. +* [services](../../cookbook/organizing-code/service.md): they're typically + stateless objects registered within dependency container and provide + various action methods. * [middleware](middleware.md): they represent a code that needs to be invoked before and after the actual handling of each request by action handlers. diff --git a/src/es/internals/014-docs.md b/src/es/internals/014-docs.md index 76c3ea24..88b83b32 100644 --- a/src/es/internals/014-docs.md +++ b/src/es/internals/014-docs.md @@ -21,7 +21,7 @@ keep documentation in the readme. ## Definitive guide The definitive guide, -[yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/guide/en) +[yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/src/guide) aims at covering usage of packages as a whole framework. Unlike package documentation, it isn't focused on a single package but is covering certain use-cases. diff --git a/src/guide/caching/data.md b/src/guide/caching/data.md index d8cede02..eecc5629 100644 --- a/src/guide/caching/data.md +++ b/src/guide/caching/data.md @@ -1,7 +1,7 @@ # Data caching Data caching is about storing some PHP variables in a cache and retrieving them later from the cache. -It's also the foundation for more advanced caching features, such as [page caching](page.md). +It's also the foundation for more advanced caching features, such as page caching. To use cache, install [yiisoft/cache](https://github.com/yiisoft/cache) package: @@ -45,7 +45,7 @@ Yii provides the following handlers: When you enable actual cache support, you can switch to using the corresponding cache handler. In both cases, you may use the same code without extra checks. - `ArrayCache` — provides caching for the current request only by storing the values in an array. -- [APCu](https://github.com/yiisoft/cache-apcu) - uses a PHP [APC](https://secure.php.net/manual/en/book.apc.php) extension. +- [APCu](https://github.com/yiisoft/cache-apcu) - uses a PHP [APC](https://www.php.net/manual/en/book.apcu.php) extension. You can consider this option as the fastest one when dealing with cache for a centralized thick application (e.g., one server, no dedicated load balancers, etc.). - [Database](https://github.com/yiisoft/cache-db) — uses a database table to store cached data. diff --git a/src/guide/caching/overview.md b/src/guide/caching/overview.md index f29003ba..c8a9c260 100644 --- a/src/guide/caching/overview.md +++ b/src/guide/caching/overview.md @@ -13,6 +13,6 @@ the browser cache. Yii supports all these caching mechanisms: * [Data caching](data.md) -* [Fragment caching](fragment.md) -* [Page caching](page.md) -* [HTTP caching](http.md) +* Fragment caching +* Page caching +* HTTP caching diff --git a/src/guide/glossary.md b/src/guide/glossary.md index db8a8084..dea668f0 100644 --- a/src/guide/glossary.md +++ b/src/guide/glossary.md @@ -196,7 +196,7 @@ It holds a set of parameters for checking if a data set is valid. Service is a focused object that performs application work or provides infrastructure behavior and is usually stored in the DI container. -Read more in ["Service components"](structure/service.md). +Read more in ["Service components"](../cookbook/organizing-code/service.md). ## service provider diff --git a/src/guide/security/best-practices.md b/src/guide/security/best-practices.md index 46ea87c6..3711cdf0 100644 --- a/src/guide/security/best-practices.md +++ b/src/guide/security/best-practices.md @@ -112,7 +112,7 @@ If all you need is plain text, then escaping is as easy as the following: ``` -If it should be HTML, you could get some help from [HtmlPurifier](http://htmlpurifier.org/). +If it should be HTML, you could get some help from [HtmlPurifier](https://github.com/ezyang/htmlpurifier). Note that HtmlPurifier processing is quite heavy, so consider adding caching. Further reading on the topic: @@ -186,8 +186,8 @@ If you absolutely need it, check twice you restrict access to your IP only. Further reading on the topic: -- -- +- +- ## Using secure connection over TLS diff --git a/src/guide/start/hello.md b/src/guide/start/hello.md index 63a96813..163f435e 100644 --- a/src/guide/start/hello.md +++ b/src/guide/start/hello.md @@ -3,7 +3,7 @@ This section describes how to create a new "Hello" page in your application. It's a simple page that will echo back whatever you pass to it or, if nothing passed, will just say "Hello!". -To achieve this goal, you will define a route and create [a handler](../structure/handler.md) that does the job and +To achieve this goal, you will define a route and create [a handler](../structure/action.md) that does the job and forms the response. Then you will improve it to use [view](../views/view.md) for building the response. diff --git a/src/guide/structure/overview.md b/src/guide/structure/overview.md index 12f08b22..6a367f67 100644 --- a/src/guide/structure/overview.md +++ b/src/guide/structure/overview.md @@ -45,7 +45,7 @@ A context may include sub-contexts. If a class is shared by multiple contexts, i both contexts. A context may have [an entry point known as "action" or "controller"](action.md). Its job is to take [a request -instance](../runtime/request.md), pass it to [domain layer](domain.md) in a suitable format, and create +instance](../runtime/request.md), pass it to [domain layer](../../cookbook/organizing-code/domain.md) in a suitable format, and create [a response](../runtime/response.md) based on domain layer return. Besides, Yii applications also have the following: @@ -53,7 +53,7 @@ Besides, Yii applications also have the following: * [entry scripts](entry-script.md): they're PHP scripts that are directly accessible by end users. They're responsible for starting a request handling cycle. Typically, a single entry script is handling the whole application. -* [services](service.md): they're typically stateless objects registered within dependency container and +* [services](../../cookbook/organizing-code/service.md): they're typically stateless objects registered within dependency container and provide various action methods. * [middleware](middleware.md): they represent a code that needs to be invoked before and after the actual handling of each request by action handlers. diff --git a/src/id/cookbook/organizing-code/service.md b/src/id/cookbook/organizing-code/service.md index 0baee5d5..98a99d1d 100644 --- a/src/id/cookbook/organizing-code/service.md +++ b/src/id/cookbook/organizing-code/service.md @@ -115,5 +115,5 @@ into. Check: - Repository - Widget -- [Middleware](middleware.md) +- [Middleware](../../guide/structure/middleware.md) - Entity diff --git a/src/id/guide/caching/data.md b/src/id/guide/caching/data.md index 87208252..99315768 100644 --- a/src/id/guide/caching/data.md +++ b/src/id/guide/caching/data.md @@ -3,7 +3,7 @@ Caching data adalah tentang menyimpan beberapa variabel PHP ke dalam cache dan mengambilnya kembali dari cache. Ini juga menjadi fondasi untuk fitur caching yang lebih lanjut, seperti -[caching halaman](page.md). +caching halaman. Untuk menggunakan cache, pasang paket [yiisoft/cache](https://github.com/yiisoft/cache): @@ -61,7 +61,7 @@ Yii menyediakan handler berikut: - `ArrayCache` — menyediakan caching hanya untuk permintaan saat ini dengan menyimpan nilai dalam sebuah array. - [APCu](https://github.com/yiisoft/cache-apcu) — menggunakan ekstensi PHP - [APC](https://secure.php.net/manual/en/book.apc.php). + [APC](https://www.php.net/manual/en/book.apcu.php). Ini bisa dianggap sebagai opsi tercepat saat berurusan dengan cache untuk aplikasi terpusat (mis., satu server, tanpa load balancer khusus, dll.). diff --git a/src/id/guide/caching/overview.md b/src/id/guide/caching/overview.md index c688cfba..6bd83331 100644 --- a/src/id/guide/caching/overview.md +++ b/src/id/guide/caching/overview.md @@ -20,6 +20,6 @@ di cache browser. Yii mendukung semua mekanisme caching berikut: * [Data caching](data.md) -* [Fragment caching](fragment.md) -* [Page caching](page.md) -* [HTTP caching](http.md) +* Fragment caching +* Page caching +* HTTP caching diff --git a/src/id/guide/glossary.md b/src/id/guide/glossary.md index bbf357a0..da4a6971 100644 --- a/src/id/guide/glossary.md +++ b/src/id/guide/glossary.md @@ -213,7 +213,7 @@ does the actual processing. Service is a focused object that performs application work or provides infrastructure behavior and is usually stored in the DI container. Read -more in ["Service components"](structure/service.md). +more in ["Service components"](../cookbook/organizing-code/service.md). ## service provider diff --git a/src/id/guide/security/best-practices.md b/src/id/guide/security/best-practices.md index cf194718..7b469c44 100644 --- a/src/id/guide/security/best-practices.md +++ b/src/id/guide/security/best-practices.md @@ -121,8 +121,8 @@ If all you need is plain text, then escaping is as easy as the following: ``` If it should be HTML, you could get some help from -[HtmlPurifier](http://htmlpurifier.org/). Note that HtmlPurifier processing -is quite heavy, so consider adding caching. +[HtmlPurifier](https://github.com/ezyang/htmlpurifier). Note that +HtmlPurifier processing is quite heavy, so consider adding caching. Further reading on the topic: @@ -202,8 +202,8 @@ need it, check twice you restrict access to your IP only. Further reading on the topic: -- -- +- +- ## Using secure connection over TLS diff --git a/src/id/guide/start/hello.md b/src/id/guide/start/hello.md index d3e506e5..08eaf058 100644 --- a/src/id/guide/start/hello.md +++ b/src/id/guide/start/hello.md @@ -5,7 +5,7 @@ application. It's a simple page that will echo back whatever you pass to it or, if nothing passed, will just say "Hello!". To achieve this goal, you will define a route and create [a -handler](../structure/handler.md) that does the job and forms the response. +handler](../structure/action.md) that does the job and forms the response. Then you will improve it to use [view](../views/view.md) for building the response. diff --git a/src/id/guide/structure/overview.md b/src/id/guide/structure/overview.md index 3d8f5d9d..19195461 100644 --- a/src/id/guide/structure/overview.md +++ b/src/id/guide/structure/overview.md @@ -48,9 +48,9 @@ contexts, it's moved to the ancestor of both contexts. A context may have [an entry point known as "action" or "controller"](action.md). Its job is to take [a request -instance](../runtime/request.md), pass it to [domain layer](domain.md) in a -suitable format, and create [a response](../runtime/response.md) based on -domain layer return. +instance](../runtime/request.md), pass it to [domain +layer](../../cookbook/organizing-code/domain.md) in a suitable format, and +create [a response](../runtime/response.md) based on domain layer return. Besides, Yii applications also have the following: @@ -58,8 +58,9 @@ Besides, Yii applications also have the following: accessible by end users. They're responsible for starting a request handling cycle. Typically, a single entry script is handling the whole application. -* [services](service.md): they're typically stateless objects registered - within dependency container and provide various action methods. +* [services](../../cookbook/organizing-code/service.md): they're typically + stateless objects registered within dependency container and provide + various action methods. * [middleware](middleware.md): they represent a code that needs to be invoked before and after the actual handling of each request by action handlers. diff --git a/src/id/internals/014-docs.md b/src/id/internals/014-docs.md index 76c3ea24..88b83b32 100644 --- a/src/id/internals/014-docs.md +++ b/src/id/internals/014-docs.md @@ -21,7 +21,7 @@ keep documentation in the readme. ## Definitive guide The definitive guide, -[yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/guide/en) +[yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/src/guide) aims at covering usage of packages as a whole framework. Unlike package documentation, it isn't focused on a single package but is covering certain use-cases. diff --git a/src/internals/014-docs.md b/src/internals/014-docs.md index 67e25716..b81d8747 100644 --- a/src/internals/014-docs.md +++ b/src/internals/014-docs.md @@ -17,7 +17,7 @@ If the total length of readme is less than about 200 lines, it's fine to keep do ## Definitive guide -The definitive guide, [yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/guide/en) +The definitive guide, [yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/src/guide) aims at covering usage of packages as a whole framework. Unlike package documentation, it isn't focused on a single package but is covering certain use-cases. diff --git a/src/it/cookbook/organizing-code/service.md b/src/it/cookbook/organizing-code/service.md index 0baee5d5..98a99d1d 100644 --- a/src/it/cookbook/organizing-code/service.md +++ b/src/it/cookbook/organizing-code/service.md @@ -115,5 +115,5 @@ into. Check: - Repository - Widget -- [Middleware](middleware.md) +- [Middleware](../../guide/structure/middleware.md) - Entity diff --git a/src/it/guide/caching/data.md b/src/it/guide/caching/data.md index 0b7d1a62..86d7aee1 100644 --- a/src/it/guide/caching/data.md +++ b/src/it/guide/caching/data.md @@ -2,7 +2,7 @@ Data caching is about storing some PHP variables in a cache and retrieving them later from the cache. It's also the foundation for more advanced -caching features, such as [page caching](page.md). +caching features, such as page caching. To use cache, install [yiisoft/cache](https://github.com/yiisoft/cache) package: @@ -54,7 +54,7 @@ Yii provides the following handlers: - `ArrayCache` — provides caching for the current request only by storing the values in an array. - [APCu](https://github.com/yiisoft/cache-apcu) - uses a PHP - [APC](https://secure.php.net/manual/en/book.apc.php) extension. You can + [APC](https://www.php.net/manual/en/book.apcu.php) extension. You can consider this option as the fastest one when dealing with cache for a centralized thick application (e.g., one server, no dedicated load balancers, etc.). diff --git a/src/it/guide/caching/overview.md b/src/it/guide/caching/overview.md index 2e2d4845..bf15f442 100644 --- a/src/it/guide/caching/overview.md +++ b/src/it/guide/caching/overview.md @@ -16,6 +16,6 @@ content in the browser cache. Yii supports all these caching mechanisms: * [Data caching](data.md) -* [Fragment caching](fragment.md) -* [Page caching](page.md) -* [HTTP caching](http.md) +* Fragment caching +* Page caching +* HTTP caching diff --git a/src/it/guide/glossary.md b/src/it/guide/glossary.md index bbf357a0..da4a6971 100644 --- a/src/it/guide/glossary.md +++ b/src/it/guide/glossary.md @@ -213,7 +213,7 @@ does the actual processing. Service is a focused object that performs application work or provides infrastructure behavior and is usually stored in the DI container. Read -more in ["Service components"](structure/service.md). +more in ["Service components"](../cookbook/organizing-code/service.md). ## service provider diff --git a/src/it/guide/security/best-practices.md b/src/it/guide/security/best-practices.md index 32ae9410..7be3f38b 100644 --- a/src/it/guide/security/best-practices.md +++ b/src/it/guide/security/best-practices.md @@ -121,8 +121,8 @@ If all you need is plain text, then escaping is as easy as the following: ``` If it should be HTML, you could get some help from -[HtmlPurifier](http://htmlpurifier.org/). Note that HtmlPurifier processing -is quite heavy, so consider adding caching. +[HtmlPurifier](https://github.com/ezyang/htmlpurifier). Note that +HtmlPurifier processing is quite heavy, so consider adding caching. Further reading on the topic: @@ -202,8 +202,8 @@ need it, check twice you restrict access to your IP only. Further reading on the topic: -- -- +- +- ## Using secure connection over TLS diff --git a/src/it/guide/start/hello.md b/src/it/guide/start/hello.md index f4bba8d2..075434ef 100644 --- a/src/it/guide/start/hello.md +++ b/src/it/guide/start/hello.md @@ -5,7 +5,7 @@ applicazione. È una pagina semplice che restituirà tutto ciò che le passi o, se non viene passato nulla, dirà semplicemente "Hello!". Per raggiungere questo obiettivo, definirai una rotta e creerai [un gestore -di richieste](../structure/handler.md) che esegue il lavoro e forma la +di richieste](../structure/action.md) che esegue il lavoro e forma la risposta. Poi lo migliorerai per usare [una vista](../views/view.md) per costruire la risposta. diff --git a/src/it/guide/structure/overview.md b/src/it/guide/structure/overview.md index 3d8f5d9d..19195461 100644 --- a/src/it/guide/structure/overview.md +++ b/src/it/guide/structure/overview.md @@ -48,9 +48,9 @@ contexts, it's moved to the ancestor of both contexts. A context may have [an entry point known as "action" or "controller"](action.md). Its job is to take [a request -instance](../runtime/request.md), pass it to [domain layer](domain.md) in a -suitable format, and create [a response](../runtime/response.md) based on -domain layer return. +instance](../runtime/request.md), pass it to [domain +layer](../../cookbook/organizing-code/domain.md) in a suitable format, and +create [a response](../runtime/response.md) based on domain layer return. Besides, Yii applications also have the following: @@ -58,8 +58,9 @@ Besides, Yii applications also have the following: accessible by end users. They're responsible for starting a request handling cycle. Typically, a single entry script is handling the whole application. -* [services](service.md): they're typically stateless objects registered - within dependency container and provide various action methods. +* [services](../../cookbook/organizing-code/service.md): they're typically + stateless objects registered within dependency container and provide + various action methods. * [middleware](middleware.md): they represent a code that needs to be invoked before and after the actual handling of each request by action handlers. diff --git a/src/it/internals/014-docs.md b/src/it/internals/014-docs.md index 76c3ea24..88b83b32 100644 --- a/src/it/internals/014-docs.md +++ b/src/it/internals/014-docs.md @@ -21,7 +21,7 @@ keep documentation in the readme. ## Definitive guide The definitive guide, -[yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/guide/en) +[yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/src/guide) aims at covering usage of packages as a whole framework. Unlike package documentation, it isn't focused on a single package but is covering certain use-cases. diff --git a/src/pt-BR/cookbook/configuring-webservers/apache.md b/src/pt-BR/cookbook/configuring-webservers/apache.md new file mode 100644 index 00000000..d1a0a30b --- /dev/null +++ b/src/pt-BR/cookbook/configuring-webservers/apache.md @@ -0,0 +1,60 @@ +# Configurando servidores web: Apache + +Use a configuração a seguir no arquivo `httpd.conf` do Apache ou na +configuração de um virtual host. Substitua `path/to/app/public` pelo caminho +real de `app/public`. + +```apache +# Define o document root como "app/public" +DocumentRoot "path/to/app/public" + + + # usa mod_rewrite para suportar URLs amigáveis + RewriteEngine on + + # Não permite acesso a URLs com o nome do script + RewriteCond %{THE_REQUEST} index.php [NC] + RewriteRule . - [R=404,L] + + # Se um diretório ou arquivo existir, usa a requisição diretamente + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_FILENAME} !-d + + # Caso contrário, encaminha a requisição para index.php + RewriteRule . index.php + + SetEnv APP_ENV dev + + # ...outras configurações... + +``` + +Se você tiver `AllowOverride All`, pode adicionar um arquivo `.htaccess` com +a configuração a seguir em vez de usar o `httpd.conf`: + +```apache +# usa mod_rewrite para suportar URLs amigáveis +RewriteEngine on + +# Não permite acesso a URLs com o nome do script +RewriteCond %{THE_REQUEST} index.php [NC] +RewriteRule . - [R=404,L] + +# Se um diretório ou arquivo existir, usa a requisição diretamente +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d + +# Caso contrário, encaminha a requisição para index.php +RewriteRule . index.php + +SetEnv APP_ENV dev + +# ...outras configurações... +``` + +Observe o uso de `SetEnv` acima. Como os templates de aplicação do Yii3 usam +variáveis de ambiente, este é um lugar possível para defini-las. Em +produção, lembre-se de definir `APP_ENV` como `prod`. + +Veja [logs da aplicação](general.md#logs-da-aplicacao) para a configuração +de logs. diff --git a/src/pt-BR/cookbook/configuring-webservers/general.md b/src/pt-BR/cookbook/configuring-webservers/general.md new file mode 100644 index 00000000..d5878778 --- /dev/null +++ b/src/pt-BR/cookbook/configuring-webservers/general.md @@ -0,0 +1,45 @@ +# Configurando servidores web: geral + +Em um servidor de produção, se você não usa Docker, configure seu servidor +web para servir apenas os arquivos públicos da aplicação. Aponte o document +root do servidor web para a pasta `app/public`. + +> [!IMPORTANT] +> Se você executa sua aplicação Yii atrás de um proxy reverso, pode ser necessário configurar +> [proxies e headers confiáveis](../../guide/security/trusted-request.md). + +## Logs da aplicação + +Os templates de aplicação do Yii3 escrevem os logs da aplicação na saída +padrão (`stdout`, ou `php://stdout`) por padrão. Eles não criam arquivos de +log da aplicação. A saída de erro padrão (`stderr`) exige configuração +explícita de destino de log. O Docker coleta a saída dos containers, mas em +um servidor sem containers você precisa configurar para onde essa saída vai +ou [configurar um destino de +arquivo](../../guide/runtime/logging.md#logs-em-arquivos). As configurações +de log de acesso e de erro do servidor web não configuram os destinos de log +do Yii. + +### PHP-FPM + +Se o seu servidor web usa PHP-FPM, habilite a captura da saída dos workers +na configuração do pool PHP-FPM da aplicação: + +```ini +catch_workers_output = yes +``` + +Recarregue o PHP-FPM depois de alterar a configuração. O PHP-FPM envia a +saída padrão e a saída de erro dos workers para o seu log de erro +principal. A diretiva `error_log` em `php-fpm.conf` define o destino. Sem +essa configuração, o PHP-FPM redireciona as duas saídas para `/dev/null` por +padrão. Veja a [referência de configuração do +PHP-FPM](https://www.php.net/manual/en/install.fpm.configuration.php). + +## Configurações específicas de servidores + +- [Nginx](nginx.md) +- [Apache](apache.md) +- [Lighttpd](lighttpd.md) +- [Nginx Unit](nginx-unit.md) +- [IIS](iis.md) diff --git a/src/pt-BR/cookbook/configuring-webservers/iis.md b/src/pt-BR/cookbook/configuring-webservers/iis.md new file mode 100644 index 00000000..812ec443 --- /dev/null +++ b/src/pt-BR/cookbook/configuring-webservers/iis.md @@ -0,0 +1,36 @@ +# Configurando servidores web: IIS + +Ao usar o [IIS](https://www.iis.net/), hospede a aplicação em um virtual +host (Website) cujo document root aponte para a pasta `path/to/app/public` e +configure o site para executar PHP. Nessa pasta `public`, coloque um +arquivo chamado `web.config` em `path/to/app/public/web.config`. Use o +seguinte conteúdo: + +```xml + + + + + + + + + + + + + + + + + + +``` + +A [documentação do IIS](https://learn.microsoft.com/en-us/iis/) também pode +ser útil para configurar o PHP no IIS. + +Veja [logs da aplicação](general.md#logs-da-aplicacao) para a configuração +de logs. diff --git a/src/pt-BR/cookbook/configuring-webservers/lighttpd.md b/src/pt-BR/cookbook/configuring-webservers/lighttpd.md new file mode 100644 index 00000000..a4b6a482 --- /dev/null +++ b/src/pt-BR/cookbook/configuring-webservers/lighttpd.md @@ -0,0 +1,10 @@ +# Configurando servidores web: lighttpd + +Para usar o [lighttpd](https://www.lighttpd.net/) >= 1.4.24, coloque o `index.php` na raiz web e adicione o seguinte à configuração: + +``` +url.rewrite-if-not-file = ("(.*)" => "/index.php/$0") +``` + +Veja [logs da aplicação](general.md#logs-da-aplicacao) para a configuração +de logs. diff --git a/src/pt-BR/cookbook/configuring-webservers/nginx-unit.md b/src/pt-BR/cookbook/configuring-webservers/nginx-unit.md new file mode 100644 index 00000000..e83b4893 --- /dev/null +++ b/src/pt-BR/cookbook/configuring-webservers/nginx-unit.md @@ -0,0 +1,71 @@ +# Configurando servidores web: NGINX Unit e FreeUnit + +Execute aplicações baseadas em Yii usando o [NGINX +Unit](https://unit.nginx.org/) com um módulo de linguagem PHP. O mesmo +formato de configuração é usado pelo +[FreeUnit](https://github.com/freeunitorg/freeunit), um fork LTS do Unit +mantido pela comunidade. Com as imagens Docker do FreeUnit, como +`ghcr.io/freeunitorg/freeunit:latest-php8.5`, coloque a configuração em +`/var/lib/unit/config.json`. + +Aqui está um exemplo de configuração. + +```json +{ + "listeners": { + "*:80": { + "pass": "routes" + } + }, + + "routes": [ + { + "match": { + "uri": [ + "!/assets/*", + "*.php", + "*.php/*" + ] + }, + + "action": { + "pass": "applications/yii/direct" + } + }, + { + "action": { + "share": "/path/to/app/public$uri", + "fallback": { + "pass": "applications/yii/index" + } + } + } + ], + + "applications": { + "yii": { + "type": "php", + "targets": { + "direct": { + "root": "/path/to/app/public/" + }, + + "index": { + "root": "/path/to/app/public/", + "script": "index.php" + } + } + } + } +} +``` + +Você também pode [configurar](https://unit.nginx.org/configuration/#php) o +ambiente PHP ou fornecer um `php.ini` personalizado na mesma configuração. + +Como os templates de aplicação do Yii3 usam variáveis de ambiente, você pode +defini-las em `applications.yii.environment`. Em produção, lembre-se de +definir `APP_ENV` como `prod`. + +Veja [logs da aplicação](general.md#logs-da-aplicacao) para a configuração +de logs. diff --git a/src/pt-BR/cookbook/configuring-webservers/nginx.md b/src/pt-BR/cookbook/configuring-webservers/nginx.md new file mode 100644 index 00000000..e54edfea --- /dev/null +++ b/src/pt-BR/cookbook/configuring-webservers/nginx.md @@ -0,0 +1,67 @@ +# Configurando servidores web: Nginx + +Para usar o [Nginx](https:/nginx.org/), instale o PHP como [FPM +SAPI](https://secure.php.net/install.fpm). Use a configuração do Nginx a +seguir, substituindo `path/to/app/public` pelo caminho real de `app/public` +e `mysite.test` pelo hostname real a ser servido. + +```nginx +server { + charset utf-8; + client_max_body_size 128M; + + listen 80; ## escuta em ipv4 + #listen [::]:80 default_server ipv6only=on; ## escuta em ipv6 + + server_name mysite.test; + root /path/to/app/public; + index index.php; + + access_log /path/to/basic/log/access.log; + error_log /path/to/basic/log/error.log; + + location / { + # Redireciona para index.php tudo que não for um arquivo real + try_files $uri $uri/ /index.php$is_args$args; + } + + # descomente para evitar que o Yii processe chamadas a arquivos estáticos inexistentes + #location ~ \.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ { + # try_files $uri =404; + #} + #error_page 404 /404.html; + + # bloqueia o acesso a arquivos php no diretório /assets + location ~ ^/assets/.*\.php$ { + deny all; + } + + location ~ \.php$ { + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_pass 127.0.0.1:9000; + #fastcgi_pass unix:/var/run/php8-fpm.sock; + try_files $uri =404; + fastcgi_param APP_ENV "dev"; + } + + location ~* /\. { + deny all; + } +} +``` + +Ao usar essa configuração, defina também `cgi.fix_pathinfo=0` no arquivo +`php.ini` para evitar muitas chamadas de sistema `stat()` desnecessárias. + +Além disso, ao executar um servidor HTTPS, você precisa adicionar +`fastcgi_param HTTPS on;` para que o Yii consiga detectar se a conexão é +segura. + +Observe o uso de `fastcgi_param APP_ENV` acima. Como os templates de +aplicação do Yii3 usam variáveis de ambiente, este é um lugar possível para +defini-las. Em produção, lembre-se de definir `APP_ENV` como `prod`. + +As diretivas `access_log` e `error_log` do Nginx acima não capturam a saída +dos workers do PHP-FPM. Veja [logs da +aplicação](general.md#logs-da-aplicacao) para a configuração de logs. diff --git a/src/pt-BR/cookbook/configuring-xdebug.md b/src/pt-BR/cookbook/configuring-xdebug.md new file mode 100644 index 00000000..1584a93e --- /dev/null +++ b/src/pt-BR/cookbook/configuring-xdebug.md @@ -0,0 +1,287 @@ +# Configurando o Xdebug + +O Xdebug permite que a IDE pare o código PHP em breakpoints enquanto a +aplicação processa uma requisição web, um comando de console ou um teste. A +IDE escuta conexões de depuração. O PHP inicia a requisição e o Xdebug se +conecta de volta à IDE. + +O Yii funciona com a configuração comum do Xdebug. Configure o Xdebug no +runtime PHP que executa o código e garanta que a IDE consiga mapear os +caminhos do runtime para os arquivos do projeto. + +## Verificando o Xdebug + +Use o Xdebug 3. A porta de depuração padrão é `9003`. + +Sem Docker, instale o Xdebug no executável PHP que roda a aplicação e depois +verifique: + +```shell +php --version +php --ri xdebug +``` + +No `php.ini` ou em um arquivo ini específico do Xdebug, habilite a depuração +passo a passo: + +```ini +xdebug.mode=develop,debug +xdebug.start_with_request=trigger +xdebug.client_host=127.0.0.1 +xdebug.client_port=9003 +``` + +`trigger` inicia uma sessão de depuração apenas quando uma extensão do +navegador, um parâmetro de query string, um cookie ou a variável de ambiente +`XDEBUG_SESSION` pedir. + +Com Docker, o template de aplicação do Yii instala o Xdebug na imagem de +desenvolvimento. Habilite a depuração passo a passo em +`docker/dev/override.env`: + +```dotenv +XDEBUG_MODE=develop,debug +XDEBUG_CONFIG="client_host=host.docker.internal idekey=phpstorm" +``` + +Mantenha o `SERVER_NAME=:80` padrão de `docker/dev/.env`, a menos que a +aplicação precise de outro endereço no Caddy. Defina a porta do navegador +com `DEV_PORT` em `docker/.env`: + +```dotenv +DEV_PORT=80 +``` + +No Linux, o Docker precisa resolver `host.docker.internal` para o gateway do +host. O template de aplicação atual do Yii já traz isso em +`docker/compose.yml`: + +```yaml +services: + app: + extra_hosts: + - "host.docker.internal:host-gateway" +``` + +Reconstrua a imagem de desenvolvimento se o Xdebug foi adicionado depois que +a imagem já tinha sido construída: + +```shell +make build +``` + +## PhpStorm + +Em **Settings** > **PHP** > **Debug**, verifique se o Xdebug escuta na porta `9003`. Comece a escutar com +**Run** > **Start Listening for PHP Debug Connections**. + +Para depurar pelo navegador, instale uma extensão de navegador a partir de **Settings** > **PHP** > **Debug**. Nas opções da extensão, +use `phpstorm` como IDE key. + +Quando o PHP roda no Docker, configure um servidor em **Settings** > **PHP** > **Servers**: + +- Nome: `localhost`. +- Host: `localhost`. +- Porta: `80`, ou a porta do host configurada em `DEV_PORT`. +- Depurador: `Xdebug`. +- Mapeamento de caminhos: mapeie a raiz do projeto no host para `/app` no + container. + +Use a raiz do projeto no mapeamento. Mapear só `public/` deixa sem +mapeamento os arquivos em `src/`, `config/` e `vendor/`. O caminho no +container precisa ser igual ao caminho usado pelo PHP. No template padrão, o +projeto é montado em `/app`. + +Com PHP local, o PhpStorm normalmente usa os mesmos caminhos do sistema de +arquivos que o PHP, então mapeamentos de caminhos costumam ser +desnecessários. + +## VS Code + +Instale a extensão [PHP +Debug](https://marketplace.visualstudio.com/items?itemName=xdebug.php-debug). + +Para PHP rodando no mesmo sistema de arquivos que o VS Code, crie +`.vscode/launch.json`: + +```json +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Listen for Xdebug", + "type": "php", + "request": "launch", + "port": 9003 + } + ] +} +``` + +Para Docker, adicione mapeamentos de caminhos: + +```json +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Listen for Xdebug", + "type": "php", + "request": "launch", + "port": 9003, + "pathMappings": { + "/app": "${workspaceFolder}" + } + } + ] +} +``` + +Inicie essa configuração antes de executar a requisição web, o comando ou o +teste. + +## Zed + +Instale ou habilite a extensão PHP no Zed. Ela fornece o adaptador de +depuração `Xdebug`. + +Crie `.zed/debug.json`: + +```json +[ + { + "label": "PHP: Listen to Xdebug", + "adapter": "Xdebug", + "request": "launch", + "port": 9003 + } +] +``` + +Para Docker, adicione mapeamentos de caminhos: + +```json +[ + { + "label": "PHP: Listen to Xdebug", + "adapter": "Xdebug", + "request": "launch", + "port": 9003, + "pathMappings": { + "/app": "$ZED_WORKTREE_ROOT" + } + } +] +``` + +Inicie a configuração com **debugger: start** antes de executar a requisição +web, o comando ou o teste. O Zed também consegue carregar configurações de +depuração de `.vscode/launch.json` quando `.zed/debug.json` não existe. + +## Depurando uma requisição web + +Sem Docker: + +1. Comece a escutar na IDE. +2. Coloque um breakpoint em uma action ou middleware. +3. Inicie o servidor embutido com um trigger do Xdebug: + + ```shell + ./yii serve --xdebug + ``` + +4. Abra ou recarregue a página no navegador. + +A opção `--xdebug` passa `XDEBUG_MODE=debug XDEBUG_TRIGGER=yes` para o +servidor embutido do PHP. Se você usa outro servidor web, habilite a +depuração com a extensão do navegador e recarregue a página. + +Com Docker: + +1. Adicione as variáveis do Xdebug para Docker em `docker/dev/override.env`. +2. Inicie ou reinicie os containers de desenvolvimento: + + ```shell + make up + ``` + +3. Comece a escutar na IDE. +4. Coloque um breakpoint em uma action ou middleware. +5. Habilite a depuração na extensão do navegador e recarregue a página. + +Se a IDE aceita a conexão e o breakpoint continua inativo, verifique +primeiro os mapeamentos de caminhos. + +## Depurando um comando de console + +Sem Docker, inicie o comando com um trigger do Xdebug: + +```shell +XDEBUG_MODE=debug XDEBUG_SESSION=phpstorm ./yii hello +``` + +Com Docker, passe o trigger para o container: + +```shell +docker compose -f docker/compose.yml -f docker/dev/compose.yml run --rm \ + -e XDEBUG_MODE=debug \ + -e XDEBUG_SESSION=phpstorm \ + -e PHP_IDE_CONFIG=serverName=localhost \ + app ./yii hello +``` + +Use o nome do comando e os argumentos de que você precisa no lugar de +`hello`. + +## Depurando testes + +Sem Docker, inicie o executor de testes com um trigger do Xdebug: + +```shell +XDEBUG_MODE=debug XDEBUG_SESSION=phpstorm vendor/bin/codecept run +``` + +Com Docker, configure `docker/test/override.env`: + +```dotenv +XDEBUG_MODE=debug,coverage +XDEBUG_CONFIG="client_host=host.docker.internal idekey=phpstorm" +``` + +Depois, rode o container de testes com um trigger: + +```shell +docker compose -f docker/compose.yml -f docker/test/compose.yml run --rm \ + -e XDEBUG_SESSION=phpstorm \ + -e PHP_IDE_CONFIG=serverName=localhost \ + app ./vendor/bin/codecept run +``` + +Use `make test` para execuções normais dos testes. Use o comando `docker +compose` explícito quando precisar passar variáveis de ambiente só de +depuração para uma execução. + +## Solução de problemas + +- A IDE precisa estar escutando antes de o PHP iniciar a requisição. +- O Xdebug se conecta do PHP para a IDE. Libere conexões de entrada na porta + `9003` no firewall do host. +- No Docker, o `client_host` precisa ser acessível a partir do container. O + template do Yii usa `host.docker.internal`. +- Para CLI e testes, defina `XDEBUG_SESSION=phpstorm` ou outro trigger + aceito pela sua configuração do Xdebug. +- Para mapeamentos de caminhos no Docker, mapeie a raiz do projeto no host + para `/app`. +- Para inspecionar as tentativas de conexão, adicione temporariamente + `log=/app/runtime/xdebug.log` ao `XDEBUG_CONFIG`. + +## Veja também + +- [Depuração passo a passo do Xdebug](https://xdebug.org/docs/step_debug) +- [Documentação do Xdebug no + PhpStorm](https://www.jetbrains.com/help/phpstorm/configuring-xdebug.html) +- [Servidores e mapeamentos de caminhos no + PhpStorm](https://www.jetbrains.com/help/phpstorm/servers.html) +- [VS Code PHP Debug](https://github.com/xdebug/vscode-php-debug) +- [Documentação de PHP no Zed](https://zed.dev/docs/languages/php#debugging) +- [Docker nos templates de aplicação](../guide/tutorial/docker.md) diff --git a/src/pt-BR/cookbook/custom-hydrator-type-casters.md b/src/pt-BR/cookbook/custom-hydrator-type-casters.md new file mode 100644 index 00000000..8fcc274c --- /dev/null +++ b/src/pt-BR/cookbook/custom-hydrator-type-casters.md @@ -0,0 +1,571 @@ +# Type casters personalizados para o hydrator + +O [Yii Hydrator](https://github.com/yiisoft/hydrator) cria objetos e os +preenche com dados de arrays. Ele é usado diretamente e por pacotes +construídos sobre ele: + +- O [Yii Input HTTP](https://github.com/yiisoft/input-http) preenche objetos + de entrada da requisição a partir de parâmetros da query string, do corpo + da requisição e, com a ajuda do [Yii + Router](https://github.com/yiisoft/router), dos argumentos da rota. +- O [Yii Form Model](https://github.com/yiisoft/form-model) fornece o + `FormHydrator`, que preenche form models com os dados enviados. + +Os dados recebidos geralmente são "brutos": requisições HTTP, linhas do +banco de dados e mensagens de fila contêm strings, números e arrays. Antes +de atribuir um valor a uma propriedade ou passá-lo a um parâmetro do +construtor, o hydrator o converte para o tipo declarado. Um *type caster* +faz essa conversão. Ao escrever seu próprio type caster, você ensina o +hydrator a criar seus tipos, como value objects, a partir de dados brutos. + +## Por que type casters personalizados + +Por padrão, o hydrator usa um type caster composto com dois casters: + +- `PhpNativeTypeCaster` converte valores para tipos nativos do PHP, como + `int`, `string`, `bool` e `array`. +- `HydratorTypeCaster` cria objetos aninhados a partir de arrays usando o + próprio hydrator. + +Isso basta para DTOs com propriedades escalares, mas não para um modelo de +domínio rico. Considere uma propriedade tipada como `UserId`, `Email` ou +`Money`. O valor recebido é uma string, e nenhum dos casters padrão sabe +transformá-lo em um objeto desses. Assim, você acaba declarando a +propriedade como `string` e convertendo-a manualmente onde quer que ela seja +usada: + +```php +final class CreatePostForm extends FormModel +{ + public string $authorId = ''; +} + +// Em toda action que usa o formulário: +try { + $authorId = new UserId($form->authorId); +} catch (InvalidArgumentException) { + // Reporte o erro de alguma forma. +} +``` + +Com um type caster para `UserId`, você pode declarar a propriedade com seu +tipo real. A conversão acontece durante a hidratação: + +```php +final class CreatePostForm extends FormModel +{ + public ?UserId $authorId = null; +} + +// $form->authorId já é uma instância de UserId. +``` + +A lógica de conversão fica em um único lugar. Depois que você registra o +caster, o hydrator o aplica a todas as propriedades e parâmetros de +construtor do tipo correspondente em todos os objetos que ele cria. + +Casos de uso típicos: + +- value objects, como IDs de entidades, e-mails, números de telefone e + valores monetários. +- tipos de bibliotecas de terceiros, como UUIDs, datas ou moedas. +- normalização consistente de valores, por exemplo, interpretar datas em um + formato específico da sua aplicação. + +## Anatomia de um type caster + +Um type caster implementa `Yiisoft\Hydrator\TypeCaster\TypeCasterInterface`, +que tem um único método: + +```php +public function cast(mixed $value, TypeCastContext $context): Result; +``` + +- `$value` é o valor bruto a ser convertido. +- `$context` é um `Yiisoft\Hydrator\TypeCaster\TypeCastContext`. Seu método + `getReflectionType()` retorna o tipo declarado da propriedade ou do + parâmetro de construtor de destino. Use-o para decidir se o caster suporta + o tipo de destino. +- O método retorna um `Yiisoft\Hydrator\Result`: + `Result::success($convertedValue)` se a conversão deu certo ou + `Result::fail()` se o caster não consegue lidar com o valor. + +Siga estas regras ao escrever um type caster: + +1. **Verifique o tipo de destino primeiro.** Se o tipo declarado não for + aquele pelo qual seu caster é responsável, retorne `Result::fail()` + imediatamente para que outros casters possam lidar com o valor. +2. **Trate tipos nomeados e tipos união.** O PHP representa um tipo anulável + como `?Email` (ou `Email|null`) com `ReflectionNamedType` e + `Email|string` com `ReflectionUnionType`. No segundo caso, procure seu + tipo entre os subtipos. +3. **Não trate `null` você mesmo.** Se o valor for `null`, apenas retorne + `Result::fail()`. O `PhpNativeTypeCaster` retorna `null` para qualquer + tipo que o permita, então um valor `null` atribuído a `?Email` continua + `null`. +4. **Aceite valores já convertidos.** Se o valor já for uma instância do + tipo de destino, retorne-o como está. +5. **Falhe em vez de lançar exceções.** Se seu caster não consegue converter + o valor, por exemplo, uma string malformada, retorne + `Result::fail()`. Uma exceção quebraria toda a hidratação. + +Tenha em mente o que acontece quando nenhum caster tem sucesso: + +- Para uma propriedade, a conversão falha silenciosamente. O hydrator não + define a propriedade nem reporta um erro, então a propriedade mantém seu + valor padrão. Reportar o problema ao usuário é papel da validação que roda + após a hidratação. Veja [Valores nulos e + inválidos](#valores-nulos-e-invalidos) para um exemplo. +- Para um parâmetro de construtor, o hydrator omite o argumento. Se o + parâmetro tiver um valor padrão, ele é usado. Caso contrário, a criação + do objeto falha com `WrongConstructorArgumentsCountException`, mesmo para + um parâmetro anulável sem valor padrão. + +## Registrando um type caster + +Combine type casters com `CompositeTypeCaster`. Ele tenta os casters um a um +e usa o resultado do primeiro que tiver sucesso. Para adicionar seu caster, +redefina `TypeCasterInterface` na configuração do container de DI, por +exemplo, em `config/common/di/hydrator.php`. A implementação de +`HydratorInterface` do container usa essa cadeia, assim como os pacotes que +dependem dela, como o Yii Input HTTP: + +```php + static fn() => new CompositeTypeCaster( + new UuidValueTypeCaster(), + new PhpNativeTypeCaster(), + new HydratorTypeCaster(), + ), +]; +``` + +Como o primeiro resultado bem-sucedido vence, a ordem importa: + +- Coloque os casters personalizados antes do `PhpNativeTypeCaster`. Caso + contrário, para uma propriedade declarada como `UserId|string`, o + `PhpNativeTypeCaster` aceita a string como está, e seu caster nunca é + executado. +- Mantenha os casters padrão na lista. O `PhpNativeTypeCaster` converte + valores escalares para tipos nativos, e o `HydratorTypeCaster` cria + objetos aninhados a partir de arrays. + +Se um caster tiver dependências, obtenha-o do container: + +```php + static fn(ContainerInterface $container) => new CompositeTypeCaster( + $container->get(MoneyTypeCaster::class), + new PhpNativeTypeCaster(), + new HydratorTypeCaster(), + ), +]; +``` + +### Registrando para form models + +O `FormHydrator` do Yii Form Model não usa `TypeCasterInterface`. Sua +configuração de DI cria um hydrator dedicado com sua própria cadeia de type +casters, então adicione seu caster lá também: + +```php + [ + '__construct()' => [ + 'hydrator' => DynamicReference::to([ + 'class' => Hydrator::class, + '__construct()' => [ + 'typeCaster' => new CompositeTypeCaster( + new NullTypeCaster(emptyString: true), + new UuidValueTypeCaster(), + new PhpNativeTypeCaster(), + new NonArrayTypeCaster(), + new HydratorTypeCaster(), + ), + ], + ]), + ], + ], +]; +``` + +Essa definição substitui a do pacote, então mantenha os type casters +dele. Este exemplo usa a lista do `config/di.php` do Yii Form Model +1.1. Confira com a versão que você usa. O `NullTypeCaster` transforma +strings vazias enviadas por formulários em `null` para propriedades +anuláveis, por isso ele continua em primeiro. + +## Exemplo: value objects de UUID + +IDs de entidades frequentemente usam value objects, como `UserId`, `PostId` +e `OrderId`, em vez de strings simples. Esses objetos tornam as assinaturas +dos métodos autodocumentadas e impedem que você passe um ID de post onde um +método espera um ID de usuário. O exemplo a seguir mostra como escrever um +type caster que os cria a partir de strings UUID. + +### Value objects + +Todos os value objects de ID estendem uma classe abstrata `UuidValue`. O +exemplo usa [ramsey/uuid](https://github.com/ramsey/uuid) para validar e +gerar UUIDs: + +```shell +composer require ramsey/uuid +``` + +```php +value = Uuid::fromString($value)->toString(); + } + + public static function generate(): static + { + return new static(Uuid::uuid7()->toString()); + } + + public function equals(self $other): bool + { + return $other instanceof static && $other->value === $this->value; + } + + public function __toString(): string + { + return $this->value; + } +} +``` + +O construtor é final, então `new static()` é seguro e cria todas as classes +filhas a partir de uma string da mesma forma. Um ID concreto é apenas uma +classe filha vazia: + +```php +findUuidValueClass($context->getReflectionType()); + if ($class === null) { + return Result::fail(); + } + + if ($value instanceof $class) { + return Result::success($value); + } + + if (!is_string($value) || !Uuid::isValid($value)) { + return Result::fail(); + } + + return Result::success(new $class($value)); + } + + /** + * Retorna a classe filha de `UuidValue` a partir do tipo declarado, ou `null` se não houver nenhuma ou houver várias + * delas, como em `UserId|PostId`. + * + * @return class-string|null + */ + private function findUuidValueClass(?ReflectionType $type): ?string + { + $types = match (true) { + $type instanceof ReflectionNamedType => [$type], + $type instanceof ReflectionUnionType => $type->getTypes(), + default => [], + }; + + $classes = []; + foreach ($types as $subType) { + if ( + $subType instanceof ReflectionNamedType + && !$subType->isBuiltin() + && is_subclass_of($subType->getName(), UuidValue::class) + ) { + $classes[] = $subType->getName(); + } + } + + return count($classes) === 1 ? $classes[0] : null; + } +} +``` + +O caster segue as [regras para escrever um type +caster](#anatomia-de-um-type-caster). Ele escolhe a classe a ser criada a +partir do tipo declarado. Todos os IDs compartilham o mesmo formato UUID, +então uma string sozinha não diz se é um ID de usuário ou de post. Por isso, +um único caster atende todas as classes filhas de `UuidValue`, e adicionar +uma nova classe de ID não exige mudanças no caster. Pelo mesmo motivo, o +caster falha para um tipo com várias classes de ID, como +`UserId|PostId`. Não há como escolher a correta. + +Registre o `UuidValueTypeCaster` como mostrado na seção [Registrando um type +caster](#registrando-um-type-caster), incluindo a [configuração para form +models](#registrando-para-form-models) se você usa o Yii Form Model. + +### Usando os value objects + +Agora qualquer classe preenchida pelo hydrator pode declarar value objects +de ID diretamente. + +#### Hydrator + +A mesma string se torna um value object diferente dependendo do tipo da +propriedade: + +```php +use App\Post\PostId; +use App\User\UserId; +use Yiisoft\Hydrator\HydratorInterface; + +final class CommentFilter +{ + public ?UserId $authorId = null; + public ?PostId $postId = null; +} + +/** @var HydratorInterface $hydrator */ +$filter = $hydrator->create(CommentFilter::class, [ + 'authorId' => '0192f2a4-7a4b-7c3e-9a1b-3f5c8d2e6a10', + 'postId' => '0192f2a4-7a4b-7c3e-9a1b-3f5c8d2e6a10', +]); + +// $filter->authorId é UserId, $filter->postId é PostId. +// $filter->authorId->equals($filter->postId) retorna false. +``` + +#### Entrada da requisição + +O pacote [Yii Input HTTP](https://github.com/yiisoft/input-http) usa o +hydrator para preencher objetos de entrada da requisição, então o mesmo type +caster funciona para parâmetros da query string, corpo da requisição e +argumentos da rota. O atributo `RouteArgument` vem do [Yii +Router](https://github.com/yiisoft/router). Estenda `AbstractInput` para que +a entrada seja validada após a hidratação: + +```php +getValidationResult()->isValid()) { + // Retorne uma resposta de erro. + } + + // $input->id é PostId, $input->authorId é UserId. + // ... + } +} +``` + +#### Form model + +O `FormHydrator` do [Yii Form Model](https://github.com/yiisoft/form-model) +preenche form models. Depois que você [registra o caster para form +models](#registrando-para-form-models), também pode declarar propriedades de +formulário como value objects: + +```php +formHydrator->populateFromPostAndValidate($form, $request)) { + // $form->authorId é UserId. + // ... + } + + // ... + } +} +``` + +### Valores nulos e inválidos + +Veja o que acontece com uma propriedade declarada como `?UserId` para +diferentes valores de entrada: + +| Valor de entrada | Tratado por | Valor da propriedade | +|------------------------------------------|------------------------|----------------------------------| +| `'0192f2a4-7a4b-7c3e-9a1b-3f5c8d2e6a10'` | `UuidValueTypeCaster` | instância de `UserId` | +| `null` | `PhpNativeTypeCaster` | `null` | +| `'not-a-uuid'` | nenhum, todos falham | valor padrão, `null` no exemplo | + +A última linha é a importante: o hydrator não reporta o valor malformado. +Com a regra `Required`, a validação o detecta com o erro "cannot be blank". +Veja os exemplos de [entrada da requisição](#entrada-da-requisicao) e [form +model](#form-model). Mas, se a propriedade for opcional, um UUID inválido é +silenciosamente transformado em `null` e fica indistinguível de um valor +ausente. Se isso não for aceitável, mantenha o valor bruto para validação: +declare a propriedade como `string`, valide seu formato e converta-a para o +value object após a validação. + +## Quando usar um type caster + +Um type caster é uma boa escolha quando a conversão: + +- depende apenas do valor e do tipo declarado. +- é a mesma em toda a aplicação. +- não precisa de I/O, como consultas ao banco de dados ou chamadas HTTP. + +Value objects para IDs, e-mails e valores monetários atendem aos três +critérios. Mantenha a conversão em um mapper dedicado ou em uma factory de +domínio quando ela: + +- precisa consultar o banco de dados, por exemplo, transformar um ID em uma + entidade carregada. +- depende de contexto, como o usuário atual. +- combina vários campos de entrada em um único objeto. +- difere entre casos de uso. diff --git a/src/pt-BR/cookbook/custom-migration-template.md b/src/pt-BR/cookbook/custom-migration-template.md new file mode 100644 index 00000000..d1e90b87 --- /dev/null +++ b/src/pt-BR/cookbook/custom-migration-template.md @@ -0,0 +1,137 @@ +# Usando um template de migration personalizado + +O comando `migrate:create` do `yiisoft/db-migration` gera classes de +migration a partir de templates PHP de view. Use um template personalizado +quando seu projeto quiser um cabeçalho padrão, um formato de classe rígido, +comentários, chamadas a helpers ou placeholders específicos da equipe em +toda nova migration. + +Esta receita assume que as migrations já estão configuradas como descrito no +guia [Migrations de banco de dados](../guide/databases/db-migrations.md). + +## Crie um template + +Crie `resources/migration-templates/migration.php`: + +```php + + +use Yiisoft\Db\Migration\MigrationBuilder; +use Yiisoft\Db\Migration\RevertibleMigrationInterface; + +final class implements RevertibleMigrationInterface +{ + public function up(MigrationBuilder $b): void + { + // Add forward migration code. + } + + public function down(MigrationBuilder $b): void + { + // Add rollback migration code. + } +} +``` + +O template é um arquivo PHP que imprime a migration gerada. Para o comando +`create` padrão, as variáveis mais úteis são `$className` e `$namespace`. + +## Configure o gerador + +Crie `config/common/di/migration-generator.php`: + +```php + [ + 'setTemplate()' => [ + 'create', + dirname(__DIR__, 3) . '/resources/migration-templates/migration.php', + ], + ], +]; +``` + +A chave `create` muda o template usado por: + +```shell +./yii migrate:create audit_log +``` + +O comando pede confirmação e então grava uma migration usando o seu +template. + +Se o novo arquivo de DI não for carregado, reconstrua o merge plan da +configuração: + +```shell +composer yii-config-rebuild +``` + +## Configure vários templates + +O `yiisoft/db-migration` suporta estas chaves de template: + +- `create` +- `table` +- `dropTable` +- `addColumn` +- `dropColumn` +- `junction` + +Para substituir vários templates de uma vez, use `setTemplates()`: + +```php +use Yiisoft\Db\Migration\Service\Generate\CreateService; + +return [ + CreateService::class => [ + 'setTemplates()' => [[ + 'create' => dirname(__DIR__, 3) . '/resources/migration-templates/migration.php', + 'table' => dirname(__DIR__, 3) . '/resources/migration-templates/create-table.php', + 'dropTable' => dirname(__DIR__, 3) . '/resources/migration-templates/drop-table.php', + 'addColumn' => dirname(__DIR__, 3) . '/resources/migration-templates/add-column.php', + 'dropColumn' => dirname(__DIR__, 3) . '/resources/migration-templates/drop-column.php', + 'junction' => dirname(__DIR__, 3) . '/resources/migration-templates/create-junction.php', + ]], + ], +]; +``` + +Para os templates voltados a tabelas, copie o arquivo correspondente de +`vendor/yiisoft/db-migration/resources/views/` e ajuste-o. Esses templates +recebem variáveis adicionais, como `$table`, `$columns`, `$foreignKeys` e +`$tableComment`. + +## Mantenha os templates fáceis de manter + +Mantenha as migrations geradas independentes dos serviços atuais da +aplicação. Uma migration pode rodar anos depois, quando as APIs dos serviços +já mudaram. Coloque operações de schema estáveis na classe gerada e deixe a +lógica de negócio em comandos de console ou serviços da aplicação. + +Não edite templates dentro de `vendor/`. Copie-os para o seu projeto e +configure o `CreateService` para usar as cópias. diff --git a/src/pt-BR/cookbook/deployment/angie-docker-proxy.md b/src/pt-BR/cookbook/deployment/angie-docker-proxy.md new file mode 100644 index 00000000..728187c1 --- /dev/null +++ b/src/pt-BR/cookbook/deployment/angie-docker-proxy.md @@ -0,0 +1,235 @@ +# Fazendo deploy de aplicações Yii com o Angie Docker Proxy + +O [Angie Docker Proxy](https://hub.docker.com/r/angiesoftware/proxy) é um +pequeno proxy reverso para projetos Docker Compose. Ele roda em um container +separado, ao lado das aplicações, lê a API do Docker pelo socket do Docker, +descobre containers pelas variáveis de ambiente `VIRTUAL_HOST` e +`VIRTUAL_PORT`, gera a configuração do Angie e obtém certificados TLS +automaticamente via ACME. + +Essa abordagem é útil quando você precisa rodar várias aplicações web em um +servidor e habilitar HTTPS para elas sem editar manualmente a configuração +do proxy reverso para cada domínio. + +Neste exemplo, vamos conectar uma aplicação Yii em container ao Angie Docker +Proxy e configurar HTTPS automático. + +Este guia assume que sua aplicação Yii já está empacotada como imagem Docker +e aceita requisições HTTP na porta 80. Construir e configurar a imagem da +aplicação está fora do escopo deste guia. + +```mermaid +graph LR + A[Internet] --> B[Proxy reverso: Angie] + B --> C[Aplicação Yii] + B --> D[Outra aplicação] + + subgraph Docker Compose Project + B + C + D + end +``` + +## Pré-requisitos + +- Um servidor com uma distribuição Linux recém-instalada. +- Um nome de domínio apontando para o IP do seu servidor. +- Docker e Docker Compose. +- Portas TCP `80` e `443` abertas. +- Acesso SSH ao seu servidor. +- Conhecimento básico de Docker e de ferramentas de linha de comando. + +## Estrutura do projeto + +O exemplo precisa de uma única configuração do Docker Compose: + +```text +yii-angie-demo/ +└── docker-compose.yml +``` + +## Configurando o Docker Compose + +Crie o `docker-compose.yml` com a configuração a seguir. Substitua: + +- `admin@example.com` pelo seu endereço de e-mail; +- `registry.example.com/yii-app:1.0.0` pela imagem da sua aplicação; +- `example-demo.example.com` pelo domínio que aponta para o seu servidor. + +```yaml +services: + angie-proxy: + image: angiesoftware/proxy:latest + environment: + - ANGIE_ACME_EMAIL=admin@example.com + - ANGIE_ACME_URL=https://acme-v02.api.letsencrypt.org/directory + - ANGIE_RESOLVER=1.1.1.1 8.8.8.8 + - ANGIE_RESOLVER_VALID=300s + - ANGIE_PROXY_NETWORK=proxy + ports: + - "80:80" + - "443:443" + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - angie_acme:/var/lib/angie/acme + networks: + - proxy + + yii-app: + image: registry.example.com/yii-app:1.0.0 + environment: + - VIRTUAL_HOST=example-demo.example.com + - VIRTUAL_PORT=80 + networks: + - proxy + +networks: + proxy: + name: proxy + +volumes: + angie_acme: +``` + +`VIRTUAL_HOST` é o domínio público da aplicação. + +`VIRTUAL_PORT` é a porta interna do container para a qual o Angie deve +encaminhar as requisições. + +O Angie Docker Proxy descobre `VIRTUAL_HOST` e `VIRTUAL_PORT` +automaticamente pelas variáveis de ambiente e emite certificados usando o +módulo ACME do Angie e o Let's Encrypt. + +## Subindo os serviços + +Suba os containers do proxy e da aplicação: + +```bash +docker compose up -d +``` + +## Adicionando outra aplicação + +Para expor outra aplicação, adicione-a em `services` no `docker-compose.yml` +e conecte-a à rede `proxy`: + +```yaml +services: + second-app: + image: traefik/whoami + environment: + - VIRTUAL_HOST=example-demo2.example.com + - VIRTUAL_PORT=80 + networks: + - proxy +``` + +Aplique as alterações: + +```bash +docker compose up -d +``` + +## Como funciona + +O Angie Docker Proxy monitora a API do Docker e descobre os containers +configurados com `VIRTUAL_HOST` e `VIRTUAL_PORT`. Ele gera a configuração +do Angie, obtém certificados TLS via ACME e encaminha as requisições +recebidas para os containers correspondentes pela rede Docker compartilhada. + +Quando containers são adicionados, removidos ou atualizados, o proxy gera a +configuração de novo e faz um reload gracioso. As conexões existentes +continuam sendo atendidas enquanto a configuração atualizada é aplicada. + +Para opções de configuração e detalhes de implementação, veja a +[documentação do Angie Docker +Proxy](https://hub.docker.com/r/angiesoftware/proxy). + +## Verificação + +Verifique os containers: + +```bash +docker compose ps +``` + +Verifique o redirecionamento HTTP: + +```bash +curl -I http://example-demo.example.com/ +``` + +Resultado esperado: + +```text +HTTP/1.1 301 Moved Permanently +Location: https://example-demo.example.com/ +``` + +Verifique o HTTPS: + +```bash +curl -I https://example-demo.example.com/ +``` + +Resultado esperado: + +```text +HTTP/1.1 200 OK +Server: Angie/... +``` + +Verifique o certificado: + +```bash +echo | openssl s_client \ + -connect example-demo.example.com:443 \ + -servername example-demo.example.com 2>/dev/null \ + | openssl x509 -noout -issuer -subject -dates +``` + +Emissor esperado: + +```text +Let's Encrypt +``` + + +## Logs + +Logs do proxy: + +```bash +docker compose logs -f angie-proxy +``` + +## Parando os serviços + +Pare os serviços: + +```bash +docker compose down +``` + +Pare os serviços e remova os certificados: + +```bash +docker compose down -v +``` + +## Limitações + +Esta configuração é feita para o Docker Compose. O Kubernetes não expõe +workloads pela API do Docker e exige um controller de Ingress ou de Gateway +API. O Docker Swarm também usa a API do Docker, mas o deploy no Swarm não é +coberto neste guia. + +## Para mais informações + +- [Documentação do Angie Docker + Proxy](https://hub.docker.com/r/angiesoftware/proxy) +- [Template de aplicação do Yii](https://github.com/yiisoft/app) +- [Docker nos templates de aplicação do + Yii](https://yiisoft.github.io/docs/guide/tutorial/docker.html) +- [Documentação do Docker Compose](https://docs.docker.com/compose/) diff --git a/src/pt-BR/cookbook/deployment/autoscaling.md b/src/pt-BR/cookbook/deployment/autoscaling.md new file mode 100644 index 00000000..ade2eb4b --- /dev/null +++ b/src/pt-BR/cookbook/deployment/autoscaling.md @@ -0,0 +1,174 @@ +# Configurando uma aplicação para autoscaling + +O autoscaling funciona quando qualquer instância da aplicação consegue +atender qualquer requisição e pode ser adicionada ou removida sem estado +local especial. Em aplicações Yii, isso significa principalmente manter o +estado de runtime fora do container ou da VM, deixar os health checks +baratos e rodar migrations e workers separados das réplicas web. + +## Mantenha as instâncias web sem estado + +Não guarde estado visível ao usuário no sistema de arquivos local de uma +instância web. Arquivos locais somem quando uma instância é substituída e +não ficam visíveis para as outras réplicas. + +Mova estes recursos para serviços compartilhados: + +- Sessões: use um handler de sessão compartilhado quando os usuários puderem + alternar entre réplicas. Veja [Sessões](../../guide/runtime/sessions.md) e + prefira fechar as sessões cedo. +- Cache: use Redis, Memcached, banco de dados ou outro backend de cache + PSR-16 compartilhado para dados que precisam ser consistentes entre as + réplicas. Veja [Cache de dados](../../guide/caching/data.md). +- Uploads: guarde arquivos em object storage, em um volume compartilhado ou + em um serviço dedicado ao armazenamento de arquivos. Os diretórios locais + `runtime` ou `public/uploads` só são seguros para arquivos temporários. +- Assets gerados: inclua-os na imagem ou publique-os em um armazenamento + compartilhado/CDN durante o deploy. +- Logs: escreva em stdout/stderr ou em um destino de log central. Não + dependa de arquivos dentro de uma instância de vida curta. + +Sticky sessions podem aliviar a pressão imediata, mas não substituem o +estado compartilhado. Uma instância substituta ou o rollout de um deploy +ainda quebram o armazenamento local de sessões e de uploads. + +## Adicione endpoints de saúde + +Use um endpoint de liveness barato para o load balancer ou o orquestrador: + +```php +responseFactory->createResponse(Status::NO_CONTENT); + } +} +``` + +Registre-o em `config/common/routes.php`: + +```php +use App\Web\Health\HealthCheckAction; +use Yiisoft\Router\Route; + +return [ + // ... + Route::get('/healthz') + ->action(HealthCheckAction::class) + ->name('healthz'), +]; +``` + +Mantenha esse endpoint independente do banco de dados e de APIs +externas. Ele deve responder se o processo PHP consegue aceitar requisições, +não se todas as dependências estão saudáveis. + +Se a sua plataforma suporta readiness checks, adicione um endpoint separado, +como `/readyz`, para as dependências que precisam estar disponíveis antes de +direcionar tráfego para uma nova instância. Limite-o com timeouts curtos. Um +readiness check lento pode piorar um pico de tráfego. + +## Configure os caminhos de runtime + +O diretório `runtime` deve conter apenas arquivos descartáveis e locais ao +processo: logs antes de serem enviados, arquivos de cache que podem ser +recriados, partes temporárias de upload, locks restritos a uma instância e +artefatos de debug. + +Para deploys com autoscaling: + +- monte `runtime` como um volume gravável local à instância ou crie-o na + inicialização da imagem; +- não guarde arquivos enviados permanentes em `runtime`; +- não use locks de arquivo locais para jobs que precisam ser únicos entre + todas as réplicas; +- limpe ou ignore o cache local de runtime durante os rollouts. + +Quando um comando ou worker precisa ser único globalmente, use um lock no +banco de dados, um lock no Redis, a semântica da fila, ou rode-o como um +único job agendado fora do grupo de autoscaling web. + +## Rode as migrations uma única vez + +Não rode `./yii migrate` em cada instância web durante a +inicialização. Várias réplicas subindo ao mesmo tempo podem disputar locks, +deixar o boot lento ou aplicar parcialmente um schema incompatível. + +Rode as migrations a partir de um único job de deploy ou de um container de +console dedicado, antes ou durante o rollout: + +```shell +APP_ENV=prod php ./yii migrate --no-interaction +``` + +Para deploys sem downtime, use um fluxo de migrations do tipo +expand-and-contract. Veja [Aplicando migrations durante rolling +updates](rolling-update-migrations.md). + +## Separe web, workers e jobs agendados + +Escale as réplicas web conforme o tráfego de requisições. Escale os workers +de fila conforme o tamanho da fila ou a latência de processamento. Rode os +jobs agendados a partir de um único agendador, não de cada réplica web. + +Use a mesma imagem da aplicação quando for prático, mas com pontos de +entrada diferentes: + +```shell +php ./yii queue:listen +php ./yii app:send-digests --no-interaction +``` + +Torne workers e comandos agendados idempotentes. Um deploy pode parar um +worker depois que ele começou a processar uma mensagem, e a fila pode +entregá-la de novo. + +## Use configuração específica por ambiente + +Mantenha segredos e valores de cada ambiente fora da imagem: + +- DSN, usuário e senha do banco de dados; +- endereços dos backends de cache/sessão; +- chaves de validação de cookies e chaves de criptografia; +- credenciais de e-mail, fila e object storage; +- URL base pública e configurações de proxies confiáveis. + +Carregue-os por variáveis de ambiente ou por arquivos de configuração do Yii +específicos de cada ambiente. Todas as réplicas da mesma release devem +receber os mesmos valores de configuração, exceto os metadados de instância +fornecidos pela plataforma. + +## Checklist de capacidade + +Antes de habilitar o autoscaling, verifique que: + +- uma requisição é atendida corretamente depois que a requisição anterior + foi para outra réplica; +- login e mensagens flash funcionam sem sticky sessions; +- arquivos enviados continuam disponíveis depois que a instância que os + recebeu é removida; +- cache misses em uma instância não corrompem nem escondem dados em outra + instância; +- as migrations são executadas por exatamente uma etapa do deploy; +- workers em segundo plano e comandos agendados não são multiplicados por + acidente; +- os health checks são rápidos e não sobrecarregam o banco de dados; +- logs e métricas identificam a versão da aplicação e a instância; +- o desligamento é gracioso o bastante para os timeouts do seu servidor web + e dos workers de fila. diff --git a/src/pt-BR/cookbook/deployment/docker-swarm-caddy.md b/src/pt-BR/cookbook/deployment/docker-swarm-caddy.md new file mode 100644 index 00000000..6ec0a140 --- /dev/null +++ b/src/pt-BR/cookbook/deployment/docker-swarm-caddy.md @@ -0,0 +1,595 @@ +# Fazendo deploy de aplicações Yii no Docker Swarm com Caddy + +Este guia mostra como fazer o deploy de uma aplicação Yii no [Docker +Swarm](https://docs.docker.com/engine/swarm/) a partir de um servidor +vazio, usando o [Caddy](https://caddyserver.com/) como proxy reverso e +fazendo o deploy a partir de um registro de containers +([Forgejo](https://forgejo.org/) ou [Gitea](https://about.gitea.com/)). + +```mermaid +graph LR + A[Internet] --> B[Proxy reverso: Caddy] + B --> C[app1.example.com] + B --> D[app2.example.com] + + subgraph Docker Swarm Cluster + B + C + D + end +``` + +## Pré-requisitos + +- Um servidor com uma distribuição Linux recém-instalada (recomendado Ubuntu + 22.04 LTS ou mais recente) +- Um nome de domínio apontando para o IP do seu servidor +- Acesso SSH ao seu servidor +- Conhecimento básico de Docker e de ferramentas de linha de comando + +## Preparando o servidor + +### Instale o Docker + +Para as instruções de instalação, veja a [documentação oficial do +Docker](https://docs.docker.com/engine/install/ubuntu/). + +### Inicialize o Docker Swarm + +Inicialize o seu servidor como manager do Docker Swarm: + +```bash +docker swarm init --advertise-addr +``` + +Substitua `` pelo IP público do seu servidor. + +### Configure a rede do proxy reverso + +Crie uma rede overlay dedicada para o proxy reverso se comunicar com os seus +serviços: + +```bash +docker network create --driver=overlay reverse_proxy_public +``` + +## Configurando o Caddy como proxy reverso + +Para fazer o deploy do Caddy como proxy reverso, crie um arquivo +`caddy-stack.yml`: + +```yaml +services: + caddy: + image: lucaslorentz/caddy-docker-proxy:ci-alpine + ports: + - "80:80" + - "443:443" + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - caddy_data:/data + networks: + - reverse_proxy_public + +volumes: + caddy_data: + +networks: + reverse_proxy_public: + external: true +``` + +Faça o deploy do Caddy: + +```bash +docker stack deploy -c caddy-stack.yml caddy +``` + +O Caddy descobre automaticamente os serviços com labels do Caddy e configura +HTTPS usando o Let's Encrypt. Os templates de aplicação do Yii3 usam labels +do Caddy por padrão: + +```yaml +deploy: + labels: + - caddy: ${PROD_HOST:-app.example.com} + - caddy.reverse_proxy: "{{upstreams 80}}" +``` + +> [!IMPORTANT] +> Garanta que os registros DNS do seu domínio estejam configurados e apontando para o seu servidor antes de fazer o deploy de serviços com +> labels do Caddy, porque o Let's Encrypt exige a validação do domínio. + +## Configurando um registro de containers + +Você precisa de um registro de containers para guardar as suas imagens +Docker. Escolha uma das opções a seguir. + +### Opção 1: usando o Forgejo + +Para fazer o deploy do Forgejo, crie um arquivo `forgejo-stack.yml`: + +```yaml +services: + forgejo: + image: codeberg.org/forgejo/forgejo:1.21 + ports: + - "3000:3000" + volumes: + - forgejo_data:/data + networks: + - reverse_proxy_public + deploy: + labels: + - "caddy=git.example.com" + - "caddy.reverse_proxy={{upstreams 3000}}" + +volumes: + forgejo_data: + +networks: + reverse_proxy_public: + external: true +``` + +Faça o deploy do Forgejo: + +```bash +docker stack deploy -c forgejo-stack.yml forgejo +``` + +Substitua `git.example.com` pelo subdomínio desejado. + +Depois do deploy, acesse o Forgejo em `https://git.example.com` e conclua a +configuração inicial. Não esqueça de habilitar o registro de containers nas +configurações. + +### Opção 2: usando o Gitea + +Para fazer o deploy do Gitea, crie um arquivo `gitea-stack.yml`: + +```yaml +services: + gitea: + image: gitea/gitea:latest + ports: + - "3000:3000" + volumes: + - gitea_data:/data + networks: + - reverse_proxy_public + deploy: + labels: + - "caddy=git.example.com" + - "caddy.reverse_proxy={{upstreams 3000}}" + +volumes: + gitea_data: + +networks: + reverse_proxy_public: + external: true +``` + +Faça o deploy do Gitea: + +```bash +docker stack deploy -c gitea-stack.yml gitea +``` + +Substitua `git.example.com` pelo subdomínio desejado. + +Depois do deploy, acesse o Gitea em `https://git.example.com` e conclua a +configuração inicial. Não esqueça de habilitar o registro de containers nas +configurações. + +## Configurando a sua aplicação Yii + +### Atualize a configuração do Makefile + +O [template de aplicação do Yii](https://github.com/yiisoft/app) inclui um +Makefile com comandos de deploy. Atualize o arquivo `docker/.env` do seu +projeto: + +```bash +STACK_NAME=myapp + +# +# Produção +# + +PROD_HOST=app.example.com +PROD_SSH="ssh://user@your-server-ip" + +IMAGE=git.example.com/username/myapp +IMAGE_TAG=latest +``` + +Substitua os valores: - `STACK_NAME`: um nome único para a stack da sua +aplicação - `PROD_HOST`: o nome de domínio em que a aplicação vai ficar +acessível - `PROD_SSH`: a string de conexão SSH com o seu servidor (formato: +`ssh://user@host`) - `IMAGE`: o caminho completo da imagem do container no +registro - `IMAGE_TAG`: a tag da imagem, normalmente `latest` ou um número +de versão + +### Configure o ambiente de produção + +Atualize o `docker/prod/.env` com as variáveis de ambiente de produção: + +```bash +APP_ENV=prod +YII_DEBUG=false +YII_ENV=prod + +# Configuração do banco de dados +DB_HOST=db +DB_NAME=myapp +DB_USER=myapp +DB_PASSWORD=secure_password_here + +# Adicione outras variáveis específicas do ambiente +``` + +> [!WARNING] +> Nunca faça commit de credenciais sensíveis no controle de versão. Use `docker/prod/override.env` para valores sensíveis e adicione-o ao `.gitignore`. + +### Revise a configuração do Docker Compose de produção + +O `docker/prod/compose.yml` padrão inclui: + +```yaml +services: + app: + image: ${IMAGE}:${IMAGE_TAG} + networks: + - reverse_proxy_public + volumes: + - runtime:/app/runtime + - caddy_data:/data + - caddy_config:/config + env_file: + - path: ./prod/.env + - path: ./prod/override.env + required: false\ + environment: + CADDY_EXTRA_CONFIG: 'auto_https off' + deploy: + replicas: 2 + update_config: + delay: 10s + parallelism: 1 + order: start-first + failure_action: rollback + monitor: 10s + rollback_config: + parallelism: 0 + order: stop-first + restart_policy: + condition: on-failure + delay: 5s + max_attempts: 3 + window: 120s + labels: + caddy: ${PROD_HOST:-app.example.com} + caddy.reverse_proxy: "{{upstreams 80}}" +``` + +Essa configuração: +- Roda 2 réplicas para alta disponibilidade +- Usa uma estratégia de rolling update com rollback automático em caso de falha +- Configura `labels` para HTTPS automático no proxy reverso +- Desabilita a obtenção de certificados HTTPS no próprio container, + já que o proxy se comunica com o container via HTTP. Isso é o `auto_https off`. + +Se você precisa de um banco de dados, adicione-o à stack: + +```yaml +services: + app: + # ... configuração existente ... + + db: + image: postgres:18-alpine + environment: + POSTGRES_DB: myapp + POSTGRES_USER: myapp + POSTGRES_PASSWORD_FILE: /run/secrets/db_password + POSTGRES_INITDB_ARGS: "--locale-provider=icu --icu-locale=und --encoding=UTF8" + volumes: + - db_data:/var/lib/postgresql + networks: + - reverse_proxy_public + deploy: + placement: + constraints: + - node.role == manager + secrets: + - db_password + +volumes: + runtime: + db_data: + +secrets: + db_password: + external: true +``` + +Crie o secret com a senha do banco de dados no servidor: + +```bash +echo "your_secure_password" | docker secret create db_password - +``` + +## Construindo e enviando a imagem + +### Configure o login do Docker na sua máquina local + +Configure o Docker para se autenticar no seu registro de containers: + +```bash +docker login git.example.com +``` + +Informe o seu usuário e a sua senha quando solicitado. + +### Construa a imagem de produção + +Use o Makefile para construir a imagem de produção: + +```bash +make prod-build +``` + +Isso executa o comando definido no Makefile: + +```bash +docker build --file docker/Dockerfile --target prod --pull -t ${IMAGE}:${IMAGE_TAG} . +``` + +O Dockerfile usa um build multi-stage: 1. Instala as dependências do +Composer em um estágio de build 2. Cria uma imagem de produção mínima, só +com os arquivos necessários 3. Roda como um usuário não root (`www-data`) + +### Envie a imagem para o registro + +Envie a imagem construída para o registro de containers: + +```bash +make prod-push +``` + +Isso executa: + +```bash +docker push ${IMAGE}:${IMAGE_TAG} +``` + +## Fazendo deploy no Docker Swarm + +### Configure o acesso SSH + +Configure a autenticação por chave SSH no seu servidor: + +```bash +# Gera uma chave SSH (se você ainda não tiver uma) +ssh-keygen -t ed25519 -C "your_email@example.com" + +# Copia a chave para o seu servidor +ssh-copy-id user@your-server-ip + +# Adiciona o host SSH à sua configuração SSH (~/.ssh/config) +cat >> ~/.ssh/config << EOF +Host docker-web + HostName your-server-ip + User user + IdentityFile ~/.ssh/id_ed25519 +EOF +``` + +### Configure o contexto do Docker + +Crie um contexto do Docker para o deploy remoto: + +```bash +docker context create swarm-prod --docker "host=ssh://docker-web" +``` + +Como alternativa, configure a variável de ambiente `DOCKER_HOST`: + +```bash +export DOCKER_HOST=ssh://docker-web +``` + +### Faça o deploy da aplicação + +Faça o deploy da stack da sua aplicação no Docker Swarm: + +```bash +make prod-deploy +``` + +Isso executa: + +```bash +docker -H ${PROD_SSH} stack deploy --prune --detach=false --with-registry-auth -c docker/compose.yml -c docker/prod/compose.yml ${STACK_NAME} +``` + +A flag `--with-registry-auth` garante que os nós do Swarm consigam baixar +imagens do seu registro privado. + +### Verifique o deploy + +Verifique o status dos seus serviços: + +```bash +docker -H ssh://docker-web service ls +docker -H ssh://docker-web service ps ${STACK_NAME}_app +``` + +Veja os logs: + +```bash +docker -H ssh://docker-web service logs ${STACK_NAME}_app +``` + +## Monitoramento e manutenção + +### Veja os logs do serviço + +```bash +# Mostra todos os logs +docker -H ssh://docker-web service logs -f ${STACK_NAME}_app + +# Mostra as últimas 100 linhas de log +docker -H ssh://docker-web service logs --tail 100 ${STACK_NAME}_app + +# Mostra os logs com timestamps +docker -H ssh://docker-web service logs -t ${STACK_NAME}_app +``` + +### Escale a aplicação + +Ajuste o número de réplicas: + +```bash +docker -H ssh://docker-web service scale ${STACK_NAME}_app=3 +``` + +Ou atualize o valor de `replicas` em `docker/prod/compose.yml` e faça o +deploy de novo. + +### Limites de recursos + +Adicione limites de recursos para evitar que os containers consumam todos os +recursos do servidor. Atualize o `docker/prod/compose.yml`: + +```yaml +services: + app: + # ... configuração existente ... + deploy: + resources: + limits: + cpus: '0.5' + memory: 512M + reservations: + cpus: '0.25' + memory: 256M +``` + +## Considerações de segurança + +### Use Docker secrets para dados sensíveis + +Em vez de variáveis de ambiente, use Docker secrets para informações +sensíveis: + +```bash +# Cria os secrets +echo "database_password" | docker secret create db_password - +echo "api_key" | docker secret create api_key - +``` + +Atualize o `docker/prod/compose.yml`: + +```yaml +services: + app: + secrets: + - db_password + - api_key + +secrets: + db_password: + external: true + api_key: + external: true +``` + +Acesse os secrets na sua aplicação em `/run/secrets/secret_name`. + +### Configure um firewall + +Configure o UFW (Uncomplicated Firewall) no seu servidor: + +```bash +# Libera SSH +sudo ufw allow 22/tcp + +# Libera HTTP e HTTPS +sudo ufw allow 80/tcp +sudo ufw allow 443/tcp + +# Libera as portas do Docker Swarm (se você pretende adicionar mais nós) +sudo ufw allow 2377/tcp +sudo ufw allow 7946/tcp +sudo ufw allow 7946/udp +sudo ufw allow 4789/udp + +# Habilita o firewall +sudo ufw enable +``` + +### Mantenha o sistema atualizado + +Atualize regularmente o seu servidor e o Docker: + +```bash +# Atualiza os pacotes do sistema +sudo apt-get update && sudo apt-get upgrade -y + +# Atualiza as imagens Docker +docker -H ssh://docker-web service update --image ${IMAGE}:${IMAGE_TAG} ${STACK_NAME}_app +``` + +## Solução de problemas + +### O serviço não sobe + +Verifique os eventos e os logs do serviço: + +```bash +docker -H ssh://docker-web service ps ${STACK_NAME}_app --no-trunc +docker -H ssh://docker-web service logs ${STACK_NAME}_app +``` + +Problemas comuns: - **Erros ao baixar a imagem**: verifique a autenticação +no registro com `docker -H ssh://docker-web login` - **Conflitos de porta**: +garanta que nenhum outro serviço esteja usando as portas 80/443 - +**Limitação de recursos**: verifique os recursos disponíveis com `docker -H +ssh://docker-web node ls` + +### Problemas com certificados SSL + +Se o Caddy não consegue obter os certificados: - Verifique se o DNS aponta +para o seu servidor - Verifique se as portas 80 e 443 estão acessíveis pela +internet - Garanta que o e-mail na configuração do Let's Encrypt é válido - +Verifique os logs: `docker -H ssh://docker-web service logs caddy` + +### Problemas de conexão com o registro de containers + +Teste a conectividade com o registro: + +```bash +# Na sua máquina local +docker pull git.example.com/username/myapp:latest + +# No servidor +docker -H ssh://docker-web pull git.example.com/username/myapp:latest +``` + +## Resumo + +Você fez o deploy de uma aplicação Yii no Docker Swarm com: - Um registro de +containers (Forgejo ou Gitea) - HTTPS automático via Caddy - Deploys sem +downtime com rolling updates - Alta disponibilidade com várias réplicas + +Os comandos do Makefile simplificam o fluxo de deploy: - `make prod-build` - +Constrói a imagem de produção - `make prod-push` - Envia para o registro - +`make prod-deploy` - Faz o deploy no Docker Swarm + +Para mais informações, veja: - [Template de aplicação do +Yii](https://github.com/yiisoft/app) - [Documentação do Docker +Swarm](https://docs.docker.com/engine/swarm/) - [Caddy Docker +Proxy](https://github.com/lucaslorentz/caddy-docker-proxy) diff --git a/src/pt-BR/cookbook/deployment/docker-swarm-traefik.md b/src/pt-BR/cookbook/deployment/docker-swarm-traefik.md new file mode 100644 index 00000000..c85d10df --- /dev/null +++ b/src/pt-BR/cookbook/deployment/docker-swarm-traefik.md @@ -0,0 +1,605 @@ +# Fazendo deploy de aplicações Yii no Docker Swarm com Traefik + +Este guia mostra como fazer o deploy de uma aplicação Yii no [Docker +Swarm](https://docs.docker.com/engine/swarm/) a partir de um servidor +vazio, usando o [Traefik](https://traefik.io/traefik) como proxy reverso e +fazendo o deploy a partir de um registro de containers +([Forgejo](https://forgejo.org/) ou [Gitea](https://about.gitea.com/)). + +```mermaid +graph LR + A[Internet] --> B[Proxy reverso: Traefik] + B --> C[app1.example.com] + B --> D[app2.example.com] + + subgraph Docker Swarm Cluster + B + C + D + end +``` + +## Pré-requisitos + +- Um servidor com uma distribuição Linux recém-instalada (recomendado Ubuntu + 22.04 LTS ou mais recente) +- Um nome de domínio apontando para o IP do seu servidor +- Acesso SSH ao seu servidor +- Conhecimento básico de Docker e de ferramentas de linha de comando + +## Preparando o servidor + +### Instale o Docker + +Para as instruções de instalação, veja a [documentação oficial do +Docker](https://docs.docker.com/engine/install/ubuntu/). + +### Inicialize o Docker Swarm + +Inicialize o seu servidor como manager do Docker Swarm: + +```bash +docker swarm init --advertise-addr +``` + +Substitua `` pelo IP público do seu servidor. + +### Configure a rede do proxy reverso + +Crie uma rede overlay dedicada para o proxy reverso se comunicar com os seus +serviços: + +```bash +docker network create --driver=overlay reverse_proxy_public +``` + +## Configurando o Traefik como proxy reverso + +Para fazer o deploy do Traefik como proxy reverso, crie um arquivo +`traefik-stack.yml`: + +```yaml +services: + traefik: + image: traefik:v2.10 + command: + - "--api.insecure=true" + - "--providers.docker=true" + - "--providers.docker.swarmMode=true" + - "--providers.docker.exposedbydefault=false" + - "--entrypoints.web.address=:80" + - "--entrypoints.websecure.address=:443" + - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true" + - "--certificatesresolvers.letsencrypt.acme.email=admin@example.com" + - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" + ports: + - "80:80" + - "443:443" + - "8080:8080" + volumes: + - "/var/run/docker.sock:/var/run/docker.sock:ro" + - "traefik_certificates:/letsencrypt" + networks: + - reverse_proxy_public + deploy: + placement: + constraints: + - node.role == manager + +volumes: + traefik_certificates: + +networks: + reverse_proxy_public: + external: true +``` + +Faça o deploy do Traefik: + +```bash +docker stack deploy -c traefik-stack.yml traefik +``` + +## Configurando um registro de containers + +Você precisa de um registro de containers para guardar as suas imagens +Docker. Escolha uma das opções a seguir. + +### Opção 1: usando o Forgejo + +Para fazer o deploy do Forgejo, crie um arquivo `forgejo-stack.yml`: + +```yaml +services: + forgejo: + image: codeberg.org/forgejo/forgejo:1.21 + ports: + - "3000:3000" + volumes: + - forgejo_data:/data + networks: + - reverse_proxy_public + deploy: + labels: + - "traefik.enable=true" + - "traefik.http.routers.app.rule=Host(`git.example.com`)" + - "traefik.http.routers.app.entrypoints=websecure" + - "traefik.http.routers.app.tls.certresolver=letsencrypt" + - "traefik.http.services.app.loadbalancer.server.port=3000" + +volumes: + forgejo_data: + +networks: + reverse_proxy_public: + external: true +``` + +Faça o deploy do Forgejo: + +```bash +docker stack deploy -c forgejo-stack.yml forgejo +``` + +Substitua `git.example.com` pelo subdomínio desejado. + +Depois do deploy, acesse o Forgejo em `https://git.example.com` e conclua a +configuração inicial. Não esqueça de habilitar o registro de containers nas +configurações. + +### Opção 2: usando o Gitea + +Para fazer o deploy do Gitea, crie um arquivo `gitea-stack.yml`: + +```yaml +services: + gitea: + image: gitea/gitea:latest + ports: + - "3000:3000" + volumes: + - gitea_data:/data + networks: + - reverse_proxy_public + deploy: + labels: + - "traefik.enable=true" + - "traefik.http.routers.app.rule=Host(`git.example.com`)" + - "traefik.http.routers.app.entrypoints=websecure" + - "traefik.http.routers.app.tls.certresolver=letsencrypt" + - "traefik.http.services.app.loadbalancer.server.port=3000" + +volumes: + gitea_data: + +networks: + reverse_proxy_public: + external: true +``` + +Faça o deploy do Gitea: + +```bash +docker stack deploy -c gitea-stack.yml gitea +``` + +Substitua `git.example.com` pelo subdomínio desejado. + +Depois do deploy, acesse o Gitea em `https://git.example.com` e conclua a +configuração inicial. Não esqueça de habilitar o registro de containers nas +configurações. + +## Configurando a sua aplicação Yii + +### Atualize a configuração do Makefile + +O [template de aplicação do Yii](https://github.com/yiisoft/app) inclui um +Makefile com comandos de deploy. Atualize o arquivo `docker/.env` do seu +projeto: + +```bash +STACK_NAME=myapp + +# +# Produção +# + +PROD_HOST=app.example.com +PROD_SSH="ssh://user@your-server-ip" + +IMAGE=git.example.com/username/myapp +IMAGE_TAG=latest +``` + +Substitua os valores: - `STACK_NAME`: um nome único para a stack da sua +aplicação - `PROD_HOST`: o nome de domínio em que a aplicação vai ficar +acessível - `PROD_SSH`: a string de conexão SSH com o seu servidor (formato: +`ssh://user@host`) - `IMAGE`: o caminho completo da imagem do container no +registro - `IMAGE_TAG`: a tag da imagem, normalmente `latest` ou um número +de versão + +### Configure o ambiente de produção + +Atualize o `docker/prod/.env` com as variáveis de ambiente de produção: + +```bash +APP_ENV=prod +YII_DEBUG=false +YII_ENV=prod + +# Configuração do banco de dados +DB_HOST=db +DB_NAME=myapp +DB_USER=myapp +DB_PASSWORD=secure_password_here + +# Adicione outras variáveis específicas do ambiente +``` + +> [!WARNING] +> Nunca faça commit de credenciais sensíveis no controle de versão. Use `docker/prod/override.env` para valores sensíveis e adicione-o ao `.gitignore`. + +### Revise a configuração do Docker Compose de produção + +Ao usar o Traefik, você precisa alterar o `docker/prod/compose.yml` da +aplicação Yii para usar labels do Traefik em vez de labels do Caddy: + +```yaml +services: + app: + image: ${IMAGE}:${IMAGE_TAG} + networks: + - reverse_proxy_public + volumes: + - runtime:/app/runtime + - caddy_data:/data + - caddy_config:/config + env_file: + - path: ./prod/.env + - path: ./prod/override.env + required: false\ + environment: + CADDY_EXTRA_CONFIG: 'auto_https off' + deploy: + replicas: 2 + update_config: + delay: 10s + parallelism: 1 + order: start-first + failure_action: rollback + monitor: 10s + rollback_config: + parallelism: 0 + order: stop-first + restart_policy: + condition: on-failure + delay: 5s + max_attempts: 3 + window: 120s + labels: + - "traefik.enable=true" + - "traefik.http.routers.app.rule=Host(`${PROD_HOST:-app.example.com}`)" + - "traefik.http.routers.app.entrypoints=websecure" + - "traefik.http.routers.app.tls.certresolver=letsencrypt" + - "traefik.http.services.app.loadbalancer.server.port=80" +``` + +Essa configuração: +- Roda 2 réplicas para alta disponibilidade +- Usa uma estratégia de rolling update com rollback automático em caso de falha +- Configura `labels` para HTTPS automático no proxy reverso +- Desabilita a obtenção de certificados HTTPS no próprio container, + já que o proxy se comunica com o container via HTTP. Isso é o `auto_https off`. + +Se você precisa de um banco de dados, adicione-o à stack: + +```yaml +services: + app: + # ... configuração existente ... + + db: + image: postgres:18-alpine + environment: + POSTGRES_DB: myapp + POSTGRES_USER: myapp + POSTGRES_PASSWORD_FILE: /run/secrets/db_password + POSTGRES_INITDB_ARGS: "--locale-provider=icu --icu-locale=und --encoding=UTF8" + volumes: + - db_data:/var/lib/postgresql + networks: + - reverse_proxy_public + deploy: + placement: + constraints: + - node.role == manager + secrets: + - db_password + +volumes: + runtime: + db_data: + +secrets: + db_password: + external: true +``` + +Crie o secret com a senha do banco de dados no servidor: + +```bash +echo "your_secure_password" | docker secret create db_password - +``` + +## Construindo e enviando a imagem + +### Configure o login do Docker na sua máquina local + +Configure o Docker para se autenticar no seu registro de containers: + +```bash +docker login git.example.com +``` + +Informe o seu usuário e a sua senha quando solicitado. + +### Construa a imagem de produção + +Use o Makefile para construir a imagem de produção: + +```bash +make prod-build +``` + +Isso executa o comando definido no Makefile: + +```bash +docker build --file docker/Dockerfile --target prod --pull -t ${IMAGE}:${IMAGE_TAG} . +``` + +O Dockerfile usa um build multi-stage: 1. Instala as dependências do +Composer em um estágio de build 2. Cria uma imagem de produção mínima, só +com os arquivos necessários 3. Roda como um usuário não root (`www-data`) + +### Envie a imagem para o registro + +Envie a imagem construída para o registro de containers: + +```bash +make prod-push +``` + +Isso executa: + +```bash +docker push ${IMAGE}:${IMAGE_TAG} +``` + +## Fazendo deploy no Docker Swarm + +### Configure o acesso SSH + +Configure a autenticação por chave SSH no seu servidor: + +```bash +# Gera uma chave SSH (se você ainda não tiver uma) +ssh-keygen -t ed25519 -C "your_email@example.com" + +# Copia a chave para o seu servidor +ssh-copy-id user@your-server-ip + +# Adiciona o host SSH à sua configuração SSH (~/.ssh/config) +cat >> ~/.ssh/config << EOF +Host docker-web + HostName your-server-ip + User user + IdentityFile ~/.ssh/id_ed25519 +EOF +``` + +### Configure o contexto do Docker + +Crie um contexto do Docker para o deploy remoto: + +```bash +docker context create swarm-prod --docker "host=ssh://docker-web" +``` + +Como alternativa, configure a variável de ambiente `DOCKER_HOST`: + +```bash +export DOCKER_HOST=ssh://docker-web +``` + +### Faça o deploy da aplicação + +Faça o deploy da stack da sua aplicação no Docker Swarm: + +```bash +make prod-deploy +``` + +Isso executa: + +```bash +docker -H ${PROD_SSH} stack deploy --prune --detach=false --with-registry-auth -c docker/compose.yml -c docker/prod/compose.yml ${STACK_NAME} +``` + +A flag `--with-registry-auth` garante que os nós do Swarm consigam baixar +imagens do seu registro privado. + +### Verifique o deploy + +Verifique o status dos seus serviços: + +```bash +docker -H ssh://docker-web service ls +docker -H ssh://docker-web service ps ${STACK_NAME}_app +``` + +Veja os logs: + +```bash +docker -H ssh://docker-web service logs ${STACK_NAME}_app +``` + +## Monitoramento e manutenção + +### Veja os logs do serviço + +```bash +# Mostra todos os logs +docker -H ssh://docker-web service logs -f ${STACK_NAME}_app + +# Mostra as últimas 100 linhas de log +docker -H ssh://docker-web service logs --tail 100 ${STACK_NAME}_app + +# Mostra os logs com timestamps +docker -H ssh://docker-web service logs -t ${STACK_NAME}_app +``` + +### Escale a aplicação + +Ajuste o número de réplicas: + +```bash +docker -H ssh://docker-web service scale ${STACK_NAME}_app=3 +``` + +Ou atualize o valor de `replicas` em `docker/prod/compose.yml` e faça o +deploy de novo. + +### Limites de recursos + +Adicione limites de recursos para evitar que os containers consumam todos os +recursos do servidor. Atualize o `docker/prod/compose.yml`: + +```yaml +services: + app: + # ... configuração existente ... + deploy: + resources: + limits: + cpus: '0.5' + memory: 512M + reservations: + cpus: '0.25' + memory: 256M +``` + +## Considerações de segurança + +### Use Docker secrets para dados sensíveis + +Em vez de variáveis de ambiente, use Docker secrets para informações +sensíveis: + +```bash +# Cria os secrets +echo "database_password" | docker secret create db_password - +echo "api_key" | docker secret create api_key - +``` + +Atualize o `docker/prod/compose.yml`: + +```yaml +services: + app: + secrets: + - db_password + - api_key + +secrets: + db_password: + external: true + api_key: + external: true +``` + +Acesse os secrets na sua aplicação em `/run/secrets/secret_name`. + +### Configure um firewall + +Configure o UFW (Uncomplicated Firewall) no seu servidor: + +```bash +# Libera SSH +sudo ufw allow 22/tcp + +# Libera HTTP e HTTPS +sudo ufw allow 80/tcp +sudo ufw allow 443/tcp + +# Libera as portas do Docker Swarm (se você pretende adicionar mais nós) +sudo ufw allow 2377/tcp +sudo ufw allow 7946/tcp +sudo ufw allow 7946/udp +sudo ufw allow 4789/udp + +# Habilita o firewall +sudo ufw enable +``` + +### Mantenha o sistema atualizado + +Atualize regularmente o seu servidor e o Docker: + +```bash +# Atualiza os pacotes do sistema +sudo apt-get update && sudo apt-get upgrade -y + +# Atualiza as imagens Docker +docker -H ssh://docker-web service update --image ${IMAGE}:${IMAGE_TAG} ${STACK_NAME}_app +``` + +## Solução de problemas + +### O serviço não sobe + +Verifique os eventos e os logs do serviço: + +```bash +docker -H ssh://docker-web service ps ${STACK_NAME}_app --no-trunc +docker -H ssh://docker-web service logs ${STACK_NAME}_app +``` + +Problemas comuns: - **Erros ao baixar a imagem**: verifique a autenticação +no registro com `docker -H ssh://docker-web login` - **Conflitos de porta**: +garanta que nenhum outro serviço esteja usando as portas 80/443 - +**Limitação de recursos**: verifique os recursos disponíveis com `docker -H +ssh://docker-web node ls` + +### Problemas com certificados SSL + +Se o Traefik não consegue obter os certificados: - Verifique se o DNS aponta +para o seu servidor - Verifique se as portas 80 e 443 estão acessíveis pela +internet - Garanta que o e-mail na configuração do Let's Encrypt é válido - +Verifique os logs: `docker -H ssh://docker-web service logs traefik_traefik` + +### Problemas de conexão com o registro de containers + +Teste a conectividade com o registro: + +```bash +# Na sua máquina local +docker pull git.example.com/username/myapp:latest + +# No servidor +docker -H ssh://docker-web pull git.example.com/username/myapp:latest +``` + +## Resumo + +Você fez o deploy de uma aplicação Yii no Docker Swarm com: - Um registro de +containers (Forgejo ou Gitea) - HTTPS automático via Traefik - Deploys sem +downtime com rolling updates - Alta disponibilidade com várias réplicas + +Os comandos do Makefile simplificam o fluxo de deploy: - `make prod-build` - +Constrói a imagem de produção - `make prod-push` - Envia para o registro - +`make prod-deploy` - Faz o deploy no Docker Swarm + +Para mais informações, veja: - [Template de aplicação do +Yii](https://github.com/yiisoft/app) - [Documentação do Docker +Swarm](https://docs.docker.com/engine/swarm/) - [Documentação do +Traefik](https://doc.traefik.io/traefik/) diff --git a/src/pt-BR/cookbook/deployment/docker-swarm.md b/src/pt-BR/cookbook/deployment/docker-swarm.md new file mode 100644 index 00000000..8856bd8c --- /dev/null +++ b/src/pt-BR/cookbook/deployment/docker-swarm.md @@ -0,0 +1,4 @@ +# Fazendo deploy de aplicações Yii no Docker Swarm + +- [Usando Caddy](docker-swarm-caddy.md) +- [Usando Traefik](docker-swarm-traefik.md) diff --git a/src/pt-BR/cookbook/deployment/rolling-update-migrations.md b/src/pt-BR/cookbook/deployment/rolling-update-migrations.md new file mode 100644 index 00000000..5d0c2488 --- /dev/null +++ b/src/pt-BR/cookbook/deployment/rolling-update-migrations.md @@ -0,0 +1,204 @@ +# Aplicando migrations durante rolling updates + +Rolling updates mantêm instâncias antigas e novas da aplicação rodando ao +mesmo tempo. Isso torna as mudanças no banco de dados mais delicadas do que +em um deploy em um único servidor: as duas versões da aplicação precisam +funcionar com o mesmo banco de dados enquanto o deploy está em andamento. + +A regra segura é: + +1. Aplique mudanças no banco de dados que sejam compatíveis com o código + atual de produção. +2. Faça o deploy do código que passa a usar essas mudanças no banco de + dados. +3. Remova estruturas obsoletas do banco de dados só depois que todas as + instâncias antigas da aplicação tiverem saído. + +Isso costuma ser chamado de padrão expand and contract. Primeiro expanda o +schema para que as duas versões possam usá-lo. Depois atualize o código da +aplicação. Por fim, contraia o schema em um deploy posterior. + +## Por que isso importa + +Durante um rolling update, as requisições podem ser atendidas por versões +diferentes da aplicação: + +- código antigo, que não conhece o novo schema; +- código novo, que espera o novo schema; +- workers em segundo plano, que podem ficar atrás das instâncias web; +- comandos agendados, que podem rodar durante o deploy. + +Se uma migration remove ou renomeia uma coluna antes que todas as instâncias +antigas parem de usá-la, o código antigo falha. Se o código que exige uma +coluna nova vai para produção antes de a coluna existir, o código novo +falha. O plano de migrations precisa manter válido cada estado +intermediário. + +## Fluxo de deploy + +Use este fluxo para mudanças que não podem interromper o tráfego de +produção: + +1. Crie uma migration que apenas adiciona schema compatível. +2. Aplique essa migration em produção enquanto a versão atual da aplicação + ainda está rodando. +3. Faça o deploy da nova versão da aplicação com um rolling update. +4. Verifique se todas as instâncias e workers rodam a nova versão. +5. Em uma release posterior, aplique as migrations de limpeza que removem + colunas, índices, tabelas ou código de compatibilidade antigos. + +Em aplicações Yii, rode as migrations com o mesmo comando que você usa nos +deploys normais, por exemplo: + +```shell +./yii migrate +``` + +Rode as migrations a partir de um único job de deploy ou de um container de +console dedicado. Não deixe cada instância do rolling update rodar +migrations na inicialização. + +## Adicionando uma coluna + +Adicionar uma coluna que aceita nulo normalmente é compatível com o código +antigo: + +```php +public function up(MigrationBuilder $b): void +{ + $cb = $b->columnBuilder(); + + $b->addColumn('user', 'display_name', $cb::string()); +} +``` + +Depois, faça o deploy do código que grava e lê `display_name`. + +Se a coluna precisar ser obrigatória no futuro: + +1. Adicione-a como coluna que aceita nulo. +2. Faça o deploy do código que a preenche em linhas novas e atualizadas. +3. Preencha as linhas existentes em lotes. +4. Adicione uma restrição `NOT NULL` em uma migration posterior. + +Não adicione uma coluna `NOT NULL` sem um valor padrão no banco de dados +enquanto o código antigo ainda insere linhas sem essa coluna. + +## Renomeando uma coluna + +Renomear não é compatível, porque o código antigo usa o nome antigo e o +código novo usa o nome novo. Em vez disso, faça a mudança ao longo de várias +releases: + +1. Adicione a nova coluna. +2. Preencha-a a partir da coluna antiga. +3. Faça o deploy do código que grava nas duas colunas e lê a nova coluna, + com fallback para a antiga. +4. Espere até que todo o código antigo tenha saído. +5. Faça o deploy do código que usa só a nova coluna. +6. Remova a coluna antiga em uma migration de limpeza posterior. + +A mesma abordagem funciona para mover dados para outra tabela. + +## Mudando o tipo de uma coluna + +Mudar o tipo de uma coluna no lugar pode travar a tabela ou quebrar o código +antigo ou o novo. Prefira uma coluna nova: + +1. Adicione uma coluna com o tipo desejado. +2. Preencha-a em lotes. +3. Faça o deploy do código que grava nas duas colunas. +4. Faça o deploy do código que lê a nova coluna. +5. Remova a coluna antiga depois que todo o código usar a nova. + +Em tabelas pequenas, mudar o tipo no lugar pode ser aceitável. Em tabelas de +produção com tráfego, verifique o comportamento de locks no motor e na +versão exatos do banco de dados antes de aplicar a mudança. + +## Removendo colunas e tabelas + +Remover é uma etapa de limpeza, não a primeira etapa: + +1. Faça o deploy do código que não lê nem grava mais a coluna ou a tabela. +2. Confirme que as instâncias antigas da aplicação, os workers e os comandos + agendados pararam. +3. Confirme que nenhum relatório externo ou script de manutenção depende + dela. +4. Remova-a em uma migration separada. + +Isso torna o rollback mais seguro. Se você precisar fazer rollback do código +da aplicação antes da limpeza, o schema antigo ainda está disponível. + +## Adicionando índices e restrições + +Índices e restrições podem ser logicamente compatíveis, mas arriscados na +operação, porque podem travar tabelas. + +Para índices: + +- use criação de índice online quando o banco de dados suportar; +- no PostgreSQL, considere `CREATE INDEX CONCURRENTLY` em uma migration ou + comando que não esteja dentro de uma transação; +- no MySQL e no MariaDB, verifique se a operação pode usar online DDL para a + sua tabela e o seu motor. + +Para restrições: + +- limpe os dados inválidos antes de adicionar a restrição; +- adicione a restrição só depois que o código em produção a respeitar; +- no PostgreSQL, considere adicionar chaves estrangeiras e check constraints + como `NOT VALID` e validá-las separadamente depois. + +Mantenha a criação de índices e as validações demoradas separadas de +mudanças de schema não relacionadas, para facilitar o monitoramento e novas +tentativas. + +## Migrations de dados + +Migrations de dados que mexem em muitas linhas precisam ser seguras para +rodar com a aplicação no ar: + +- torne-as idempotentes, para que rodar de novo não corrompa os dados; +- processe as linhas em lotes pequenos; +- evite depender da lógica atual de serviços ou entidades da aplicação, + porque essa lógica muda com o tempo; +- prefira valores compatíveis com o futuro, que tanto o código antigo quanto + o novo consigam tratar; +- guarde o progresso quando um preenchimento for grande demais para uma + única execução de migration. + +Para preenchimentos muito grandes, use um comando de console ou um job em +segundo plano depois da migration de schema. A migration de schema deve +preparar o banco de dados; o processo em segundo plano deve mover os dados +aos poucos. + +## Revertendo + +Em deploys com rolling update em produção, reverter uma migration destrutiva +costuma ser mais difícil do que fazer o deploy de uma migration +corretiva. Trate os métodos `down()` de operações destrutivas como uma +conveniência para o desenvolvimento local, não como o principal plano de +rollback em produção. + +Um plano de rollback prático é: + +- antes da limpeza, faça rollback apenas do código, porque o schema antigo + ainda existe; +- depois da limpeza, faça o deploy de uma nova migration que restaure a + estrutura ou a compatibilidade necessária; +- restaure um backup só quando dados foram realmente perdidos e nenhum + reparo por uma nova migration é possível. + +## Checklist + +Antes de aplicar uma migration em produção, verifique que: + +- o código atual de produção funciona depois da migration; +- o código novo funciona antes e depois de todas as instâncias serem + atualizadas; +- workers antigos e comandos agendados foram considerados; +- inserts e updates mantêm as colunas obrigatórias válidas em todas as fases + do deploy; +- operações de schema demoradas não vão bloquear o tráfego de produção de + forma inesperada; +- a limpeza acontece em uma release separada, depois que o rollout terminou. diff --git a/src/pt-BR/cookbook/disabling-csrf-protection.md b/src/pt-BR/cookbook/disabling-csrf-protection.md new file mode 100644 index 00000000..669e4439 --- /dev/null +++ b/src/pt-BR/cookbook/disabling-csrf-protection.md @@ -0,0 +1,156 @@ +# Desativando a proteção CSRF + +## O que é a proteção CSRF? + +A proteção contra Cross-Site Request Forgery (CSRF) é um mecanismo de +segurança que impede sites maliciosos de fazer requisições não autorizadas +em nome de usuários autenticados. O Yii3 inclui proteção CSRF nativa por +meio do middleware `Yiisoft\Yii\Web\Middleware\CsrfTokenMiddleware`. + +Para entender a fundo os ataques CSRF e os mecanismos de proteção, veja a +seção [Boas práticas de +segurança](../guide/security/best-practices.md#evitando-csrf) do guia +principal. + +## Quando desativar a proteção CSRF + +Embora a proteção CSRF deva, em geral, continuar ativada em aplicações web, +há cenários específicos em que você pode precisar desativá-la: + +### Quando sistemas externos não conseguem fornecer tokens CSRF + +Ao construir APIs ou tratar requisições automatizadas de sistemas externos, +a proteção CSRF pode atrapalhar requisições legítimas, já que esses sistemas +não conseguem fornecer tokens CSRF válidos: + +- **Integrações de terceiros**: serviços externos não conseguem fornecer + tokens CSRF válidos +- **Aplicativos móveis**: apps móveis nativos normalmente não usam cookies + ou sessões da mesma forma que os navegadores +- **Comunicação entre servidores**: endpoints de API projetados para + comunicação máquina a máquina +- **Processadores de pagamento**: PayPal, Stripe e outros sistemas de + pagamento enviam notificações por webhook +- **Sistemas de controle de versão**: webhooks do GitHub e do GitLab para + pipelines de CI/CD +- **Redes sociais**: notificações por webhook do Twitter e do Facebook +- **Serviços de comunicação**: integrações com bots do Slack e do Discord + +## Como desativar a proteção CSRF + +Primeiro, remova o middleware de CSRF da lista principal de middlewares da +aplicação em `config/web/di/application.php`: + +```php +return [ + Application::class => [ + '__construct()' => [ + 'dispatcher' => DynamicReference::to([ + 'class' => MiddlewareDispatcher::class, + 'withMiddlewares()' => [ + [ + ErrorCatcher::class, + SessionMiddleware::class, + CsrfTokenMiddleware::class, // <- Remova esta linha +``` + +Agora, se você precisar manter o CSRF ativo para rotas ou grupos de rotas +específicos, adicione o middleware `CsrfTokenMiddleware` na configuração do +router em `config/common/routes.php`. Para um grupo, fica assim: + +```php +return [ + Group::create() + ->middleware(CsrfTokenMiddleware::class) + ->routes( +``` + +Para uma única rota, você pode adicionar o middleware diretamente nela: + +```php +Route::methods([Method::GET, Method::POST], '/say[/{test}]') + ->action(\App\Controller\Echo\Action::class) + ->name('echo/say') + ->middleware(CsrfTokenMiddleware::class) +``` + + +## Considerações de segurança + +Ao desativar a proteção CSRF, tenha em mente estas considerações de +segurança: + +### Métodos alternativos de autenticação + +Para endpoints de API, implemente mecanismos de autenticação adequados: + +- **Chaves de API**: exija chaves de API para autenticação +- **Bearer tokens**: use JWT ou autenticação similar baseada em token +- **OAuth 2.0**: implemente OAuth 2.0 para acesso de terceiros +- **Lista de IPs permitidos**: restrinja o acesso de webhooks a endereços IP + conhecidos + +### Validação da requisição + +Implemente validação adicional para requisições sem proteção CSRF: + +- **Verificação de assinatura**: verifique assinaturas de webhooks (por + exemplo, o X-Hub-Signature do GitHub) +- **Validação de timestamp**: confira o timestamp das requisições para + evitar ataques de replay +- **Rate limiting**: implemente limite de requisições para evitar abuso +- **Validação de entrada**: valide rigorosamente todos os parâmetros de + entrada + +### Exemplo: verificação de assinatura de webhook + +```php +getHeaderLine('X-Webhook-Signature'); + $payload = (string) $request->getBody(); + $expectedSignature = hash_hmac('sha256', $payload, $this->webhookSecret); + + if (!hash_equals($signature, $expectedSignature)) { + throw new \RuntimeException('Invalid webhook signature'); + } + + // Processa o payload do webhook + // ... + } +} +``` + +## Boas práticas + +1. **Minimize a exposição**: desative a proteção CSRF apenas onde for + realmente necessário +2. **Use HTTPS**: sempre use HTTPS para endpoints de API e webhooks +3. **Monitore os logs**: registre em log todas as requisições aos endpoints + de API para monitoramento de segurança +4. **Auditorias de segurança regulares**: revise periodicamente seus + endpoints de API e as medidas de segurança deles +5. **Documentação**: documente claramente quais endpoints têm a proteção + CSRF desativada e por quê + +## Conclusão + +Embora a proteção CSRF seja essencial para aplicações web, há cenários +legítimos em que ela precisa ser desativada, principalmente para APIs +externas e webhooks. Ao desativá-la, sempre implemente medidas de segurança +alternativas e siga as boas práticas de segurança para manter a segurança +geral da sua aplicação. + +Lembre-se de que desativar a proteção CSRF aumenta os riscos de segurança, +então é essencial avaliar com cuidado e implementar corretamente as medidas +de segurança alternativas. diff --git a/src/pt-BR/cookbook/index.md b/src/pt-BR/cookbook/index.md new file mode 100644 index 00000000..06162bc6 --- /dev/null +++ b/src/pt-BR/cookbook/index.md @@ -0,0 +1,44 @@ +# Cookbook da comunidade Yii3 + +O Cookbook da comunidade Yii3 é um livro de código aberto cheio de dicas e +truques sobre o framework PHP [Yii3](https://www.yiiframework.com/). + +- A comunidade Yii escreve o cookbook. +- Membros do time principal do Yii fazem a curadoria e a edição. + +Fique à vontade para enviar seus próprios textos via pull request. Os +membros do time vão revisar, dar feedback e fazer o merge da melhor forma +possível. + +Este livro segue os [Termos da documentação do +Yii](https://www.yiiframework.com/license#docs). + +--- + +- [Prefácio](preface.md) +- [Fazendo requisições HTTP](making-http-requests.md) +- [Usando htmx para recarregar partes da + página](using-htmx-for-partial-reloads.md) +- [Desativando a proteção CSRF](disabling-csrf-protection.md) +- [Integração com o Sentry](sentry-integration.md) +- [Usando um template de migration + personalizado](custom-migration-template.md) +- [Type casters personalizados para o + hydrator](custom-hydrator-type-casters.md) +- [Usando o Yii em aplicações de + terceiros](using-yii-in-third-party-apps.md) +- [Integrações com terceiros](third-party-integrations/index.md) +- [Trabalhando no Windows](working-on-windows.md) +- [Abrindo arquivos direto no PhpStorm](opening-files-in-phpstorm.md) +- [Configurando o Xdebug](configuring-xdebug.md) +- [Configurando servidores web](configuring-webservers/general.md) +- [Estruturando o código por caso de uso com vertical + slices](organizing-code/structuring-by-use-case-with-vertical-slices.md) +- [Domínio](organizing-code/domain.md) +- [Componentes de serviço](organizing-code/service.md) +- [Deploy com Docker Swarm](deployment/docker-swarm.md) +- [Deploy de aplicações Yii com Angie Docker + Proxy](deployment/angie-docker-proxy.md) +- [Configurando uma aplicação para autoscaling](deployment/autoscaling.md) +- [Aplicando migrations durante rolling + updates](deployment/rolling-update-migrations.md) diff --git a/src/pt-BR/cookbook/making-http-requests.md b/src/pt-BR/cookbook/making-http-requests.md new file mode 100644 index 00000000..594d41ab --- /dev/null +++ b/src/pt-BR/cookbook/making-http-requests.md @@ -0,0 +1,210 @@ +# Fazendo requisições HTTP + +O Yii não inclui uma implementação própria de cliente HTTP. Use um cliente +que implemente a [PSR-18](https://www.php-fig.org/psr/psr-18/) e dependa das +interfaces PSR no código da sua aplicação. + +Esta receita usa o [Guzzle](https://docs.guzzlephp.org/) como cliente +HTTP. O Guzzle fornece um cliente PSR-18 e usa mensagens PSR-7. + +## Instalação + +Instale o Guzzle: + +```shell +composer require guzzlehttp/guzzle +``` + +O pacote instala as interfaces HTTP da PSR e o `guzzlehttp/psr7`, que +fornece mensagens PSR-7 e factories PSR-17. + +## Configure o container + +Crie `config/common/di/http-client.php`: + +```php + [ + 'class' => Client::class, + '__construct()' => [ + 'config' => [ + 'timeout' => 10.0, + 'connect_timeout' => 3.0, + ], + ], + ], + + HttpFactory::class => HttpFactory::class, + RequestFactoryInterface::class => Reference::to(HttpFactory::class), + ResponseFactoryInterface::class => Reference::to(HttpFactory::class), + StreamFactoryInterface::class => Reference::to(HttpFactory::class), + UriFactoryInterface::class => Reference::to(HttpFactory::class), +]; +``` + +Use `ClientInterface` para enviar requisições e as factories PSR-17 para +criar requisições, streams e URIs. + +## Envie uma requisição GET + +Injete `Psr\Http\Client\ClientInterface` e +`Psr\Http\Message\RequestFactoryInterface` no serviço que conversa com a API +externa: + +```php + + */ + public function latest(string $owner, string $repository): array + { + $request = $this->requestFactory + ->createRequest( + 'GET', + sprintf( + 'https://api.github.com/repos/%s/%s/releases/latest', + rawurlencode($owner), + rawurlencode($repository), + ), + ) + ->withHeader('Accept', 'application/vnd.github+json'); + + try { + $response = $this->httpClient->sendRequest($request); + } catch (ClientExceptionInterface $e) { + throw new RuntimeException('GitHub request failed.', previous: $e); + } + + if ($response->getStatusCode() !== 200) { + throw new RuntimeException(sprintf( + 'GitHub returned HTTP %d.', + $response->getStatusCode(), + )); + } + + return json_decode((string) $response->getBody(), true, 512, JSON_THROW_ON_ERROR); + } +} +``` + +Clientes PSR-18 lançam `ClientExceptionInterface` para erros no envio da +requisição. Códigos de status HTTP como `404` e `500` são respostas válidas, +então verifique o código de status no seu serviço. + +## Envie JSON + +Use `StreamFactoryInterface` quando precisar de um corpo na requisição: + +```php + $payload + */ + public function send(array $payload): void + { + $body = $this->streamFactory->createStream(json_encode($payload, JSON_THROW_ON_ERROR)); + + $request = $this->requestFactory + ->createRequest('POST', 'https://api.example.com/webhooks') + ->withHeader('Content-Type', 'application/json') + ->withHeader('Accept', 'application/json') + ->withBody($body); + + $this->httpClient->sendRequest($request); + } +} +``` + +## Testes + +Para testes unitários, passe um cliente configurado com o `MockHandler` do +Guzzle: + +```php + '1.0.0'], JSON_THROW_ON_ERROR)), + ]); + + $client = new Client(['handler' => HandlerStack::create($handler)]); + $factory = new HttpFactory(); + + $releaseClient = new ReleaseClient($client, $factory); + + $release = $releaseClient->latest('yiisoft', 'docs'); + + $this->assertSame('1.0.0', $release['tag_name']); + } +} +``` + +## Quando usar o Guzzle diretamente + +Dependa das interfaces PSR nos serviços comuns da aplicação. Use +`GuzzleHttp\Client` diretamente em código de infraestrutura que precise de +recursos exclusivos do Guzzle, como requisições assíncronas, handler stacks +ou middleware. diff --git a/src/pt-BR/cookbook/opening-files-in-phpstorm.md b/src/pt-BR/cookbook/opening-files-in-phpstorm.md new file mode 100644 index 00000000..e08aa0c5 --- /dev/null +++ b/src/pt-BR/cookbook/opening-files-in-phpstorm.md @@ -0,0 +1,132 @@ +# Abrindo arquivos diretamente no PhpStorm + +As páginas de erro do Yii podem mostrar links que abrem os arquivos do stack +trace no PhpStorm, na linha que falhou. Isso é útil no desenvolvimento +local, quando a página de erro roda no navegador e o projeto está aberto na +IDE. + +## Verifique os links do Toolbox + +O PhpStorm suporta URLs do Toolbox que usam o protocolo `jetbrains://`. Para obter o valor de `project` e o formato do caminho, +clique com o botão direito em um arquivo do projeto na janela Project e selecione **Copy Path/Reference** > **Toolbox URL**. +Se a URL copiada tiver `origin`, mantenha o parâmetro `origin` e o valor dele nos seus links. + +No Linux, verifique se o Toolbox registrou o handler do protocolo: + +```shell +xdg-mime query default x-scheme-handler/jetbrains +``` + +O comando deve imprimir um arquivo desktop do Toolbox ou do daemon da +JetBrains, por exemplo `jetbrainsd.desktop`. + +O PhpStorm deve estar rodando com o projeto aberto quando você clicar nos +links do stack trace. + +## Configure os links do stack trace + +O template de aplicação do Yii configura o +`Yiisoft\ErrorHandler\Renderer\HtmlRenderer` em +`config/common/di/error-handler.php`. Ele lê um parâmetro `traceLink` e o +usa nos links de arquivos do stack trace. + +Adicione o parâmetro em `config/common/params.php`: + +```php + 'jetbrains://phpstorm/navigate/reference?project=my-app&path={file}:{line}', + // Outros parâmetros. +]; +``` + +Substitua `my-app` pelo valor de `project` da URL do Toolbox. Se a URL do +Toolbox usar `origin`, mantenha `origin` no template do link e use o valor +dele. + +Depois disso, abra uma página de erro em modo debug e clique em um link de +arquivo no stack trace. + +## Mapeie os caminhos do Docker para os caminhos do host + +Quando a aplicação roda no Docker, os stack traces geralmente contêm +caminhos do container, como `/app/src/...`. O PhpStorm precisa do caminho +correspondente no host. + +Defina `APP_HOST_PATH` em `docker/dev/override.env` com o caminho do projeto +na máquina host. Defina `APP_IDE_PROJECT` com o valor de `project` de uma +URL do Toolbox. Se a URL usar `origin`, guarde o valor de `origin` e use +`origin` no template final da URL: + +```dotenv +APP_HOST_PATH=/home/user/projects/my-app +APP_IDE_PROJECT=my-app +``` + +O `docker/dev/override.env` é para configurações específicas de cada +desenvolvedor e não deve ser commitado. Veja [Arquivos env de +override](../guide/tutorial/docker.md#arquivos-env-de-override) para mais +detalhes. + +Nos parâmetros da aplicação, exponha esses valores de ambiente como +`$params['app']['hostPath']` e `$params['app']['ideProject']`. + +Com o template de aplicação padrão, `/app/src/Web/HomePage/Action.php` será +linkado como `/home/user/projects/my-app/src/Web/HomePage/Action.php`. + +## Configure o `HtmlRenderer` manualmente + +Se a sua aplicação não tiver a configuração `error-handler.php` do template, +configure o `HtmlRenderer` diretamente: + +```php + [ + '__construct()' => [ + 'traceLink' => 'jetbrains://phpstorm/navigate/reference?project=my-app&path={file}:{line}', + ], + ], +]; +``` + +Para o Docker, use uma closure para mapear o caminho do container para o +caminho do host: + +```php + [ + '__construct()' => [ + 'traceLink' => static function (string $file, ?int $line) use ($hostPath, $project): string { + $file = preg_replace('~^/app/~', $hostPath, $file); + $path = $line === null ? $file : $file . ':' . $line; + + return str_replace( + ['{project}', '{path}'], + [$project, $path], + 'jetbrains://phpstorm/navigate/reference?project={project}&path={path}', + ); + }, + ], + ], +]; +``` diff --git a/src/pt-BR/cookbook/organizing-code/domain.md b/src/pt-BR/cookbook/organizing-code/domain.md new file mode 100644 index 00000000..88908b85 --- /dev/null +++ b/src/pt-BR/cookbook/organizing-code/domain.md @@ -0,0 +1,89 @@ +# Domínio + +O domínio, ou modelo de domínio, é o que torna o projeto único. Com os requisitos e a terminologia do problema a ser resolvido +em mente (o contexto do problema), você constrói uma abstração composta por entidades, seus relacionamentos e a lógica que +opera essas entidades. Para focar na parte complexa do problema, o domínio, idealmente, fica separado da + parte de infraestrutura do sistema (como salvar dados no banco de dados, como montar a resposta HTTP etc.). + +> [!NOTE] +> Esse isolamento é adequado para sistemas complexos. Se o domínio do seu projeto é basicamente criar/ler/atualizar/excluir +> um conjunto de registros sem muita lógica complexa, não faz sentido aplicar uma solução complexa a um problema simples. +> Os conceitos individuais de design de domínio abaixo podem ser aplicados separadamente, então vale conferi-los mesmo que o seu +> projeto não seja tão complicado. + +## Bounded context + +É quase impossível construir um modelo que resolva vários problemas sem que +ele mesmo fique complicado demais. Por isso, é uma boa prática dividir o +domínio em vários casos de uso e ter um modelo separado para cada um. Esses +modelos separados são chamados de "bounded contexts". + +## Blocos de construção + +Existem vários blocos de construção normalmente usados para descrever +modelos de domínio. Não é obrigatório usar todos. + +### Entidade + +Entidade é um objeto identificável de forma única, como um usuário, um +produto, um pagamento etc. Ao comparar entidades, você verifica o ID, não os +valores dos atributos. Se dois objetos têm atributos diferentes, mas o mesmo +ID, eles são considerados a mesma coisa. + +### Value object + +Um value object descreve um objeto por suas características. Por exemplo, um +preço composto por valor e moeda. Ao comparar esses objetos, você verifica +os valores de fato. Se eles coincidem, os objetos são considerados iguais. + +### Agregado + +Agregado é um conjunto de objetos de domínio, como entidades e value +objects, e dados adicionais que podem ser tratados como uma única +unidade. Ele geralmente representa um objeto composto do modelo de domínio, +como um pedido de loja ou o dossiê de uma pessoa no RH. + +Um dos componentes de um agregado é chamado de raiz. A raiz identifica o +agregado como um todo e deve ser usada para acessá-lo. + +### Evento de domínio + +Um agregado, ao ser processado, pode disparar eventos. Por exemplo, quando +um pedido é confirmado, o evento `OrderConfirmed` é disparado para que +outras partes do sistema possam reagir a ele. + +### Data transfer object + +Data transfer object, ou DTO, é um objeto cujo único propósito é guardar +dados como estão. Ele é comumente usado para passar dados entre diferentes +serviços. + +### Serviço + +Serviço é uma classe que contém uma operação independente dentro do contexto +do seu modelo de domínio. Veja "[componentes de serviço](service.md)". + +### Repositório + +A tarefa do repositório é abstrair como os objetos de domínio são +obtidos. Ele geralmente é dividido em duas partes: uma interface, que fica +na camada de domínio, e uma implementação, que fica na camada de +infraestrutura. Dessa forma, o domínio não se importa com como os dados são +obtidos e salvos e pode se concentrar na lógica de negócio complicada. + +O repositório geralmente é implementado como um serviço. + +### Instanciando os blocos de construção + +Entidades, value objects, agregados e eventos de domínio não são serviços e +não devem ser instanciados pelo container de DI. Use `new` para criá-los. + +## Referências + +- [BoundedContext, por Martin + Fowler](https://martinfowler.com/bliki/BoundedContext.html) +- [ValueObject, por Martin + Fowler](https://martinfowler.com/bliki/ValueObject.html) +- [Aggregate, por Martin + Fowler](https://martinfowler.com/bliki/DDD_Aggregate.html) + diff --git a/src/pt-BR/cookbook/organizing-code/service.md b/src/pt-BR/cookbook/organizing-code/service.md new file mode 100644 index 00000000..e2a1c994 --- /dev/null +++ b/src/pt-BR/cookbook/organizing-code/service.md @@ -0,0 +1,121 @@ +# Componentes de serviço + +A aplicação pode ficar complicada, então faz sentido extrair partes focadas +da lógica de negócio ou da infraestrutura para componentes de serviço. Eles +normalmente são injetados em outros componentes ou em action handlers. Isso +geralmente é feito por autowiring: + +```php +public function actionIndex(CurrentRoute $route, MyService $myService): ResponseInterface +{ + $id = $route->getArgument('id'); + + // ... + $extraData = $myService->getExtraData($id); + + // ... +} +``` + +Tecnicamente, o Yii3 não impõe nenhuma limitação sobre como você constrói +serviços. Em geral, não é preciso estender uma classe base nem implementar +uma interface específica: + +```php +final readonly class MyService +{ + public function __construct( + private ExtraDataStorage $extraDataStorage + ) + { + } + + public function getExtraData(string $id): array + { + return $this->extraDataStorage->get($id); + } +} +``` + +Serviços executam uma tarefa ou retornam dados. Eles são criados uma vez, +colocados em um container de DI e então podem ser usados várias vezes. Por +isso, é uma boa ideia manter seus serviços sem estado: nem o próprio serviço +nem qualquer uma de suas dependências devem guardar estado. Você pode +garantir isso usando a palavra-chave `readonly` do PHP no nível da classe. + +## Dependências e configuração de serviços + +Serviços devem sempre declarar todas as suas dependências de outros serviços +via `__construct()`. Isso permite usar o serviço logo depois de criado e +também serve como indicador de que o serviço faz coisas demais, quando há +dependências demais. + +- Depois de criado, o serviço não deve ser reconfigurado em tempo de + execução. +- A instância do container de DI geralmente **não deve** ser injetada como + dependência. Prefira interfaces concretas. +- Em caso de inicialização complicada ou "pesada", tente adiá-la até que o + método do serviço seja chamado. + +O mesmo vale para valores de configuração. Eles devem ser fornecidos como +argumento do construtor. Valores relacionados podem ser agrupados em value +objects. Por exemplo, uma conexão com banco de dados geralmente exige a +string DSN, o nome de usuário e a senha. Esses três podem ser combinados em +uma classe Dsn: + +```php +final readonly class Dsn +{ + public function __construct( + public string $dsn, + public string $username, + public string $password + ) + { + if (!$this->isValidDsn($dsn)) { + throw new \InvalidArgumentException('DSN provided is not valid.'); + } + } + + private function isValidDsn(string $dsn): bool + { + // verifica se o DSN é válido + } +} +``` + +## Métodos de serviço + +Um método de serviço geralmente faz alguma coisa. Pode ser algo simples +repetido exatamente igual, mas normalmente depende do contexto. Por exemplo: + +```php +final readonly class PostPersister +{ + public function __construct( + private Storage $db + ) + { + } + + public function persist(Post $post) + { + $this->db->insertOrUpdate('post', $post); + } +} +``` + +Aqui há um serviço que salva posts em um armazenamento permanente, como um +banco de dados. O objeto que permite a comunicação com um armazenamento +concreto é sempre o mesmo, então é injetado pelo construtor, enquanto o post +salvo pode variar, então é passado como argumento do método. + +## Tudo é um serviço? + +Muitas vezes faz sentido escolher outro tipo de classe para colocar seu +código. Confira: + +- Repositório +- Widget +- [Middleware](../../guide/structure/middleware.md) +- Entidade diff --git a/src/pt-BR/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md b/src/pt-BR/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md new file mode 100644 index 00000000..2abfb31b --- /dev/null +++ b/src/pt-BR/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md @@ -0,0 +1,82 @@ +# Estruturando o código por caso de uso com vertical slices + +Ao construir uma aplicação, é importante organizar o código de forma que ele +seja fácil de entender, manter e escalar. Uma abordagem popular é estruturar +o código por caso de uso com vertical slices. + +Vertical slices são partes autocontidas de funcionalidade que cobrem toda a +stack, da interface do usuário à camada de acesso a dados. O desenvolvedor +organiza cada slice em torno de um caso de uso específico, como criar um +novo usuário ou atualizar um produto. + +Ao estruturar o código da forma clássica, por tipo (models, views, +controllers, helpers etc.), é fácil perder de vista o quadro geral e como as +diferentes partes do código interagem para atender funcionalidades ou casos +de uso específicos. Isso pode levar a duplicação de código, acoplamento +forte e manutenção difícil à medida que a aplicação cresce. + +Por outro lado, estruturar o código por caso de uso faz os desenvolvedores +focarem em uma funcionalidade ou fluxo específico e entenderem como as +diferentes partes do código trabalham juntas para atendê-lo. Essa abordagem +também ajuda a manter o código relacionado junto, em um único diretório, o +que facilita a navegação e a manutenção. O vertical slicing também incentiva +o uso de conceitos de domain-driven design, como entidades, repositórios e +serviços, que ajudam a promover uma boa separação de responsabilidades e +modularidade. + +Além disso, estruturar o código por caso de uso pode facilitar os testes e o +debug da aplicação, já que o namespace do caso de uso encapsula cada +funcionalidade ou fluxo em seu próprio diretório, com limites claros e +interfaces bem definidas. + +Veja um exemplo de estrutura de diretórios de uma aplicação PHP organizada +com vertical slices: + +``` +src/ +└── Blog/ + ├── Model/ + │ ├── Comment.php + │ ├── CommentRepository.php + │ ├── Post.php + │ └── PostRepository.php + ├── Service/ + │ └── MarkdownProcessor.php + ├── UseCase/ + │ ├── CreateComment/ + │ │ ├── CreateCommentAction.php + │ │ ├── CreateCommentRequest.php + │ ├── CreatePost/ + │ │ ├── CreatePostAction.php + │ │ ├── CreatePostRequest.php + │ ├── DeleteComment/ + │ │ ├── DeleteCommentAction.php + │ │ ├── DeleteCommentRequest.php + │ ├── DeletePost/ + │ │ ├── DeletePostAction.php + │ │ ├── DeletePostRequest.php + │ ├── ListComments/ + │ │ ├── ListCommentsAction.php + │ ├── ListPosts/ + │ │ ├── ListPostsAction.php + │ ├── UpdatePost/ + │ │ ├── UpdatePostAction.php + │ │ ├── UpdatePostRequest.php + │ ├── ViewPost/ + │ │ ├── ViewPostAction.php + │ ├── Rss/ + │ │ ├── RssAction.php + | | ├── RssBuilder.php +``` + +Cada vertical slice tem seu próprio diretório, que contém o código associado +ao caso de uso. + +Os subdiretórios de caso de uso e suas respectivas classes são organizados +por tipo dentro de cada diretório, omitindo o diretório quando há uma única +classe daquele tipo. Se um código é compartilhado entre vários casos de uso, +ele sobe um nível, como em `Model` ou `Service`. + +## Referências + +- [Visão geral da estrutura da aplicação](../../guide/structure/overview.md) diff --git a/src/pt-BR/cookbook/preface.md b/src/pt-BR/cookbook/preface.md new file mode 100644 index 00000000..adefb14c --- /dev/null +++ b/src/pt-BR/cookbook/preface.md @@ -0,0 +1,38 @@ +# Prefácio + +O Yii é um framework PHP de alto desempenho, baseado em pacotes, para +desenvolver aplicações modernas. O nome Yii (pronuncia-se `Yee` ou `[ji:]`) +significa "simples e evolutivo" em chinês. Você também pode pensar nele +como um acrônimo de **Yes It Is**! + +O Yii é um framework genérico de programação web. Você pode usá-lo para +desenvolver todo tipo de aplicação web com PHP. Por causa da sua +arquitetura e do suporte sofisticado a cache, ele é especialmente indicado +para aplicações de grande porte, como portais, sistemas de gerenciamento de +conteúdo, e-commerce, APIs REST etc. + +Com uma documentação abrangente e uma comunidade de usuários entusiasmada, o +Yii pode reduzir bastante o seu tempo de desenvolvimento a longo prazo. + +## Sobre o que é este livro + +Este livro é para você se já conhece o Yii3, constrói aplicações Yii e leu o +guia oficial do Yii3. Ele cobre conceitos de desenvolvimento fundamentais, +abordagens de arquitetura de aplicações, integração de serviços de terceiros +com o Yii3 etc. + +O livro é formado por receitas individuais reunidas por especialistas em +Yii, que você pode aplicar nas suas aplicações. Elas são organizadas por +tema, mas você pode lê-las em qualquer ordem, já que não há dependência +entre elas. + +## Pré-requisitos + +- Você deve ter o Yii3 instalado. +- Você deve conhecer o básico do framework e o guia oficial. + +## Como participar + +Se você encontrou alguma errata ou informação errada, quer melhorar algo ou +tem uma boa receita, crie uma issue ou abra um pull request no [repositório +do livro no GitHub](https://github.com/yiisoft/docs). diff --git a/src/pt-BR/cookbook/sentry-integration.md b/src/pt-BR/cookbook/sentry-integration.md new file mode 100644 index 00000000..28e56813 --- /dev/null +++ b/src/pt-BR/cookbook/sentry-integration.md @@ -0,0 +1,124 @@ +# Integração com o Sentry + +## O que é o Sentry + +O [Sentry](https://sentry.io/) é uma ferramenta para monitorar e depurar a estabilidade e o desempenho de aplicações. +O Sentry dá acesso aos eventos que você envia para ele a partir da sua aplicação. + +Na maioria das vezes, o Sentry é usado para monitorar erros (exceções). +Você pode enriquecer os erros com contexto para entender melhor o problema: +- Argumentos da requisição - Tags para agrupar exceções - Estado do +ambiente: variáveis de ambiente, estado da aplicação e outros atributos +globais + +Você encontra a lista completa de funcionalidades no site oficial: +https://sentry.io/welcome/ + +## Instalação + +### Instale o pacote + +Instale o pacote necessário `yiisoft/yii-sentry` com o seguinte comando: + +```shell +composer require yiisoft/yii-sentry --prefer-dist +``` + +### Instale um driver HTTP + +A biblioteca +[`getsentry/sentry-php`](https://github.com/getsentry/sentry-php) exige o +pacote `php-http/httplug` e algum driver HTTP. No exemplo abaixo, vamos +usar o adaptador do Guzzle. + +> Você encontra a lista de todos os adaptadores [nesta página](https://docs.php-http.org/en/latest/clients.html#clients-adapters). + +Para instalar os pacotes, execute o seguinte comando: + +```shell +composer require php-http/httplug php-http/guzzle7-adapter --prefer-dist +``` + +## Configuração + +### Obtenha e guarde o token + +Em seguida, configure a aplicação. + +Primeiro, cadastre-se no [Sentry](https://sentry.io) e crie um projeto. + +Depois, nas configurações do projeto, na aba “General Settings”, encontre o +campo “Security Token” e copie o valor dele. + +Agora coloque esse token na configuração do pacote. Por padrão, a configuração fica em `config/packages/yiisoft/yii-sentry/config/params.php`. +Defina o token copiado como valor do elemento do array em `yiisoft/yii-sentry` => `options` => `dsn`. Exemplo: + +```diff +'yiisoft/yii-sentry' => [ + 'enabled' => true, + 'options' => [ +- 'dsn' => '', ++ 'dsn' => 'TOKEN', + ], +], +``` + +### Configure o cliente HTTP + +Depois de instalar o cliente HTTP, configure-o. + +Crie o arquivo `config/common/sentry.php` e coloque nele o seguinte código: + +```php + \GuzzleHttp\Client::class, + \Http\Client\HttpAsyncClient::class => [ + 'class' => \Http\Adapter\Guzzle7\Client::class, + '__construct()' => [ + \Yiisoft\Factory\Definition\Reference::to(\Http\Client\HttpClient::class), + ], + ], +]; +``` + +# Integração + +### Web + +O suporte do Sentry para `web` é implementado como middleware. + +Isso significa que você só precisa adicionar o `SentryMiddleware` à lista +global de middlewares em `config/web/application.php`: + +```diff +return [ + Yiisoft\Yii\Web\Application::class => [ + '__construct()' => [ + 'dispatcher' => DynamicReference::to(static function (Injector $injector) { + return ($injector->make(MiddlewareDispatcher::class)) + ->withMiddlewares( + [ + Router::class, + SubFolder::class, ++ SentryMiddleware::class, + ErrorCatcher::class, + ] + ); + }), + 'fallbackHandler' => Reference::to(NotFoundHandler::class), + ], + ], +]; +``` + +### Console + +O Sentry suporta o `console` por meio de um handler para o evento +[ConsoleEvents::ERROR](https://symfony.com/doc/current/components/console/events.html#the-consoleevents-error-event). + +O pacote fornece um arquivo de configuração que inscreve a aplicação nesse +evento automaticamente. diff --git a/src/pt-BR/cookbook/third-party-integrations/index.md b/src/pt-BR/cookbook/third-party-integrations/index.md new file mode 100644 index 00000000..05bec5ef --- /dev/null +++ b/src/pt-BR/cookbook/third-party-integrations/index.md @@ -0,0 +1,18 @@ +# Integrações de terceiros + +Esta é uma coleção de guias, contribuídos pela comunidade, para integrar +pacotes de terceiros com o Yii3. + +- Os guias são criados pela comunidade Yii. +- Membros do time principal do Yii fazem a curadoria e a edição. + +Fique à vontade para enviar seus próprios textos via pull request. Os +membros do time vão revisar, dar feedback e fazer o merge da melhor forma +possível. + +--- + +- [Guia de integração com o Symfony + Messenger](symfony-messenger-integration-guide.md) +- [Guia de integração com o Symfony + Scheduler](symfony-scheduler-integration-guide.md) diff --git a/src/pt-BR/cookbook/third-party-integrations/symfony-messenger-integration-guide.md b/src/pt-BR/cookbook/third-party-integrations/symfony-messenger-integration-guide.md new file mode 100644 index 00000000..fe8aaa65 --- /dev/null +++ b/src/pt-BR/cookbook/third-party-integrations/symfony-messenger-integration-guide.md @@ -0,0 +1,352 @@ +# Guia de integração com o Symfony Messenger + +O componente [Symfony +Messenger](https://symfony.com/doc/current/components/messenger.html) ajuda +as aplicações a enviar e receber mensagens de/para outras aplicações ou por +meio de filas de mensagens. + +## Instalação + +```shell +composer require symfony/messenger +``` + +## Como usar com o Yii + +### 1. Crie uma Message e um Handler. + +```php +namespace App\Messages; + +final readonly class MyMessage +{ + public function __construct(public string $content) + { + } +} +``` + +```php +namespace App\Messages; + +use Psr\Log\LoggerInterface; + +final readonly class MyMessageHandler +{ + public function __construct(private LoggerInterface $logger) + { + } + public function __invoke(MyMessage $message): void + { + // ... + $this->logger->info("The message with the content '$message->content' has been received."); + } +} +``` + +### 2. Implemente a ServiceProviderInterface. + +Essa instância da ServiceProviderInterface é usada para configurar alguns +comandos do Symfony Messenger. + +```php +namespace App\Services; + +use Psr\Container\ContainerInterface; +use Symfony\Contracts\Service\ServiceProviderInterface; + +final readonly class ServiceProvider implements ServiceProviderInterface +{ + /** + * @param ContainerInterface $container + * @param array $serviceMap + */ + public function __construct( + private ContainerInterface $container, + private array $serviceMap) + { + } + + /** + * @inheritDoc + */ + public function get(string $id): mixed + { + return $this->container->get($id); + } + + public function has(string $id): bool + { + return $this->container->has($id); + } + + /** + * @inheritDoc + */ + public function getProvidedServices(): array + { + return $this->serviceMap; + } +} +``` + +### 3. Configure o Symfony Messenger. + +O exemplo usa o pacote +[symfony/doctrine-messenger](https://packagist.org/packages/symfony/doctrine-messenger) +como transporte: + +Adicione os pacotes do Doctrine ao `composer.json`: +```json +{ + // ... + "require": { + // ... + "doctrine/orm": "^3", + "doctrine/dbal": "^4", + "symfony/cache": "^7" + }, +} +``` + +Instale o Doctrine: +```shell +composer install +``` + +Configure a conexão do Doctrine em `config/common/params.php`: +```php +return [ + // ... + 'doctrine' => [ + 'paths' => [ + ], + 'isDevMode' => false, + 'connection' => [ + 'driver' => 'pdo_mysql', + 'user' => 'site1', + 'password' => 'secret', + 'dbname' => 'site3' + ] + ], +]; +``` + +Instale o pacote Symfony Doctrine Messenger: +```shell +composer require symfony/doctrine-messenger +``` + +Configure as dependências do Doctrine e do Symfony Messenger em +`config/common/di/application.php`: +```php +use App\Messages\MyMessage; +use App\Messages\MyMessageHandler; +use App\Services\ServiceProvider; +use Doctrine\DBAL\DriverManager; +use Doctrine\ORM\Configuration; +use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\ORMSetup; +use Doctrine\ORM\Proxy\ProxyFactory; +use Doctrine\ORM\Tools\Console\EntityManagerProvider; +use Doctrine\ORM\Tools\Console\EntityManagerProvider\SingleManagerProvider; +use Psr\Cache\CacheItemPoolInterface; +use Psr\Container\ContainerInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\Cache\Adapter\FilesystemAdapter; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Messenger\Bridge\Doctrine\Transport\Connection; +use Symfony\Component\Messenger\Bridge\Doctrine\Transport\DoctrineTransport; +use Symfony\Component\Messenger\Command\ConsumeMessagesCommand; +use Symfony\Component\Messenger\Command\DebugCommand; +use Symfony\Component\Messenger\Command\FailedMessagesRemoveCommand; +use Symfony\Component\Messenger\Command\FailedMessagesRetryCommand; +use Symfony\Component\Messenger\Command\FailedMessagesShowCommand; +use Symfony\Component\Messenger\Command\SetupTransportsCommand; +use Symfony\Component\Messenger\Command\StatsCommand; +use Symfony\Component\Messenger\EventListener\StopWorkerOnRestartSignalListener; +use Symfony\Component\Messenger\Handler\HandlersLocator; +use Symfony\Component\Messenger\MessageBus; +use Symfony\Component\Messenger\Middleware\HandleMessageMiddleware; +use Symfony\Component\Messenger\Middleware\SendMessageMiddleware; +use Symfony\Component\Messenger\RoutableMessageBus; +use Symfony\Component\Messenger\Transport\Sender\SendersLocator; +use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; +use Symfony\Contracts\Service\ServiceProviderInterface; +use Yiisoft\Aliases\Aliases; +use Yiisoft\Definitions\Reference; + +class_alias(MessageBus::class, 'MyMessageBus'); + +return [ + // ... + CacheItemPoolInterface::class => static function (ContainerInterface $container) { + return new FilesystemAdapter(directory: $container->get(Aliases::class)->get('@runtime')); + }, //One of the following adapters can be used instead: Psr16Adapter, RedisAdapter, MemcachedAdapter, DoctrineDbalAdapter, and so forth. + + Configuration::class => static function (ContainerInterface $container) use ($params) { + $config = ORMSetup::createAttributeMetadataConfiguration( // on PHP >= 8.4, use ORMSetup::createAttributeMetadataConfig() + paths: $params['doctrine']['paths'], + isDevMode: $params['doctrine']['isDevMode'], + cache: $container->get(CacheItemPoolInterface::class)); + $config->setAutoGenerateProxyClasses(ProxyFactory::AUTOGENERATE_FILE_NOT_EXISTS_OR_CHANGED); + return $config; + }, + + EntityManagerInterface::class => static function (ContainerInterface $container) use ($params) { + $configuration = $container->get(Configuration::class); + return new EntityManager( + DriverManager::getConnection( + $params['doctrine']['connection'], + $configuration + ), + $configuration); + }, + EntityManagerProvider::class => SingleManagerProvider::class, + + SerializerInterface::class => PhpSerializer::class, + 'DoctrineTransport' => static function (ContainerInterface $container) use ($params) { + $configuration = $container->get(Configuration::class); + $connection = new Connection([], DriverManager::getConnection( + $params['doctrine']['connection'], + $configuration + )); + return new DoctrineTransport($connection, $container->get(SerializerInterface::class)); + }, + + MyMessageBus::class => static function (ContainerInterface $container) { + return new MyMessageBus([ + new SendMessageMiddleware(sendersLocator: new SendersLocator([ + MyMessage::class => ['DoctrineTransport'] + ], $container)), + new HandleMessageMiddleware(new HandlersLocator([ + MyMessage::class => [$container->get(MyMessageHandler::class)] + ])), + ]); + }, + + EventDispatcherInterface::class => static function (ContainerInterface $container) { + $eventDispatcher = new EventDispatcher(); + $eventDispatcher->addSubscriber($container->get(StopWorkerOnRestartSignalListener::class)); + return $eventDispatcher; + }, + ServiceProviderInterface::class => [ + 'class' => ServiceProvider::class, + '__construct()' => [ + 'container' => Reference::to(ContainerInterface::class), + 'serviceMap' => [ + 'DoctrineTransport' => DoctrineTransport::class + ] + ], + ], + + ConsumeMessagesCommand::class => static function (ContainerInterface $container) { + return new ConsumeMessagesCommand( + $container->get(RoutableMessageBus::class), + $container, + $container->get(EventDispatcherInterface::class), + $container->get(LoggerInterface::class), + array_keys($container->get(ServiceProviderInterface::class)->getProvidedServices()) + ); + }, + DebugCommand::class => [ + '__construct()' => [ + 'mapping' => [ + MyMessageBus::class => [Reference::to(MyMessageHandler::class)] + ] + ], + ], + FailedMessagesRemoveCommand::class => [ + '__construct()' => [ + 'globalFailureReceiverName' => null, + 'failureTransports' => Reference::to(ServiceProviderInterface::class) + ], + ], + FailedMessagesRetryCommand::class => [ + '__construct()' => [ + 'globalReceiverName' => null, + 'failureTransports' => Reference::to(ServiceProviderInterface::class), + 'messageBus' => Reference::to(MyMessageBus::class), + 'eventDispatcher' => Reference::to(EventDispatcherInterface::class), + 'logger' => Reference::to(LoggerInterface::class), + ], + ], + FailedMessagesShowCommand::class => [ + '__construct()' => [ + 'globalFailureReceiverName' => null, + 'failureTransports' => Reference::to(ServiceProviderInterface::class) + ], + ], + SetupTransportsCommand::class => static function (ContainerInterface $container) { + return new SetupTransportsCommand( + $container, + array_keys($container->get(ServiceProviderInterface::class)->getProvidedServices()) + ); + }, + StatsCommand::class => static function (ContainerInterface $container) { + return new StatsCommand( + $container, + array_keys($container->get(ServiceProviderInterface::class)->getProvidedServices()) + ); + }, +]; +``` + +### 4. Integre os comandos do Symfony Messenger ao console do Yii. + +Adicione os comandos em `config/console/commands.php`: +```php +use Symfony\Component\Messenger\Command\ConsumeMessagesCommand; +use Symfony\Component\Messenger\Command\DebugCommand; +use Symfony\Component\Messenger\Command\FailedMessagesRemoveCommand; +use Symfony\Component\Messenger\Command\FailedMessagesRetryCommand; +use Symfony\Component\Messenger\Command\FailedMessagesShowCommand; +use Symfony\Component\Messenger\Command\SetupTransportsCommand; +use Symfony\Component\Messenger\Command\StatsCommand; +use Symfony\Component\Messenger\Command\StopWorkersCommand; + +return [ + // ... + 'symfony:messenger:consume' => ConsumeMessagesCommand::class, + 'symfony:messenger:debug' => DebugCommand::class, + 'symfony:messenger:failed:remove' => FailedMessagesRemoveCommand::class, + 'symfony:messenger:failed:retry' => FailedMessagesRetryCommand::class, + 'symfony:messenger:failed:show' => FailedMessagesShowCommand::class, + 'symfony:messenger:setup-transports' => SetupTransportsCommand::class, + 'symfony:messenger:stats' => StatsCommand::class, + 'symfony:messenger:stop-workers' => StopWorkersCommand::class +]; +``` + +### 5. Despache uma mensagem. + +Exemplo: + +```php +use App\Messages\MyMessage; +use MyMessageBus; +use Psr\Http\Message\ResponseInterface; + +final readonly class MyController +{ + public function __construct(private MyMessageBus $bus) + { + } + + public function sendMessage(): ResponseInterface + { + $this->bus->dispatch(new MyMessage('Hello Symfony Messenger!')); + // ... + } +} +``` + +### 6. Consuma as mensagens. + +Exemplo: +```bash +./yii symfony:messenger:consume DoctrineTransport --bus=MyMessageBus +``` diff --git a/src/pt-BR/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md b/src/pt-BR/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md new file mode 100644 index 00000000..ee0eee8f --- /dev/null +++ b/src/pt-BR/cookbook/third-party-integrations/symfony-scheduler-integration-guide.md @@ -0,0 +1,293 @@ +# Guia de integração com o Symfony Scheduler + +O componente [Symfony +Scheduler](https://symfony.com/doc/current/scheduler.html) gerencia o +agendamento de tarefas na sua aplicação PHP, como rodar uma tarefa toda +noite às 3h, a cada duas semanas exceto em feriados, ou qualquer outro +agendamento personalizado de que você precise. + +## Instalação + +```shell +composer require symfony/scheduler +``` + +## Como usar com o Yii + +### 1. Crie uma Message e um Handler. + +```php +namespace App\Messages; + +final readonly class MyMessage +{ + public function __construct(public string $content) + { + } +} +``` + +```php +namespace App\Messages; + +use Psr\Log\LoggerInterface; + +final readonly class MyMessageHandler +{ + public function __construct(private LoggerInterface $logger) + { + } + public function __invoke(MyMessage $message): void + { + // ... + $this->logger->info("The message with the content '$message->content' has been received."); + } +} +``` + +### 2. Associe mensagens recorrentes a um Schedule. + +```php +namespace App\Scheduler; + +use App\Messages\MyMessage; +use Symfony\Component\Scheduler\RecurringMessage; +use Symfony\Component\Scheduler\Schedule; +use Symfony\Component\Scheduler\ScheduleProviderInterface; + +class MyScheduleProvider implements ScheduleProviderInterface +{ + public function getSchedule(): Schedule + { + return (new Schedule()) + ->with( + RecurringMessage::every( + '10 seconds', + new MyMessage('Hello Symfony Scheduler!')) + ); + } +} +``` + +### 3. Configure o Symfony Scheduler. + +Dependendo das suas necessidades, o componente Symfony Scheduler oferece +duas formas de consumir mensagens: usando o comando `messenger:consume` ou +[criando um worker +programaticamente](https://symfony.com/doc/current/scheduler.html#creating-a-consumer-programmatically). +O exemplo usa o pacote +[symfony/messenger](https://packagist.org/packages/symfony/messenger) para +consumir as mensagens. + + +Instale o pacote Symfony Messenger: +```shell +composer require symfony/messenger +``` + +Instale o pacote Symfony Cache: +```shell +composer require symfony/cache +``` + +Implemente a ServiceProviderInterface. Essa instância da +ServiceProviderInterface é usada para configurar alguns comandos do Symfony +Messenger. + +```php +namespace App\Services; + +use Psr\Container\ContainerInterface; +use Symfony\Contracts\Service\ServiceProviderInterface; + +final readonly class ServiceProvider implements ServiceProviderInterface +{ + /** + * @param ContainerInterface $container + * @param array $serviceMap + */ + public function __construct( + private ContainerInterface $container, + private array $serviceMap) + { + } + + /** + * @inheritDoc + */ + public function get(string $id): mixed + { + return $this->container->get($id); + } + + public function has(string $id): bool + { + return $this->container->has($id); + } + + /** + * @inheritDoc + */ + public function getProvidedServices(): array + { + return $this->serviceMap; + } +} +``` + +Configure as dependências do Symfony Scheduler e do Symfony Messenger em +`config/common/di/application.php`: +```php +use App\Messages\MyMessage; +use App\Messages\MyMessageHandler; +use App\Scheduler\MyScheduleProvider; +use App\Services\ServiceProvider; +use Psr\Cache\CacheItemPoolInterface; +use Psr\Container\ContainerInterface; +use Psr\EventDispatcher\EventDispatcherInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\Cache\Adapter\FilesystemAdapter; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\Messenger\Command\ConsumeMessagesCommand; +use Symfony\Component\Messenger\Command\DebugCommand; +use Symfony\Component\Messenger\Command\FailedMessagesRemoveCommand; +use Symfony\Component\Messenger\Command\FailedMessagesRetryCommand; +use Symfony\Component\Messenger\Command\FailedMessagesShowCommand; +use Symfony\Component\Messenger\Command\SetupTransportsCommand; +use Symfony\Component\Messenger\Command\StatsCommand; +use Symfony\Component\Messenger\EventListener\StopWorkerOnRestartSignalListener; +use Symfony\Component\Messenger\Handler\HandlersLocator; +use Symfony\Component\Messenger\MessageBus; +use Symfony\Component\Messenger\Middleware\HandleMessageMiddleware; +use Symfony\Component\Messenger\RoutableMessageBus; +use Symfony\Component\Scheduler\Generator\MessageGenerator; +use Symfony\Component\Scheduler\Messenger\SchedulerTransport; +use Symfony\Contracts\Service\ServiceProviderInterface; +use Yiisoft\Aliases\Aliases; +use Yiisoft\Definitions\Reference; + +class_alias(MessageBus::class, 'MyMessageBus'); + +return [ + // ... + CacheItemPoolInterface::class => static function (ContainerInterface $container) { + return new FilesystemAdapter(directory: $container->get(Aliases::class)->get('@runtime')); + }, //One of the following adapters can be used instead: Psr16Adapter, RedisAdapter, MemcachedAdapter, DoctrineDbalAdapter, and so forth. + + + 'SchedulerTransport' => static function () { + return new SchedulerTransport( + new MessageGenerator( + new MyScheduleProvider(), + 'MySchedule' + ) + ); + }, + + MyMessageBus::class => static function (ContainerInterface $container) { + return new MyMessageBus([ + new HandleMessageMiddleware(new HandlersLocator([ + MyMessage::class => [$container->get(MyMessageHandler::class)] + ])), + ]); + }, + + EventDispatcherInterface::class => static function (ContainerInterface $container) { + $eventDispatcher = new EventDispatcher(); + $eventDispatcher->addSubscriber($container->get(StopWorkerOnRestartSignalListener::class)); + return $eventDispatcher; + }, + ServiceProviderInterface::class => [ + 'class' => ServiceProvider::class, + '__construct()' => [ + 'container' => Reference::to(ContainerInterface::class), + 'serviceMap' => [ + 'SchedulerTransport' => SchedulerTransport::class + ] + ], + ], + + ConsumeMessagesCommand::class => static function (ContainerInterface $container) { + return new ConsumeMessagesCommand( + $container->get(RoutableMessageBus::class), + $container, + $container->get(EventDispatcherInterface::class), + $container->get(LoggerInterface::class), + array_keys($container->get(ServiceProviderInterface::class)->getProvidedServices()) + ); + }, + DebugCommand::class => [ + '__construct()' => [ + 'mapping' => [ + MyMessageBus::class => [Reference::to(MyMessageHandler::class)] + ] + ], + ], + FailedMessagesRemoveCommand::class => [ + '__construct()' => [ + 'globalFailureReceiverName' => null, + 'failureTransports' => Reference::to(ServiceProviderInterface::class) + ], + ], + FailedMessagesRetryCommand::class => [ + '__construct()' => [ + 'globalReceiverName' => null, + 'failureTransports' => Reference::to(ServiceProviderInterface::class), + 'messageBus' => Reference::to(MyMessageBus::class), + 'eventDispatcher' => Reference::to(EventDispatcherInterface::class), + 'logger' => Reference::to(LoggerInterface::class), + ], + ], + FailedMessagesShowCommand::class => [ + '__construct()' => [ + 'globalFailureReceiverName' => null, + 'failureTransports' => Reference::to(ServiceProviderInterface::class) + ], + ], + SetupTransportsCommand::class => static function (ContainerInterface $container) { + return new SetupTransportsCommand( + $container, + array_keys($container->get(ServiceProviderInterface::class)->getProvidedServices()) + ); + }, + StatsCommand::class => static function (ContainerInterface $container) { + return new StatsCommand( + $container, + array_keys($container->get(ServiceProviderInterface::class)->getProvidedServices()) + ); + }, +]; +``` + +### 4. Integre os comandos do Symfony Messenger ao console do Yii. + +Adicione os comandos em `config/console/commands.php`: +```php +use Symfony\Component\Messenger\Command\ConsumeMessagesCommand; +use Symfony\Component\Messenger\Command\DebugCommand; +use Symfony\Component\Messenger\Command\FailedMessagesRemoveCommand; +use Symfony\Component\Messenger\Command\FailedMessagesRetryCommand; +use Symfony\Component\Messenger\Command\FailedMessagesShowCommand; +use Symfony\Component\Messenger\Command\SetupTransportsCommand; +use Symfony\Component\Messenger\Command\StatsCommand; +use Symfony\Component\Messenger\Command\StopWorkersCommand; + +return [ + // ... + 'symfony:messenger:consume' => ConsumeMessagesCommand::class, + 'symfony:messenger:debug' => DebugCommand::class, + 'symfony:messenger:failed:remove' => FailedMessagesRemoveCommand::class, + 'symfony:messenger:failed:retry' => FailedMessagesRetryCommand::class, + 'symfony:messenger:failed:show' => FailedMessagesShowCommand::class, + 'symfony:messenger:setup-transports' => SetupTransportsCommand::class, + 'symfony:messenger:stats' => StatsCommand::class, + 'symfony:messenger:stop-workers' => StopWorkersCommand::class +]; +``` + +### 5. Consuma as mensagens. + +Exemplo: +```bash +./yii symfony:messenger:consume SchedulerTransport --bus=MyMessageBus +``` diff --git a/src/pt-BR/cookbook/using-htmx-for-partial-reloads.md b/src/pt-BR/cookbook/using-htmx-for-partial-reloads.md new file mode 100644 index 00000000..a18df4ce --- /dev/null +++ b/src/pt-BR/cookbook/using-htmx-for-partial-reloads.md @@ -0,0 +1,393 @@ +# Usando htmx para recarregar partes da página + +O [htmx](https://htmx.org/) permite que links e formulários requisitem fragmentos de HTML e os troquem na página atual. Em uma +aplicação Yii, isso funciona bem para grids: ordenação, filtros e paginação podem atualizar só o grid enquanto o resto +da página continua no lugar. + +Esta receita usa o `GridView` como exemplo porque ele tem links e +formulários que se beneficiam naturalmente de recargas parciais. O mesmo +padrão funciona para qualquer widget ou fragmento de página: renderize o +fragmento separadamente, adicione atributos do htmx aos controles que devem +atualizá-lo e retorne apenas esse fragmento nas requisições do htmx. + +## Instale o GridView + +Instale o pacote de data view, se a aplicação ainda não o usa: + +```shell +composer require yiisoft/yii-dataview +``` + +## Carregue o htmx + +A configuração mais simples é carregar o htmx de uma CDN. Crie +`src/Web/Shared/Layout/Main/HtmxAsset.php`: + +```php + 'sha384-H5SrcfygHmAuTDZphMHqBJLc3FhssKjG7w/CeCpFReSfwBWDTKpkzPP8c+cLsK+V', + 'crossorigin' => 'anonymous', + ]; +} +``` + +Ao atualizar a versão do htmx, atualize a URL e o valor de `integrity` +juntos. + +Em aplicações de produção, considere servir o htmx a partir dos assets da +sua aplicação para não depender de uma CDN de terceiros. Baixe o +`htmx.min.js` para `assets/main/js/htmx.min.js` e use um asset bundle local: + +```php + */ + $pagination = OffsetPagination::widget(); + + return GridView::widget() + ->containerAttributes([ + 'id' => 'UsersGridView', + 'class' => 'mt-4 position-relative', + ]) + ->dataReader($this->dataReader()) + ->pageSizeConstraint(5) + ->paginationWidget($pagination) + ->columns( + new DataColumn('id', header: 'ID', filter: true), + new DataColumn('login', header: 'Login', filter: true), + new DataColumn('name', header: 'Name', filter: true), + new DataColumn('status', header: 'Status', filter: true), + ) + ->render(); + } + + private function dataReader(): IterableDataReader + { + return new IterableDataReader([ + ['id' => 1, 'login' => 'admin', 'name' => 'Alice Adams', 'status' => 'Active'], + ['id' => 2, 'login' => 'editor', 'name' => 'Eve Editor', 'status' => 'Active'], + ['id' => 3, 'login' => 'author', 'name' => 'Arthur Author', 'status' => 'Active'], + ['id' => 4, 'login' => 'reviewer', 'name' => 'Rita Reviewer', 'status' => 'Inactive'], + ['id' => 5, 'login' => 'support', 'name' => 'Sam Support', 'status' => 'Active'], + ['id' => 6, 'login' => 'guest', 'name' => 'Grace Guest', 'status' => 'Inactive'], + ]); + } +} +``` + +Em uma aplicação real, substitua `dataReader()` por um reader baseado em uma +consulta ao banco de dados ou em um repositório. Mantenha o widget +responsável por renderizar o fragmento do grid. + +Crie `src/Web/Users/Index/template.php`: + +```php +setTitle('Users'); +?> +

Users

+ + +``` + +Crie `src/Web/Users/Index/Action.php`: + +```php +viewRenderer->render(__DIR__ . '/template'); + } +} +``` + +Adicione a action em `config/common/routes.php`: + +```php +routes( + Route::get('/') + ->action(Web\HomePage\Action::class) + ->name('home'), + Route::get('/users') + ->action(Web\Users\Index\Action::class) + ->name('users/index'), + ), +]; +``` + +Abra `/users` e verifique primeiro se a ordenação, os filtros e a paginação +funcionam com recarga completa da página. + +## Adicione atributos do htmx ao grid + +Agora atualize o `UsersGrid` para que os controles do grid requisitem um +fragmento e o troquem em `#UsersGridView`: + +```php + '#UsersGridView', + 'hx-target' => '#UsersGridView', + 'hx-replace-url' => 'true', + 'hx-swap' => 'outerHTML', + ]; + + /** @var PaginationWidgetInterface */ + $pagination = OffsetPagination::widget()->addLinkAttributes([ + 'hx-boost' => 'true', + ...$htmxLoadAttributes, + ]); + + return GridView::widget() + ->containerAttributes([ + 'id' => 'UsersGridView', + 'class' => 'mt-4 position-relative', + ]) + ->dataReader($this->dataReader()) + ->pageSizeConstraint(5) + ->sortableLinkAttributes([ + 'hx-boost' => 'true', + ...$htmxLoadAttributes, + ]) + ->filterFormAttributes([ + 'hx-boost' => 'true', + ...$htmxLoadAttributes, + ]) + ->paginationWidget($pagination) + ->columns( + new DataColumn('id', header: 'ID', filter: true), + new DataColumn('login', header: 'Login', filter: true), + new DataColumn('name', header: 'Name', filter: true), + new DataColumn('status', header: 'Status', filter: true), + ) + ->render(); + } + + private function dataReader(): IterableDataReader + { + return new IterableDataReader([ + ['id' => 1, 'login' => 'admin', 'name' => 'Alice Adams', 'status' => 'Active'], + ['id' => 2, 'login' => 'editor', 'name' => 'Eve Editor', 'status' => 'Active'], + ['id' => 3, 'login' => 'author', 'name' => 'Arthur Author', 'status' => 'Active'], + ['id' => 4, 'login' => 'reviewer', 'name' => 'Rita Reviewer', 'status' => 'Inactive'], + ['id' => 5, 'login' => 'support', 'name' => 'Sam Support', 'status' => 'Active'], + ['id' => 6, 'login' => 'guest', 'name' => 'Grace Guest', 'status' => 'Inactive'], + ]); + } +} +``` + +A parte importante é o array compartilhado `$htmxLoadAttributes`: + +- `hx-boost="true"` faz os links e o formulário de filtro do grid enviarem + requisições htmx. +- `hx-target="#UsersGridView"` diz ao htmx qual elemento substituir. +- `hx-swap="outerHTML"` substitui todo o container do grid pela resposta. +- `hx-replace-url="true"` mantém a URL do navegador sincronizada com a + ordenação, o filtro e a página atuais. +- `hx-indicator="#UsersGridView"` marca o grid como o elemento indicador de + carregamento enquanto a requisição está ativa. + +O seletor de destino e o `id` do container precisam coincidir. Neste +exemplo, ambos usam `UsersGridView`. + +## Retorne HTML parcial para requisições do htmx + +O htmx envia o header `HX-Request` nas suas requisições. + +Na action, retorne apenas o widget quando o header estiver presente: + +```php +getHeaderLine('HX-Request') === 'true' + ? $this->htmlResponseFactory->createResponse(UsersGrid::widget()) + : $this->viewRenderer->render(__DIR__ . '/template'); + + return $response->withAddedHeader('Vary', 'HX-Request'); + } +} +``` + +O header `Vary` importa quando um navegador, proxy ou CDN faz cache das +respostas. A mesma URL pode retornar uma página completa sem `HX-Request` e +um fragmento com `HX-Request: true`, então os caches precisam manter essas +respostas separadas. + +## Experimente + +Abra a página da lista e use a ordenação, os filtros ou a paginação. A URL +do navegador deve mudar, e apenas o HTML do grid deve ser substituído. + +Nas ferramentas de desenvolvedor do navegador, as requisições do htmx devem +incluir o header `HX-Request`. As respostas devem conter apenas o container +do grid. + +Use o mesmo padrão para outros widgets ou fragmentos de página: + +1. Coloque o HTML recarregável em um widget ou em outro pequeno + renderizador. +2. Adicione atributos do htmx aos links e formulários que devem atualizá-lo. +3. Retorne o fragmento para requisições do htmx e a página completa para + requisições comuns. diff --git a/src/pt-BR/cookbook/using-yii-in-third-party-apps.md b/src/pt-BR/cookbook/using-yii-in-third-party-apps.md new file mode 100644 index 00000000..95c64065 --- /dev/null +++ b/src/pt-BR/cookbook/using-yii-in-third-party-apps.md @@ -0,0 +1,174 @@ +# Usando o Yii em aplicações de terceiros + +Às vezes um projeto já tem um ponto de entrada controlado por outro +framework, CMS ou aplicação legada, mas você ainda quer reaproveitar +serviços do Yii: configuração, definições de DI, serviços de domínio, logs, +mailers, conexões com banco de dados ou código de aplicação voltado ao +console. + +O Yii3 não tem um singleton global de aplicação. Inicialize o container do +Yii explicitamente e passe os serviços de que você precisa ao código de +terceiros. + +## Inicialize o container do Yii + +Crie um pequeno adaptador na aplicação hospedeira, por exemplo +`bootstrap-yii-services.php`: + +```php +withValidate(Environment::appDebug()) + ->withDefinitions(array_merge( + $config->get('di-console'), + [ConfigInterface::class => $config], + )) + ->withProviders($config->get('di-providers-console')) + ->withDelegates($config->get('di-delegates-console')); + + if ($config->has('di-tags-console')) { + $containerConfig = $containerConfig->withTags($config->get('di-tags-console')); + } + + $container = new Container($containerConfig); + + foreach ($config->get('bootstrap-console') as $callback) { + if (!is_callable($callback)) { + throw new RuntimeException(sprintf( + 'Bootstrap callback must be callable, "%s" given.', + get_debug_type($callback), + )); + } + + $callback($container); + } + + return $container; +} +``` + +O adaptador monta apenas a configuração e o container de DI do Yii e depois +executa os callbacks de bootstrap configurados. Ele não cria nem executa um +runner de aplicação do Yii, então a aplicação de terceiros continua dona do +ponto de entrada e do ciclo de vida do processo. + +Use os grupos de configuração de console quando precisar de serviços comuns +e serviços seguros para o console. Use os grupos web apenas quando precisar +intencionalmente de definições específicas da web do grupo `di-web`, como as +factories HTTP da PSR-17 ou dependências de middlewares web. + +## Obtenha serviços do Yii a partir da aplicação hospedeira + +Use o adaptador a partir da aplicação de terceiros: + +```php +get(ApplicationParams::class); + +echo $params->name; +``` + +Em integrações reais, prefira obter os serviços da sua própria aplicação em +vez da infraestrutura do framework. Por exemplo, exponha `InvoiceSender`, +`ReportBuilder` ou `CatalogImporter` a partir do Yii e chame esse serviço na +aplicação hospedeira. + +## Mantenha os limites explícitos + +Evite misturar ciclos de vida de requisição. Deixe a aplicação hospedeira +continuar dona da requisição e da resposta HTTP. Deixe o Yii fornecer +serviços que não pressupõem que o Yii está tratando a requisição atual. + +Bons candidatos para reaproveitamento: + +- serviços de domínio; +- repositórios e conexões com banco de dados; +- mailers e serviços de notificação; +- loggers; +- validadores; +- produtores de fila; +- serviços de aplicação no estilo de comandos. + +Evite trazer actions, pilhas de middlewares, sessões, middleware de CSRF ou +renderização de views do Yii, a menos que a aplicação hospedeira delegue +explicitamente essa responsabilidade inteira ao Yii. + +## Grupos de configuração + +O template de aplicação padrão separa a configuração por grupo: + +- `di` é compartilhado pelos pontos de entrada web e de console; +- `di-console` é específico do console e inclui `di` no template; +- `di-web` é específico da web e inclui `di`; +- `params-console` e `params-web` estendem o `params` comum. + +Escolha o menor grupo que contém os serviços de que você precisa. Se a +aplicação hospedeira só precisa de serviços de domínio, mantenha essas +definições em `config/common/di/*.php` para que tanto o Yii quanto a +aplicação de terceiros possam usá-las sem dependências exclusivas da web. + +Depois de alterar `config/configuration.php`, reconstrua o merge plan: + +```shell +composer yii-config-rebuild +``` + +## Tratamento de erros e logs + +A aplicação hospedeira deve continuar responsável pelo tratamento de erros +de nível mais alto. Capture as exceções na fronteira da integração quando a +aplicação hospedeira precisar convertê-las na sua própria resposta ou +formato de erro. + +Os serviços do Yii ainda podem usar `Psr\Log\LoggerInterface`. Configure o +logger do Yii para gravar no mesmo destino da aplicação hospedeira ou +conecte as duas aplicações ao mesmo logger PSR-3. + +## Processos hospedeiros de longa duração + +Se a aplicação de terceiros for um worker, um daemon ou um servidor com +event loop, evite estado mutável compartilhado nos serviços. Os serviços do +Yii obtidos do container são compartilhados por padrão, então projete-os +como serviços sem estado ou crie um container novo para cada job isolado +quando dependências com estado forem inevitáveis. diff --git a/src/pt-BR/cookbook/working-on-windows.md b/src/pt-BR/cookbook/working-on-windows.md new file mode 100644 index 00000000..c482e356 --- /dev/null +++ b/src/pt-BR/cookbook/working-on-windows.md @@ -0,0 +1,91 @@ +# Trabalhando no Windows + +Aplicações Yii geralmente rodam no Linux em produção. No Windows, escolha um +fluxo de trabalho local que fique próximo desse ambiente e mantenha o +desempenho do sistema de arquivos previsível. + +## Configuração recomendada: WSL + +Use o [Windows Subsystem for +Linux](https://learn.microsoft.com/windows/wsl/) com uma distribuição Linux +como o Ubuntu. Instale PHP, Composer, Git e Make dentro do WSL e depois +clone o projeto no sistema de arquivos do Linux: + +```shell +cd ~ +git clone https://github.com/yiisoft/app.git my-app +cd my-app +composer install +``` + +Mantenha o projeto no sistema de arquivos do WSL, por exemplo +`/home/user/projects/my-app`. Evite trabalhar a partir de um caminho montado +do Windows, como `/mnt/c/Users/user/projects/my-app`; ele é muito mais lento +para o Composer, os testes e as ferramentas que leem muitos arquivos +pequenos. + +Você pode abrir o projeto em editores do Windows por meio da integração com +o WSL. No PhpStorm, abra o projeto a partir do sistema de arquivos do +WSL. No VS Code, use a extensão WSL e abra a pasta de dentro da sessão do +WSL. + +## Docker com WSL + +O Docker Desktop com o backend WSL também é uma boa configuração no +Windows. Mantenha o projeto no sistema de arquivos do WSL e rode os comandos +do Docker a partir do WSL: + +```shell +make build +make up +make yii +make test +``` + +Isso mantém os bind mounts rápidos e dá aos containers caminhos Linux que +batem com as ferramentas usadas pelos templates de aplicação do Yii. + +Se você precisar de links para a IDE nos stack traces de debug, defina +`APP_HOST_PATH` com o caminho do projeto que a sua IDE consegue abrir. + +## Git Bash + +O [Git for Windows](https://git-scm.com/downloads/win) instala o Git Bash e +ferramentas Unix comuns. Ele pode bastar quando você quer rodar a aplicação +diretamente no Windows, sem WSL nem Docker. + +Use esta opção quando o seu projeto não depende de extensões ou scripts de +shell exclusivos do Linux. Teste os mesmos comandos que você espera que os +contribuidores usem: + +```shell +composer install +composer test +``` + +Se o projeto usa `make`, o Git for Windows inclui um ambiente Bash, mas a +disponibilidade do `make` depende da sua instalação local. Instale-o +separadamente quando necessário. + +## PowerShell e CMD + +O PowerShell e o CMD conseguem rodar PHP e Composer, mas diferem do ambiente +comum de servidores Linux em aspas, variáveis de ambiente, caminhos e +utilitários de shell. Use-os apenas para comandos simples. + +Para o desenvolvimento regular com Yii no Windows, prefira o WSL ou o Docker +com WSL. + +## Escolhendo um fluxo de trabalho + +Use o WSL quando quiser o ambiente local mais parecido com um servidor Linux +e não precisar de containers para cada serviço. + +Use o Docker com WSL quando quiser a aplicação, o banco de dados e outros +serviços descritos em arquivos do Compose. + +Use o Git Bash para projetos pequenos ou verificações rápidas que rodam +diretamente no Windows. + +Use o PowerShell ou o CMD quando se sabe que o comando é independente de +plataforma. diff --git a/src/pt-BR/guide/caching/data.md b/src/pt-BR/guide/caching/data.md new file mode 100644 index 00000000..6fd8e6c8 --- /dev/null +++ b/src/pt-BR/guide/caching/data.md @@ -0,0 +1,218 @@ +# Cache de dados + +O cache de dados consiste em guardar algumas variáveis PHP no cache e +recuperá-las dele mais tarde. Ele também é a base para recursos de cache +mais avançados, como o cache de páginas. + +Para usar o cache, instale o pacote +[yiisoft/cache](https://github.com/yiisoft/cache): + +```shell +composer require yiisoft/cache +``` + +O código a seguir é um padrão típico de uso do cache de dados, em que +`$cache` se refere a uma instância de `Cache` do pacote: + +```php +public function getTopProducts(\Yiisoft\Cache\CacheInterface $cache): array +{ + $key = ['top-products', $count = 10]; + + // Tenta recuperar $data do cache. + $data = $cache->getOrSet($key, function (\Psr\SimpleCache\CacheInterface $cache) use ($count) { + // $data não está no cache, então calcula do zero. + return getTopProductsFromDatabase($count); + }, 3600); + + return $data; +} +``` + +Quando o cache tem dados associados à `$key`, ele retorna o valor em cache. +Caso contrário, executa a função anônima passada para calcular o valor a ser +guardado no cache e retornado. + +Se a função anônima precisar de dados do escopo externo, você pode passá-los +com a instrução `use`. + +## Drivers de cache + +O serviço de cache usa drivers de cache compatíveis com a +[PSR-16](https://www.php-fig.org/psr/psr-16/), que representam vários tipos +de armazenamento, como memória, arquivos e bancos de dados. + +O Yii fornece os seguintes drivers: + +- `NullCache` — um substituto de cache que não faz cache de verdade. O + objetivo desse driver é simplificar o código que precisa verificar se há + cache disponível. Por exemplo, durante o desenvolvimento ou se o servidor + não tiver suporte real a cache, você pode configurar o serviço de cache + para usar esse driver. Quando você habilitar o suporte real a cache, pode + trocar para o driver correspondente. Nos dois casos, você pode usar o + mesmo código, sem verificações extras. +- `ArrayCache` — faz cache apenas durante a requisição atual, guardando os + valores em um array. +- [APCu](https://github.com/yiisoft/cache-apcu) - usa a extensão + [APC](https://www.php.net/manual/en/book.apcu.php) do PHP. Você pode + considerar esta a opção mais rápida ao lidar com cache em uma aplicação + centralizada e robusta (por exemplo, um servidor, sem load balancers + dedicados etc.). +- [Banco de dados](https://github.com/yiisoft/cache-db) — usa uma tabela do + banco de dados para guardar os dados em cache. +- [Arquivo](https://github.com/yiisoft/cache-file) — usa arquivos comuns + para guardar os dados em cache. É especialmente adequado para guardar + grandes blocos de dados, como o conteúdo de páginas. +- [Memcached](https://github.com/yiisoft/cache-memcached) — usa a extensão + [memcached](https://secure.php.net/manual/en/book.memcached.php) do + PHP. Você pode considerar esta a opção mais rápida ao lidar com cache em + uma aplicação distribuída + (por exemplo, com vários servidores, load balancers etc.) +- [Wincache](https://github.com/yiisoft/cache-wincache) — usa a extensão [WinCache](https://iis.net/downloads/microsoft/wincache-extension) + ([veja também](https://secure.php.net/manual/en/book.wincache.php)) do PHP. + +[Você encontra mais drivers no +packagist.org](https://packagist.org/providers/psr/simple-cache-implementation). + +> [!TIP] +> Você pode usar armazenamentos de cache diferentes na mesma aplicação. Uma estratégia comum é: +> - Usar armazenamento de cache em memória para dados pequenos, mas usados constantemente (por exemplo, estatísticas) +> - Usar armazenamento de cache em arquivo ou em banco de dados para dados grandes e usados com menos frequência (por exemplo, conteúdo de páginas) + +Os drivers de cache normalmente são configurados em um [container de injeção +de dependência](../concept/di-container.md), para que possam ser +configurados e acessados globalmente. + +Como todos os drivers de cache suportam o mesmo conjunto de APIs, você pode +trocar o driver de cache subjacente por outro. Basta reconfigurar a +aplicação, sem modificar o código que usa o cache. + +### Chaves de cache + +Uma chave identifica de forma única cada item de dados guardado no cache. Ao +guardar um item, você precisa especificar uma chave para ele. Depois, ao +recuperar o item, você deve informar a chave correspondente. + +Você pode usar uma string ou um valor arbitrário como chave de cache. Quando +a chave não é uma string, ela é serializada automaticamente em uma string. + +Uma estratégia comum para definir uma chave de cache é incluir todos os +fatores determinantes em um array. + +Quando aplicações diferentes usam o mesmo armazenamento de cache, você deve +especificar um prefixo de chave de cache único para cada aplicação, para +evitar conflitos de chaves. Você pode fazer isso usando o decorator +`\Yiisoft\Cache\PrefixedCache`: + +```php +$arrayCacheWithPrefix = new \Yiisoft\Cache\PrefixedCache(new \Yiisoft\Cache\ArrayCache(), 'myapp_'); +$cache = new \Yiisoft\Cache\Cache($arrayCacheWithPrefix); +``` + +### Expiração do cache + +Um item de dados guardado no cache fica lá para sempre, a menos que seja +removido por alguma política de cache. Por exemplo, o espaço do cache fica +cheio e o armazenamento remove os dados mais antigos. Para mudar esse +comportamento, você pode definir um parâmetro TTL ao chamar um método que +guarda um item: + +```php +$ttl = 3600; +$data = $cache->getOrSet($key, function (\Psr\SimpleCache\CacheInterface $cache) use ($count) { +return getTopProductsFromDatabase($count); +}, $ttl); +``` + +O parâmetro `$ttl` indica por quantos segundos o item pode continuar válido +no cache. Ao recuperar o item, se o tempo de expiração já tiver passado, o +método executa a função e grava o valor resultante no cache. + +Você pode definir o TTL padrão do cache: + +```php +$cache = new \Yiisoft\Cache\Cache($arrayCache, 60 * 60); // 1 hora +``` + +Além disso, você pode invalidar uma chave de cache explicitamente: + +```php +$cache->remove($key); +``` + +### Dependências de invalidação + +Além da configuração de expiração, mudanças nas chamadas **dependências de +invalidação** também podem invalidar um item em cache. Por exemplo, +`\Yiisoft\Cache\Dependency\FileDependency` representa a dependência da data +de modificação de um arquivo. Quando essa dependência muda, significa que +algo modificou o arquivo correspondente. Como resultado, qualquer conteúdo +desatualizado do arquivo encontrado no cache deve ser invalidado. + +As dependências de cache são objetos de classes descendentes de +`\Yiisoft\Cache\Dependency\Dependency`. Ao guardar um item no cache, você +pode passar junto um objeto de dependência de cache associado. Por exemplo, + +```php +/** + * @var callable $callable + * @var \Yiisoft\Cache\CacheInterface $cache + */ + +use Yiisoft\Cache\Dependency\TagDependency; + +// Grava vários valores no cache, marcando ambos com uma tag. +$cache->getOrSet('item_42_price', $callable, null, new TagDependency('item_42')); +$cache->getOrSet('item_42_total', $callable, 3600, new TagDependency('item_42')); + +// Dispara a invalidação pela tag. +TagDependency::invalidate($cache, 'item_42'); +``` + +Veja um resumo das dependências de cache disponíveis: + +- `\Yiisoft\Cache\Dependency\ValueDependency`: invalida o cache quando o + valor especificado muda. +- `\Yiisoft\Cache\Dependency\CallbackDependency`: invalida o cache quando o + resultado do callback PHP especificado é diferente. +- `\Yiisoft\Cache\Dependency\FileDependency`: invalida o cache quando a data + da última modificação do arquivo é diferente. +- `\Yiisoft\Cache\Dependency\TagDependency`: associa um item em cache a uma + ou várias tags. Você pode invalidar os itens em cache com as tags + especificadas chamando `TagDependency::invalidate()`. + +Você pode combinar várias dependências usando +`\Yiisoft\Cache\Dependency\AnyDependency` ou +`\Yiisoft\Cache\Dependency\AllDependencies`. + +Para implementar a sua própria dependência, estenda +`\Yiisoft\Cache\Dependency\Dependency`. + +### Prevenção do efeito manada + +O [efeito manada (cache +stampede)](https://en.wikipedia.org/wiki/Cache_stampede) é um tipo de falha +em cascata que pode ocorrer quando sistemas de computação massivamente +paralelos com mecanismos de cache ficam sob carga alta. Esse comportamento +às vezes também é chamado de dog-piling. + +O `\Yiisoft\Cache\Cache` usa um algoritmo embutido de "expiração antecipada +probabilística" ("Probably early expiration") que evita o efeito manada. +Esse algoritmo simula aleatoriamente um cache miss para um usuário enquanto +os outros continuam recebendo o valor em cache. Você pode controlar o +comportamento dele com o quinto parâmetro opcional de `getOrSet()`, um valor +float chamado `$beta`. Por padrão, beta é `1.0`, o que costuma ser +suficiente. Quanto maior o valor, mais cedo o cache será recriado. + +```php +/** + * @var mixed $key + * @var callable $callable + * @var \DateInterval $ttl + * @var \Yiisoft\Cache\CacheInterface $cache + * @var \Yiisoft\Cache\Dependency\Dependency $dependency + */ + +$beta = 2.0; +$cache->getOrSet($key, $callable, $ttl, $dependency, $beta); +``` diff --git a/src/pt-BR/guide/caching/overview.md b/src/pt-BR/guide/caching/overview.md new file mode 100644 index 00000000..67763a49 --- /dev/null +++ b/src/pt-BR/guide/caching/overview.md @@ -0,0 +1,22 @@ +# Cache + +O cache é uma forma barata e eficaz de melhorar o desempenho de uma +aplicação. Ao armazenar dados relativamente estáticos no cache e servi-los +a partir dele quando solicitados, a aplicação economiza o tempo que, de +outra forma, precisaria para gerar os dados do zero a cada vez. + +O cache pode ocorrer em diferentes níveis e lugares de uma aplicação. No +lado do servidor, no nível mais baixo, o cache pode ser usado para armazenar +dados básicos, como uma lista com as informações dos artigos mais recentes +obtida do banco de dados; e, no nível mais alto, o cache pode ser usado para +armazenar fragmentos ou páginas web inteiras, como o resultado da +renderização dos artigos mais recentes. No lado do cliente, você pode usar o +cache HTTP para manter o conteúdo das páginas visitadas mais recentemente no +cache do navegador. + +O Yii suporta todos estes mecanismos de cache: + +* [Cache de dados](data.md) +* Cache de fragmentos +* Cache de páginas +* Cache HTTP diff --git a/src/pt-BR/guide/concept/aliases.md b/src/pt-BR/guide/concept/aliases.md new file mode 100644 index 00000000..273be6e8 --- /dev/null +++ b/src/pt-BR/guide/concept/aliases.md @@ -0,0 +1,148 @@ +# Aliases + +Você pode usar aliases para representar caminhos de arquivos ou URLs, +evitando escrever caminhos absolutos ou URLs fixos no seu projeto. Um alias +deve começar com o caractere `@` para se diferenciar de caminhos de arquivos +e URLs normais. Um alias definido sem o `@` inicial receberá o prefixo `@`. + +A aplicação Yii padrão tem alguns aliases predefinidos em +`config/params.php`. Por exemplo, o alias `@public` representa o caminho da +raiz web; `@baseUrl` representa a URL base da aplicação web em execução. + +## Definindo aliases + +Você pode definir um alias no `config/params.php` da aplicação: + +```php +return [ + // ... + + 'yiisoft/aliases' => [ + 'aliases' => [ + // ... + + // um alias de um caminho de arquivo + '@foo' => '/path/to/foo', + + // um alias de uma URL + '@bar' => 'https://www.example.com', + + // um alias de um arquivo concreto que contém a classe \foo\Bar + '@foo/Bar.php' => '/definitely/not/foo/Bar.php', + ], + ], +]; +``` + +> [!NOTE] +> O caminho de arquivo ou URL representado pelo alias *não* precisa necessariamente se referir a um arquivo ou recurso existente. + +A partir de um alias definido, você pode derivar um novo alias acrescentando +uma barra `/` seguida de um ou mais segmentos de caminho. Por exemplo, +`@foo` é um alias raiz, enquanto `@foo/bar/file.php` é um alias derivado. + +Você pode definir um alias usando outro alias (raiz ou derivado): + +```php +'@foobar' => '@foo/bar', +``` + +O parâmetro `yiisoft/aliases` inicializa o serviço `Aliases` do pacote +[`yiisoft/aliases`](https://github.com/yiisoft/aliases). Você pode definir +aliases extras em tempo de execução usando o serviço: + +```php +use \Yiisoft\Aliases\Aliases; + +public function actionIndex(Aliases $aliases) +{ + $aliases->set('@uploads', '@root/uploads'); +} +``` + +## Usando aliases na configuração + +É preferível resolver os aliases no nível da configuração, para que os +serviços recebam URLs e caminhos como strings prontas para uso: + +```php + static fn (Aliases $aliases) => new FileCache( + $aliases->get($params['yiisoft/cache-file']['fileCache']['path']) + ), +]; +``` + +## Resolvendo aliases + +Você pode usar o serviço `Aliases` para resolver um alias ou alias derivado +no caminho de arquivo ou URL que ele representa: + +```php +use \Yiisoft\Aliases\Aliases; + +public function actionIndex(Aliases $aliases) +{ + $foo = $aliases->get('@foo'); // /path/to/foo + $bar = $aliases->get('@bar'); // https://www.example.com + $file = $aliases->get('@foo/bar/file.php'); // /path/to/foo/bar/file.php +} +``` + +O caminho/URL representado por um alias derivado é determinado substituindo +a parte do alias raiz pelo caminho/URL correspondente. + +> [!NOTE] +> O método `get()` não verifica se o caminho/URL resultante se refere a um arquivo ou recurso existente. + + +Um alias raiz também pode conter caracteres de barra `/`. O método `get()` é +inteligente o suficiente para identificar qual parte de um alias é o alias +raiz e, assim, determina corretamente o caminho de arquivo ou URL +correspondente: + +```php +use \Yiisoft\Aliases\Aliases; + +public function actionIndex(Aliases $aliases) +{ + $aliases->set('@foo', '/path/to/foo'); + $aliases->set('@foo/bar', '/path2/bar'); + + $aliases->get('@foo/test/file.php'); // /path/to/foo/test/file.php + $aliases->get('@foo/bar/file.php'); // /path2/bar/file.php +} +``` + +Se `@foo/bar` não estiver definido como alias raiz, a última instrução +exibiria `/path/to/foo/bar/file.php`. + + +## Aliases predefinidos + +A [aplicação Yii](https://github.com/yiisoft/app) predefine um conjunto de +aliases para referenciar caminhos de arquivos e URLs de uso comum: + +- `@root` - a pasta base da aplicação em execução. +- `@assets` - pasta pública da aplicação onde ela publica os assets. +- `@assetsUrl` - URL da pasta base com os assets publicados. +- `@baseUrl` - a URL base da aplicação web em execução. O padrão é `/`. +- `@npm` - pasta de pacotes node. +- `@bower` - pasta de pacotes bower. +- `@vendor` - a pasta `vendor` do Composer. +- `@public` - pasta publicamente acessível da aplicação, que contém o + `index.php`. +- `@runtime` - o caminho de runtime da aplicação em execução. O padrão é + `@root/runtime`. +- `@layout` - a pasta com os layouts. +- `@resources` - pasta com views, fontes de assets e outros recursos. +- `@views` - pasta base dos templates de view da aplicação. diff --git a/src/pt-BR/guide/concept/autoloading.md b/src/pt-BR/guide/concept/autoloading.md new file mode 100644 index 00000000..7038ac31 --- /dev/null +++ b/src/pt-BR/guide/concept/autoloading.md @@ -0,0 +1,39 @@ +# Autoload de classes + +Como o Yii usa o [Composer](https://getcomposer.org) para gerenciar pacotes, +ele carrega automaticamente as classes desses pacotes sem a necessidade de +fazer `require` dos arquivos explicitamente. Ao instalar pacotes, o +Composer gera um [autoloader compatível com +PSR-4](https://www.php-fig.org/psr/psr-4/). Para usá-lo, faça +`require_once` do autoloader `/vendor/autoload.php` no seu arquivo de ponto +de entrada `index.php`. + +Você pode usar o autoloader não só para os pacotes instalados, mas também +para a sua aplicação, já que ela também é um pacote. Para carregar classes +de um determinado namespace, adicione o seguinte ao `composer.json`: + +```json +{ + "autoload": { + "psr-4": { + "App\\": "src/" + } + } +} +``` + +Onde `App\\` é o namespace raiz e `src/` é a pasta onde ficam suas +classes. Você pode adicionar mais raízes de código-fonte se +precisar. Depois, execute `composer dump-autoload` ou simplesmente `composer +du`, e as classes dos namespaces correspondentes passarão a ser carregadas +automaticamente. + +Se você precisar de autoload específico do ambiente de desenvolvimento, que +não seja usado ao executar o Composer com a flag `--no-dev`, adicione-o à +seção `autoload-dev` em vez de `autoload`. + +## Referências + +- [PSR-4: Autoloader](https://www.php-fig.org/psr/psr-4/). +- [Guia do Composer sobre + autoload](https://getcomposer.org/doc/01-basic-usage.md#autoloading). diff --git a/src/pt-BR/guide/concept/configuration.md b/src/pt-BR/guide/concept/configuration.md new file mode 100644 index 00000000..9177e7e8 --- /dev/null +++ b/src/pt-BR/guide/concept/configuration.md @@ -0,0 +1,464 @@ +# Configuração + +Há muitas formas de configurar a sua aplicação. Aqui o foco são os conceitos +usados no [template de projeto padrão](https://github.com/yiisoft/app). + +As configurações do Yii3 fazem parte da aplicação. Você pode mudar muitos +aspectos do funcionamento da aplicação editando a configuração na pasta +`config/`. + +## Plugin de configuração + +O template de aplicação usa o +[yiisoft/config](https://github.com/yiisoft/config) como plugin do Composer +para montar as configurações. + +Os pacotes fornecem configurações padrão por meio de [grupos de +configuração](https://github.com/yiisoft/config#config-groups) definidos na +chave `config-plugin` da seção `extra` do `composer.json`: + +```json +"extra": { + "config-plugin-options": { + "source-directory": "config", + }, + "config-plugin": { + "params": "params.php", + "web": "web.php" + } +} +``` + +Depois que o Composer atualiza os arquivos de autoload, como durante +`dump-autoload`, `install`, `require`, `update` ou `remove`, o plugin +procura configurações nos pacotes instalados e grava um merge plan em +`config/.merge-plan.php`. O merge plan declara a ordem em que as +configurações encontradas são mescladas na configuração final, que é passada +ao [container de DI](di-container.md). + +Em tempo de execução, `Yiisoft\Config\Config` carrega os grupos de +configuração definidos de acordo com esse merge plan. As configurações são +lidas em três camadas: + +1. Configurações dos pacotes em vendor, com os valores padrão. +2. Configurações do pacote raiz, da pasta `config/` da aplicação. +3. Configurações da aplicação específicas de cada ambiente. + +> [!WARNING] +> Chaves de configuração com o mesmo nome não são permitidas dentro de uma mesma camada. + +O template de aplicação guarda as configurações em um arquivo PHP em vez de +JSON inline: + +```json +"extra": { + "config-plugin-file": "config/configuration.php" +} +``` + +Esse arquivo retorna as mesmas chaves que você poderia definir no +`composer.json`: `config-plugin`, `config-plugin-options` e +`config-plugin-environments`. + +```php +use App\Environment; + +return [ + 'config-plugin-options' => [ + 'source-directory' => 'config', + ], + 'config-plugin' => [ + 'params' => 'common/params.php', + 'params-web' => [ + '$params', + 'web/params.php', + ], + 'params-console' => [ + '$params', + 'console/params.php', + ], + 'bootstrap' => 'common/bootstrap.php', + 'bootstrap-web' => '$bootstrap', + 'bootstrap-console' => '$bootstrap', + 'di' => 'common/di/*.php', + 'di-web' => [ + '$di', + 'web/di/*.php', + ], + 'di-console' => '$di', + 'di-delegates' => [], + 'di-delegates-console' => '$di-delegates', + 'di-delegates-web' => '$di-delegates', + 'di-providers' => [], + 'di-providers-web' => '$di-providers', + 'di-providers-console' => '$di-providers', + 'events' => [], + 'events-web' => '$events', + 'events-console' => '$events', + 'routes' => 'common/routes.php', + ], + 'config-plugin-environments' => [ + Environment::DEV => [ + 'params' => [ + 'environments/dev/params.php', + ], + ], + Environment::TEST => [ + 'params' => [ + 'environments/test/params.php', + ], + ], + Environment::PROD => [ + 'params' => [ + 'environments/prod/params.php', + ], + ], + ], +]; +``` + +Os nomes dos grupos de configuração são as chaves do mapeamento. Os valores +são caminhos de arquivos relativos à opção `source-directory`, cujo padrão é +a pasta que contém o `composer.json`. + +- Um valor string carrega um arquivo. +- Um array carrega e mescla vários arquivos na ordem indicada. +- `?` marca um arquivo opcional. +- `*` marca um caminho com curinga. +- `$group` referencia outro grupo de configuração a ser mesclado. + +O grupo `params` é especial: por padrão, os valores dele ficam disponíveis +como `$params` nos outros arquivos de configuração. + +Leia mais na [documentação do +yiisoft/config](https://github.com/yiisoft/config/blob/master/README.md). + +## Arquivos de configuração + +Agora que você sabe como o plugin monta as configurações, veja a estrutura +da pasta `config/` usada pelo template de aplicação padrão: + +``` +common/ + bootstrap.php + params.php + routes.php + di/ + *.php +console/ + params.php +environments/ + dev/ + params.php + prod/ + params.php + test/ + params.php +web/ + params.php + di/ + *.php +.merge-plan.php +configuration.php +``` + +Essa estrutura segue os grupos definidos em `config/configuration.php`: + +- `params`, `params-web` e `params-console` carregam arquivos de parâmetros + de `common/`, `web/` e `console/`. +- `di` e `di-web` carregam definições do container de `common/di/` e + `web/di/`. +- `routes` e `bootstrap` carregam `common/routes.php` e + `common/bootstrap.php`. +- `config-plugin-environments` acrescenta arquivos de parâmetros específicos + de cada ambiente de `environments/dev/`, `environments/test/` e + `environments/prod/`. + +Em tempo de execução, `.merge-plan.php` guarda o merge plan montado a partir +de `configuration.php`. + +### Configuração do container + +A aplicação é formada por serviços registrados em um [container de +dependências](di-container.md). No template padrão, as definições diretas do +container ficam em `config/common/di/*.php` e `config/web/di/*.php`. + +As definições de `common/di/` são compartilhadas pelos pontos de entrada web +e de console. O grupo `di-web` acrescenta definições específicas da web, de +`web/di/`. Atualmente, o grupo `di-console` reaproveita as definições +compartilhadas de `di`, sem arquivos extras. + +```php + [ + '__construct()' => [ + 'name' => $params['application']['name'], + 'charset' => $params['application']['charset'], + 'locale' => $params['application']['locale'], + ], + ], +]; +``` + +O plugin de configuração passa a variável especial `$params` para todos os +arquivos de configuração. A definição a usa para configurar os serviços. + +O guia ["Injeção de dependência e container"](di-container.md) descreve em +detalhes o formato da configuração e a ideia de injeção de dependência. + +Por conveniência, existe uma convenção de nomes para chaves string +personalizadas: + +1. Prefixe com o nome do pacote, como em + `yiisoft/cache-file/custom-definition`. +2. Se a configuração for da própria aplicação, omita o prefixo do pacote, + como em `custom-definition`. + +### Service providers + +Como alternativa a registrar dependências diretamente, você pode usar +service providers. Um service provider é uma classe que retorna um conjunto +reutilizável de definições e extensões do container. + +O template padrão expõe três grupos de configuração para service providers: +`di-providers`, `di-providers-web` e `di-providers-console`. No template, +eles são inicializados como arrays vazios em `config/configuration.php`, e +depois você pode preenchê-los inline ou fazê-los carregar valores de +arquivos. + +Prefira a configuração direta do container para serviços da aplicação com +definição simples: um nome de classe, a implementação de uma interface, +argumentos do construtor vindos de `$params` ou uma closure que cria um +único serviço. + +Use um service provider quando o próprio registro for uma unidade +reutilizável: + +- Um pacote registra vários serviços, aliases ou extensões relacionados. +- O registro de um serviço também precisa de definições de apoio. +- O mesmo registro deve ser reutilizado em várias aplicações. +- O registro depende de classes opcionais ou de decisões específicas do + ambiente. + +Use uma classe factory quando a lógica de construção pertence a um único +serviço. Uma factory retorna um objeto. Um service provider retorna +definições para vários serviços relacionados. + +```php +/* @var array $params */ + +// ... +use App\Provider\CacheProvider; +use App\Provider\MiddlewareProvider; +// ... + +return [ + // ... + 'yiisoft/yii-web/middleware' => MiddlewareProvider::class, + 'yiisoft/cache/cache' => new CacheProvider($params['yiisoft/cache-file']['file-cache']['path']), + // ... +]; +``` + +Nesta configuração, as chaves são os nomes dos providers. Por convenção, +eles seguem o formato `vendor/package-name/provider-name`. Os valores são +nomes de classes de provider ou instâncias de provider. Essas classes podem +ser criadas no próprio projeto ou fornecidas por um pacote. + +Se você precisar configurar algumas opções de um serviço, da mesma forma que +na configuração direta do container, pegue os valores de `$params` e +passe-os aos providers. + +O provider deve implementar `Yiisoft\Di\ServiceProviderInterface`. Abaixo +está um provider para um serviço de cache: + +```php +use Psr\Container\ContainerInterface; +use Psr\SimpleCache\CacheInterface; +use Yiisoft\Aliases\Aliases; +use Yiisoft\Cache\Cache; +use Yiisoft\Cache\CacheInterface as YiiCacheInterface; +use Yiisoft\Cache\File\FileCache; +use Yiisoft\Di\ServiceProviderInterface; + +final readonly class CacheProvider implements ServiceProviderInterface +{ + public function __construct( + private string $cachePath = '@runtime/cache' + ) + { + } + + public function getDefinitions(): array + { + return [ + CacheInterface::class => function (ContainerInterface $container) { + $aliases = $container->get(Aliases::class); + + return new FileCache($aliases->get($this->cachePath)); + }, + YiiCacheInterface::class => Cache::class, + ]; + } + + public function getExtensions(): array + { + return []; + } +} +``` + +### Rotas + +Você pode configurar como a aplicação web responde a determinadas URLs em +`config/common/routes.php`: + +```php +use App\Web; +use Yiisoft\Router\Group; +use Yiisoft\Router\Route; + +return [ + Group::create() + ->routes( + Route::get('/') + ->action(Web\HomePage\Action::class) + ->name('home'), + ), +]; +``` + +Leia mais sobre isso em ["Rotas"](../runtime/routing.md). + +### Eventos + +Muitos serviços emitem eventos aos quais você pode se associar. O template +padrão define três grupos de configuração de eventos em +`config/configuration.php`: `events`, `events-web` e `events-console`. Eles +vêm vazios por padrão, mas você pode preenchê-los inline ou apontá-los para +arquivos de configuração de eventos. + +A configuração é um array em que as chaves são os nomes dos eventos e os +valores são arrays de handlers: + +```php +return [ + EventName::class => [ + // Uma closure comum, que será chamada pelo Dispatcher "como está". + static fn (EventName $event) => someStuff($event), + + // Uma closure comum com uma dependência extra. Todos os parâmetros depois do primeiro (o próprio evento) + // serão resolvidos pelo seu container de DI por meio do `yiisoft/injector`. + static fn (EventName $event, DependencyClass $dependency) => someStuff($event), + + // Um exemplo com um callable comum. Se o método `staticMethodName` tiver dependências, + // elas serão resolvidas da mesma forma que no exemplo anterior. + [SomeClass::class, 'staticMethodName'], + + // Métodos não estáticos também são permitidos. Nesse caso, `SomeClass` será instanciada pelo seu container de DI. + [SomeClass::class, 'methodName'], + + // Um objeto de uma classe que implementa o método `__invoke` + new InvokableClass(), + + // Nesse caso, a `InvokableClass` com o método `__invoke` será instanciada pelo seu container de DI + InvokableClass::class, + + // Qualquer definição de classe invocável pode estar aqui, desde que `$container->has('the definition')` seja true. + 'di-alias' + ], +]; +``` + +Leia mais sobre isso em ["Eventos"](events.md). + + +### Parâmetros + +Os parâmetros base ficam em `config/common/params.php`. Depois, eles são +estendidos por `config/web/params.php`, `config/console/params.php` e pelos +arquivos específicos de cada ambiente em `config/environments/`. + +> [!TIP] +> Não use parâmetros, constantes ou variáveis de ambiente diretamente na sua aplicação; em vez disso, configure +> os serviços. + +O `common/params.php` da aplicação padrão é assim: + +```php + require __DIR__ . '/application.php', + + 'yiisoft/aliases' => [ + 'aliases' => require __DIR__ . '/aliases.php', + ], + + 'yiisoft/view' => [ + 'basePath' => null, + 'parameters' => [ + 'assetManager' => Reference::to(AssetManager::class), + 'applicationParams' => Reference::to(ApplicationParams::class), + 'aliases' => Reference::to(Aliases::class), + 'urlGenerator' => Reference::to(UrlGeneratorInterface::class), + 'currentRoute' => Reference::to(CurrentRoute::class), + ], + ], + + 'yiisoft/yii-view-renderer' => [ + 'viewPath' => null, + 'layout' => '@src/Web/Shared/Layout/Main/layout.php', + 'injections' => [ + Reference::to(CsrfViewInjection::class), + ], + ], +]; +``` + +Por conveniência, existe uma convenção de nomes para os parâmetros: + +1. Agrupe os parâmetros pelo nome do pacote, como em `yiisoft/cache-file`. +2. Se os parâmetros forem da própria aplicação, como em `application`, omita + o prefixo do pacote. +3. Se houver muitos serviços no pacote, como `file-target` e `file-rotator` + no pacote `yiisoft/log-target-file`, agrupe os parâmetros pelo nome do + serviço. +4. Use `enabled` como nome de parâmetro para poder desabilitar ou habilitar + um serviço, como em `yiisoft/yii-debug`. + +### Configurações de pacotes + +O plugin de configuração não copia automaticamente as configurações dos +pacotes em vendor. Ele as carrega diretamente de `vendor/` como camada +vendor e as combina com as camadas do pacote raiz e específicas de cada +ambiente. + +Se você quiser personalizar um arquivo de configuração de um pacote na sua +aplicação, use o comando do Composer `yii-config-copy` para copiá-lo para a +sua pasta `config/`, normalmente em `config/packages/`. Depois de copiado, o +arquivo passa a fazer parte da camada do pacote raiz e pode sobrescrever os +padrões de vendor. + +O merge plan guardado em `.merge-plan.php` define como os grupos de +configuração são montados. Se você adicionar novos arquivos ou pastas de +configuração e atualizar a configuração do pacote raiz, reconstrua o merge +plan com `composer yii-config-rebuild`. diff --git a/src/pt-BR/guide/concept/di-container.md b/src/pt-BR/guide/concept/di-container.md new file mode 100644 index 00000000..db08ba66 --- /dev/null +++ b/src/pt-BR/guide/concept/di-container.md @@ -0,0 +1,351 @@ +# Injeção de dependência e container + +## Injeção de dependência + +Há duas formas de reaproveitar código em OOP: herança e composição. + +A herança é simples: + +```php +class Cache +{ + public function getCachedValue($key) + { + // .. + } +} + +final readonly class CachedWidget extends Cache +{ + public function render(): string + { + $output = $this->getCachedValue('cachedWidget'); + if ($output !== null) { + return $output; + } + // ... + } +} +``` + +O problema aqui é que essas duas classes ficam acopladas ou interdependentes +sem necessidade, o que as torna mais frágeis. + +Outra forma de resolver isso é a composição: + +```php +interface CacheInterface +{ + public function getCachedValue($key); +} + +final readonly class Cache implements CacheInterface +{ + public function getCachedValue($key) + { + // .. + } +} + +final readonly class CachedWidget +{ + public function __construct( + private CacheInterface $cache + ) + { + } + + public function render(): string + { + $output = $this->cache->getCachedValue('cachedWidget'); + if ($output !== null) { + return $output; + } + // ... + } +} +``` + +Evitamos a herança desnecessária e usamos `CacheInterface` no `CacheWidget` +para reduzir o acoplamento. Você pode trocar a implementação do cache sem +alterar o `CachedWidget`, então ele fica mais estável. Quanto menos edições +forem feitas no código, menor a chance de quebrá-lo. + +Aqui, `CacheInterface` é uma dependência: um contrato de que o nosso objeto +precisa para funcionar. Em outras palavras, o nosso objeto depende do +contrato. + +O processo de colocar uma instância de um contrato dentro de um objeto +(`CachedWidget`) se chama injeção de dependência. Há várias formas de fazer +isso: + +- Injeção pelo construtor. A melhor para dependências obrigatórias. +- Injeção por método. A melhor para dependências opcionais. +- Injeção por propriedade. É melhor evitar em PHP, exceto talvez em data + transfer objects. + +### Por que usar propriedades privadas + +No exemplo de composição acima, repare que a propriedade `$cache` é +declarada como `private`. + +Essa abordagem favorece a composição ao garantir que os objetos tenham +interfaces bem definidas para interação, em vez de acesso direto às +propriedades, o que deixa o código mais fácil de manter e menos sujeito a +certos tipos de erro. + +Essa escolha de design traz vários benefícios: + +- **Encapsulamento**: propriedades privadas com getters/setters permitem + controlar o acesso e fazer mudanças futuras sem quebrar o código + existente. +- **Integridade dos dados**: setters podem validar, normalizar ou formatar + valores antes de armazená-los, garantindo que as propriedades contenham + dados válidos. +- **Imutabilidade**: propriedades privadas permitem padrões de objetos + imutáveis, em que os métodos `with*()` retornam novas instâncias em vez de + modificar a atual. +- **Flexibilidade**: você pode criar propriedades somente leitura ou somente + escrita, ou acrescentar lógica ao acesso às propriedades mais tarde. + + +## Container de DI + +Injetar dependências básicas é simples. Você escolhe um lugar onde não se +importa com as dependências, que normalmente é um handler de action, que +você nunca vai testar com testes unitários, cria as instâncias das +dependências necessárias e as passa para as classes dependentes. + +Isso funciona bem quando há poucas dependências no total e quando não há +dependências aninhadas. Quando há muitas e cada dependência tem as suas +próprias dependências, instanciar a hierarquia inteira se torna um processo +tedioso, que exige muito código e pode levar a erros difíceis de depurar. + +Além disso, muitas dependências, como certos wrappers de APIs de terceiros, +são as mesmas para qualquer classe que as use. Então faz sentido: + +- Definir como instanciar essas dependências comuns. +- Instanciá-las quando necessário e apenas uma vez por requisição. + +É para isso que servem os containers de dependências. + +Um container de injeção de dependência (DI) é um objeto que sabe como +instanciar e configurar objetos e todos os objetos dos quais eles dependem. + +O Yii fornece o container de DI por meio dos pacotes +[yiisoft/di](https://github.com/yiisoft/di) e +[yiisoft/injector](https://github.com/yiisoft/injector). + +> [!NOTE] +> O container contém apenas instâncias compartilhadas. Se você precisar de uma factory, use o pacote dedicado +> [yiisoft/factory](https://github.com/yiisoft/factory). + +> [!TIP] +> O [artigo de Martin Fowler](https://martinfowler.com/articles/injection.html) explica bem +> por que um container de DI é útil. Aqui vamos explicar principalmente o uso do container de DI fornecido pelo Yii. + +### Configurando o container + +Como para criar um novo objeto você precisa das dependências dele, +registre-as o quanto antes. Você pode fazer isso na configuração da +aplicação, `config/web.php`. Para o seguinte serviço: + +```php +final class MyService implements MyServiceInterface +{ + public function __construct(int $amount) + { + } + + public function setDiscount(int $discount): void + { + + } +} +``` + +a configuração poderia ser: + +```php +return [ + MyServiceInterface::class => [ + 'class' => MyService::class, + '__construct()' => [42], + 'setDiscount()' => [10], + ], +]; +``` + +Isso equivale ao seguinte: + +```php +$myService = new MyService(42); +$myService->setDiscount(10); +``` + +Você também pode passar argumentos com nomes: + +```php +return [ + MyServiceInterface::class => [ + 'class' => MyService::class, + '__construct()' => ['amount' => 42], + 'setDiscount()' => ['discount' => 10], + ], +]; +``` + +Basicamente é isso. Você define um mapa de interfaces para classes e define +como configurá-las. Quando uma interface é solicitada no construtor ou em +outro lugar, o container cria uma instância da classe e a configura conforme +a configuração: + +```php +final class MyAction +{ + public function __construct( + private readonly MyServiceInterface $myService + ) { + } + + public function __invoke() + { + $this->myService->doSomething(); + } +} +``` + +Há outras formas de declarar a configuração de dependências. + +Nos casos mais simples, em que não são necessários valores personalizados e +todas as dependências do construtor podem ser obtidas do container, você +pode usar um nome de classe como valor. + +```php +interface EngineInterface +{ + +} + +final class EngineMarkOne implements EngineInterface +{ + public function __construct(CacheInterface $cache) { + } +} +``` + +No exemplo acima, se já houver um cache definido no container, não é preciso +nada além do nome da classe: + +```php +return [ + // declara uma classe para uma interface, resolvendo as dependências automaticamente + EngineInterface::class => EngineMarkOne::class, +]; +``` + +Se você tiver uma dependência com propriedades públicas, também pode +configurá-la. + + +```php +final class NameProvider +{ + public string $name; +} +``` + +Veja como fazer isso no exemplo acima: + +```php +NameProvider::class => [ + 'class' => NameProvider::class, + '$name' => 'Alex', +], +``` + +Neste exemplo, você pode notar que `NameProvider` aparece duas vezes. A +chave é o que você pode solicitar como dependência, e o valor é como +criá-la. + +Se a configuração for complicada e exigir alguma lógica, você pode usar uma +closure: + +```php +MyServiceInterface::class => static function(ContainerInterface $container) { + return new MyService($container->get('db')); +}, +``` + +Além do `ContainerInterface`, você pode solicitar qualquer serviço +registrado diretamente como parâmetro da closure. O injector vai +resolvê-los e injetá-los automaticamente: + +```php +MyServiceInterface::class => static function(ConnectionInterface $db) { + return new MyService($db); +}, +``` + +É possível usar a chamada de um método estático: + +```php +MyServiceInterface::class => [MyFactory::class, 'create'], +``` + +Ou uma instância de um objeto: + +```php +MyServiceInterface::class => new MyService(), +``` + +### Injetando dependências corretamente + +Referenciar o container diretamente em uma classe é uma má ideia, porque o +código deixa de ser genérico, fica acoplado à interface do container e, pior +ainda, as dependências ficam escondidas. Por isso, o Yii inverte o +controle, injetando automaticamente objetos do container em alguns +construtores e métodos com base nos tipos dos argumentos. + +Isso é feito principalmente no construtor e no método de tratamento dos +handlers de action: + +```php +use \Yiisoft\Cache\CacheInterface; + +final readonly class MyController +{ + public function __construct( + private CacheInterface $cache + ) + { + $this->cache = $cache; + } + + public function actionDashboard(RevenueReport $report) + { + $reportData = $this->cache->getOrSet('revenue_report', function() use ($report) { + return $report->getData(); + }); + + return $this->render('dashboard', [ + 'reportData' => $reportData, + ]); + } +} +``` + +Como é o [yiisoft/injector](https://github.com/yiisoft/injector) que +instancia e chama o handler de action, ele verifica os tipos dos argumentos +do construtor e do método, obtém do container as dependências desses tipos e +as passa como argumentos. Isso normalmente se chama autowiring. Acontece +também com as subdependências: se você não fornecer uma dependência +explicitamente, o container vai verificar primeiro se tem essa dependência. +Basta declarar a dependência de que você precisa, e ela será obtida do +container automaticamente. + + +## Referências + +- [Inversion of Control Containers and the Dependency Injection pattern, de + Martin Fowler](https://martinfowler.com/articles/injection.html) diff --git a/src/pt-BR/guide/concept/events.md b/src/pt-BR/guide/concept/events.md new file mode 100644 index 00000000..5337ff4f --- /dev/null +++ b/src/pt-BR/guide/concept/events.md @@ -0,0 +1,201 @@ +# Eventos + +Eventos permitem executar código personalizado em determinados pontos da +execução, sem alterar o código que emite o evento. Você associa a um evento +um código personalizado chamado listener. Quando o evento é disparado, o +listener é executado. + +Por exemplo, quando um usuário se cadastra, você precisa enviar um e-mail de +boas-vindas. Dá para fazer isso no `SignupService`. Mais tarde, quando você +também precisar redimensionar a imagem de avatar do usuário, o serviço vai +ter que saber disso também. + +Um fluxo mais limpo é disparar um evento `UserSignedUp` a partir do +`SignupService`. O remetente do e-mail de boas-vindas e o processador de +avatar escutam esse evento. Trabalho adicional relacionado ao cadastro pode +ser incluído registrando outro listener. + +O Yii usa o [yiisoft/yii-event](https://github.com/yiisoft/yii-event) para a +configuração de eventos da aplicação. Ele é construído sobre o pacote +[yiisoft/event-dispatcher](https://github.com/yiisoft/event-dispatcher), que +fornece um event dispatcher compatível com +[PSR-14](https://www.php-fig.org/psr/psr-14/). + +## Classes de evento + +Um evento é um objeto. Normalmente ele contém os dados de que os listeners +precisam: + +```php +final readonly class UserSignedUp +{ + public function __construct( + public SignupForm $form, + ) {} +} +``` + +## Listeners de eventos + +Um listener de evento é um [callable do +PHP](https://www.php.net/manual/en/language.types.callable.php) que recebe +um evento: + +```php +static function (UserSignedUp $event): void { + // Envia um e-mail de boas-vindas. +} +``` + +Você também pode usar uma classe invocável: + +```php +final readonly class WelcomeEmailSender +{ + public function __invoke(UserSignedUp $event): void + { + // Envia um e-mail de boas-vindas. + } +} +``` + +## Configurando listeners de eventos + +Em uma aplicação, configure os listeners em: + +- `config/events.php` para todos os tipos de aplicação. +- `config/events-web.php` para eventos da aplicação web. +- `config/events-console.php` para eventos da aplicação de console. + +A configuração é um array em que as chaves são os nomes das classes de +evento e os valores são listas de listeners: + +```php + [ + WelcomeEmailSender::class, + static fn (UserSignedUp $event, AvatarProcessor $avatarProcessor) => $avatarProcessor->resize($event->form), + ], +]; +``` + +O listener pode ser uma closure, um array callable, um objeto invocável, o +nome de uma classe invocável ou um alias de DI. Para listeners do tipo +closure e array callable, os parâmetros depois do primeiro (o evento) são +resolvidos pelo container de DI. Nomes de classes invocáveis são +instanciados pelo container. + +As dependências são resolvidas quando o evento é disparado. + +## Disparando eventos + +Para disparar um evento, use `Psr\EventDispatcher\EventDispatcherInterface`: + +```php +use Psr\EventDispatcher\EventDispatcherInterface; + +final readonly class SignupService +{ + public function __construct( + private EventDispatcherInterface $eventDispatcher, + ) {} + + public function signup(SignupForm $form): void + { + // Cadastra o usuário. + + $this->eventDispatcher->dispatch(new UserSignedUp($form)); + } +} +``` + +O dispatcher pede a um listener provider os listeners que correspondem ao +evento e os chama um por um. + +## Ordem dos listeners + +Quando vários listeners são configurados para o mesmo evento, eles são +chamados na ordem em que aparecem na configuração. Se um evento implementa +`Psr\EventDispatcher\StoppableEventInterface`, o dispatcher verifica +`isPropagationStopped()` antes de chamar o próximo listener. Quando ele +retorna `true`, o dispatcher para de processar o evento. + +Mantenha os listeners independentes sempre que possível. A ordem é útil para +necessidades técnicas, mas a lógica de negócio costuma ser mais fácil de +manter quando cada listener consegue rodar sozinho. + +## Hierarquia de eventos + +Eventos não têm nomes nem correspondência por curinga. Nomes de classes de +evento, interfaces e herança podem ser usados quando um listener precisa +tratar vários eventos relacionados: + +```php +interface DocumentEvent +{ +} + +final readonly class BeforeDocumentProcessed implements DocumentEvent +{ +} + +final readonly class AfterDocumentProcessed implements DocumentEvent +{ +} +``` + +Com a interface, você pode escutar todos os eventos relacionados a +documentos: + +```php +use Yiisoft\EventDispatcher\Provider\ListenerCollection; +use Yiisoft\EventDispatcher\Provider\Provider; + +$listeners = (new ListenerCollection()) + ->add(static function (DocumentEvent $event): void { + // Registra em log os eventos de documentos. + }); + +$provider = new Provider($listeners); +``` + +## Configuração manual do listener provider + +Em uma aplicação, use a configuração de eventos. Para código de pacotes ou +testes, você pode criar um listener provider manualmente: + +```php +use Yiisoft\EventDispatcher\Dispatcher\Dispatcher; +use Yiisoft\EventDispatcher\Provider\ListenerCollection; +use Yiisoft\EventDispatcher\Provider\Provider; + +$listeners = (new ListenerCollection()) + ->add(static function (UserSignedUp $event): void { + // Envia um e-mail de boas-vindas. + }); + +$provider = new Provider($listeners); +$dispatcher = new Dispatcher($provider); + +$dispatcher->dispatch(new UserSignedUp($form)); +``` + +`ListenerCollection::add()` retorna uma nova instância da coleção. Atribua o resultado ao montar uma coleção passo a passo: + +```php +$listeners = new ListenerCollection(); +$listeners = $listeners->add( + static function (UserSignedUp $event): void { + // Envia um e-mail de boas-vindas. + }, + UserSignedUp::class, +); +``` diff --git a/src/pt-BR/guide/concept/immutability.md b/src/pt-BR/guide/concept/immutability.md new file mode 100644 index 00000000..0094f2c3 --- /dev/null +++ b/src/pt-BR/guide/concept/immutability.md @@ -0,0 +1,161 @@ +# Imutabilidade + +Imutabilidade significa que o estado de um objeto não pode mudar depois que +ele é criado. Em vez de modificar uma instância, você cria uma nova +instância com as mudanças desejadas. Essa abordagem é comum em value +objects como Money, IDs e DTOs. Ela ajuda a evitar efeitos colaterais +acidentais: os métodos não conseguem alterar silenciosamente um estado +compartilhado, o que torna o código mais fácil de entender. + +## Armadilhas da mutabilidade (o que evitamos) + +```php +// Uma query base compartilhada, montada uma vez e reutilizada: +$base = Post::find()->where(['status' => Post::STATUS_PUBLISHED]); + +// Em algum lugar profundo do código, precisamos de um só post: +$one = $base->limit(1)->one(); // altera o builder subjacente (o limit fica grudado!) + +// Depois reutilizamos o mesmo $base esperando a lista completa: +$list = $base->orderBy(['created_at' => SORT_DESC])->all(); +// Ops: continua limitado a 1, porque o limit(1) anterior modificou $base. +``` + +## Criando um objeto imutável em PHP + +Não há como modificar uma instância diretamente, mas você pode usar clone +para criar uma nova instância com as mudanças desejadas. É isso que os +métodos `with*` fazem. + +```php +final class Money +{ + public function __construct( + private int $amount, + private string $currency, + ) { + $this->validateAmount($amount); + $this->validateCurrency($currency); + } + + private function validateAmount(string $amount) + { + if ($amount < 0) { + throw new InvalidArgumentException('Amount must be positive.'); + } + } + + private function validateCurrency(string $currency) + { + if (!in_array($currency, ['USD', 'EUR'])) { + throw new InvalidArgumentException('Invalid currency. Only USD and EUR are supported.'); + } + } + + public function withAmount(int $amount): self + { + $this->validateAmount($amount); + + if ($amount === $this->amount) { + return $this; + } + + $clone = clone $this; + $clone->amount = $amount; + return $clone; + } + + public function withCurrency(string $currency): self + { + $this->validateCurrency($currency); + + if ($currency === $this->currency) { + return $this; + } + + $clone = clone $this; + $clone->currency = $currency; + return $clone; + } + + public function amount(): int + { + return $this->amount; + } + + public function currency(): string + { + return $this->currency; + } + + public function add(self $money): self + { + if ($money->currency !== $this->currency) { + throw new InvalidArgumentException('Currency mismatch. Cannot add money of different currency.'); + } + return $this->withAmount($this->amount + $money->amount); + } +} + +$price = new Money(1000, 'USD'); +$discounted = $price->withAmount(800); +// $price continua 1000 USD, $discounted é 800 USD +``` + +- Marcamos a classe como `final` para impedir mutações por subclasses; como + alternativa, projete a extensão com cuidado. +- Valide no construtor e nos métodos `with*`, para que toda instância seja + sempre válida. + +> [!TIP] +> Se você define um DTO simples, pode usar o `readonly` do PHP moderno e deixar as propriedades `public`. A palavra-chave `readonly` +> garante que as propriedades não possam ser modificadas depois que o objeto é criado. + +## Usando clone (e por que é barato) + +O clone do PHP faz uma cópia rasa do objeto. Para value objects imutáveis +que contêm apenas escalares ou outros objetos imutáveis, a clonagem rasa é +suficiente e rápida. No PHP moderno, clonar value objects pequenos é barato +em tempo e em memória. + +Se o seu objeto guarda subobjetos mutáveis que também precisam ser copiados, +implemente `__clone` para fazer a clonagem profunda deles: + +```php +final class Order +{ + public function __construct( + private Money $total + ) {} + + public function total(): Money + { + return $this->total; + } + + public function __clone(): void + { + // Money é imutável no nosso exemplo, então a clonagem profunda não é necessária. + // Se fosse mutável, você poderia fazer: $this->total = clone $this->total; + } + + public function withTotal(Money $total): self + { + $clone = clone $this; + $clone->total = $total; + return $clone; + } +} +``` + +## Estilo de uso + +- Crie um value object uma vez e passe-o adiante. Se precisar de uma + mudança, use um método `with*` que retorna uma nova instância. +- Prefira campos escalares/imutáveis dentro de objetos imutáveis; se um + campo puder mudar, isole-o e faça a clonagem profunda em `__clone` quando + necessário. + +A imutabilidade combina bem com a preferência do Yii por código previsível e +sem efeitos colaterais, e torna serviços, cache e configuração mais +robustos. diff --git a/src/pt-BR/guide/databases/db-migrations.md b/src/pt-BR/guide/databases/db-migrations.md new file mode 100644 index 00000000..f19015fe --- /dev/null +++ b/src/pt-BR/guide/databases/db-migrations.md @@ -0,0 +1,448 @@ +# Migrations + +Ao longo do desenvolvimento e da manutenção de uma aplicação que usa banco +de dados, a estrutura do banco evolui assim como o código-fonte. Por +exemplo, durante o desenvolvimento de uma aplicação, pode surgir a +necessidade de uma nova tabela; depois que a aplicação vai para produção, +pode-se descobrir que é preciso criar um índice para melhorar o desempenho +de uma consulta; e assim por diante. Como uma mudança na estrutura do banco +de dados muitas vezes exige mudanças no código-fonte, o Yii oferece o +recurso chamado *migration de banco de dados*, que permite acompanhar as +mudanças no banco em forma de *migrations*, versionadas junto com o +código-fonte. + +Os passos a seguir mostram como uma equipe pode usar migrations durante o +desenvolvimento: + +1. Tim cria uma nova migration (por exemplo, cria uma nova tabela, altera a + definição de uma coluna etc.). +2. Tim faz o commit da nova migration no sistema de controle de versão (por + exemplo, Git, Mercurial). +3. Doug atualiza o repositório dele a partir do sistema de controle de + versão e recebe a nova migration. +4. Doug aplica a migration ao banco de dados local de desenvolvimento, + sincronizando o banco dele com as mudanças que Tim fez. + +E os passos a seguir mostram como fazer o deploy de uma nova release com +migrations para produção: + +1. Scott cria uma tag de release no repositório do projeto que contém + algumas migrations novas. +2. Scott atualiza o código-fonte no servidor de produção para a tag da + release. +3. Scott aplica todas as migrations acumuladas ao banco de dados de + produção. + +```mermaid +sequenceDiagram + participant Tim + participant VCS as Controle de versão + participant Doug + participant LocalDB as Banco de dados local de desenvolvimento + participant Scott + participant ProdServer as Servidor de produção + participant ProdDB as Banco de dados de produção + + Tim->>Tim: Cria uma nova migration + Tim->>VCS: Faz o commit da nova migration + Doug->>VCS: Atualiza o repositório e recebe a nova migration + Doug->>LocalDB: Aplica a migration localmente + + Scott->>VCS: Cria uma tag de release com as novas migrations + Scott->>ProdServer: Atualiza o código-fonte para a tag da release + Scott->>ProdDB: Aplica as migrations acumuladas +``` + +O Yii fornece um conjunto de ferramentas de linha de comando para migrations +que permitem: + +* criar novas migrations; +* aplicar migrations; +* reverter migrations; +* reaplicar migrations; +* mostrar o histórico e o status das migrations. + +Todas essas ferramentas são acessíveis pelo comando `yii migrate`. Nesta +seção, vamos descrever em detalhes como realizar várias tarefas usando essas +ferramentas. + +> [!TIP] +> Migrations podem afetar não só o schema do banco de dados, mas também ajustar dados existentes ao novo schema, criar a hierarquia +de RBAC ou limpar o cache. + +> [!NOTE] +> Ao manipular dados em uma migration, pode parecer útil usar suas classes Active Record ou de entidade, +> já que parte da lógica já está implementada nelas. Lembre-se, porém, de que, ao contrário +> do código escrito nas migrations, que por natureza deve permanecer constante para sempre, a lógica da aplicação está sujeita a mudanças. +> Então, ao usar classes Active Record ou de entidade no código de migrations, mudanças na lógica do código-fonte +> podem quebrar acidentalmente as migrations existentes. Por isso, o código das migrations deve ser mantido independente do restante +> da lógica da aplicação. + +## Configuração inicial + +Para usar migrations, instale o pacote +[yiisoft/db-migration](https://github.com/yiisoft/db-migration/): + +```shell +make composer require yiisoft/db-migration +``` + +Crie um diretório `src/Migration` para armazenar as migrations, diretamente +na raiz do projeto. + +Adicione a seguinte configuração em `config/common/params.php`: + +```php +'yiisoft/db-migration' => [ + 'newMigrationNamespace' => 'App\\Migration', + 'sourceNamespaces' => ['App\\Migration'], +], +``` + +Se você quiser colocar as migrations em outro lugar, pode definir o caminho +em `newMigrationPath`. Se as migrations a aplicar vêm de várias fontes, como +módulos externos, você pode usar `sourcePaths` para defini-las. + +Você também precisa de uma conexão com o banco de dados configurada. Veja +[Trabalhando com banco de dados](../start/databases.md) para um exemplo de +configuração com PostgreSQL. + +## Criando uma migration + +Para criar uma nova migration vazia, execute o seguinte comando: + +```sh +make shell +./yii migrate:create +``` + +O argumento obrigatório `name` dá uma breve descrição da nova migration. Por +exemplo, se a migration cria uma nova tabela chamada *news*, você pode usar +o nome `create_news_table` e executar o seguinte comando: + +``` +make shell +./yii migrate:create create_news_table +``` + + +> [!NOTE] +> Como o argumento `name` é usado como parte do nome da classe de migration gerada, +> ele deve conter apenas letras, dígitos e/ou underscores. + +O comando acima cria um novo arquivo de classe PHP chamado +`src/Migration/M251225221906CreateNewsTable.php`. O arquivo contém o código +a seguir, que basicamente declara uma classe de migration com o esqueleto do +código: + +```php +columnBuilder(); + + $b->createTable('news', [ + 'id' => $cb::uuidPrimaryKey(), + 'title' => $cb::string()->notNull(), + 'content' => $cb::text(), + ]); + } + + public function down(MigrationBuilder $b): void + { + $b->dropTable('news'); + } +} +``` + +No exemplo acima, o migration builder `$b` gerencia o schema do banco de +dados, enquanto o column builder `$cb` gerencia os tipos de coluna. Ambos +permitem usar *tipos abstratos*. Quando uma migration é aplicada a um banco +de dados específico, os tipos abstratos são traduzidos para os tipos físicos +correspondentes do banco e para o SQL correspondente que os define. + +Os métodos disponíveis no migration builder se dividem nos seguintes tipos: + +- Consultas SQL puras + - getDb — para obter a instância da conexão com o banco de dados. + - execute — para executar uma consulta SQL pura. +- Dados + - insert / update / delete + - batchInsert + - upsert +- Tabelas e views + - createTable / renameTable / dropTable + - truncateTable + - addCommentOnTable / dropCommentFromTable + - createView / dropView +- Colunas + - addColumn / renameColumn / alterColumn / dropColumn + - addCommentOnColumn / dropCommentFromColumn +- Chaves e índices + - addPrimaryKey / dropPrimaryKey + - addForeignKey / dropForeignKey + - createIndex / dropIndex + +Além disso, há um `columnBuilder()`, usado para obter um column builder como +no exemplo acima. O builder tem métodos estáticos que definem vários tipos +de coluna: + +- Chaves + - primaryKey + - smallPrimaryKey + - bigPrimaryKey + - uuidPrimaryKey +- Booleano + - boolean +- Números + - bit + - tinyint + - smallint + - integer + - bigint + - flat + - double + - decimal +- Strings + - char + - string + - text +- Data e hora + - timestamp + - datetime + - datetimeWithTimezone + - time + - timeWithTimezone + - date +- Tipos especiais + - money + - binary + - uuid + - array + - structured + - json +- enum + +Todos os métodos acima criam um tipo base que pode ser ajustado com métodos +adicionais: + +- null / notNull +- defaultValue +- unique +- scale / size / unsigned +- primaryKey / autoIncrement +- check +- comment +- computed +- extra +- reference + +### Migrations irreversíveis + +Nem todas as migrations são reversíveis. Por exemplo, se o método `up()` +apaga uma linha de uma tabela, talvez você não consiga recuperar essa linha +no método `down()`. Às vezes, você pode simplesmente não querer implementar +o `down()`, porque não é muito comum reverter migrations. Nesse caso, +implemente `Yiisoft\Db\Migration\MigrationInterface`, que tem apenas `up()`. + + +### Migrations transacionais + +Ao executar migrations complexas, é importante garantir que cada migration +tenha sucesso ou falhe por completo, para que o banco de dados mantenha a +integridade e a consistência. Para isso, é recomendado envolver +automaticamente as operações de banco de cada migration em uma transação, +adicionando `TransactionalMigrationInterface` ao `implements` da sua +migration. + +Assim, se qualquer operação no método `up()` ou `down()` falhar, todas as +operações anteriores serão desfeitas (rollback) automaticamente. + +> Nota: nem todo SGBD dá suporte a transações. E algumas consultas não podem ser colocadas em uma transação. Para alguns exemplos, +consulte [implicit commit](https://dev.mysql.com/doc/refman/5.7/en/implicit-commit.html). + +## Gerando uma migration + +Em vez de escrever migrations à mão, o comando oferece uma forma prática de +gerar parte do código. + +```shell +make shell +./yii migrate:create -- my_first_table --command=table --fields=name,example --table-comment=my_first_table +``` + +Isso geraria o seguinte: + +```php +columnBuilder(); + + $b->createTable('my_first_table', [ + 'id' => $columnBuilder::primaryKey(), + 'name', + 'example', + ]); + + $b->addCommentOnTable('my_first_table', 'my_first_table'); + } + + public function down(MigrationBuilder $b): void + { + $b->dropTable('my_first_table'); + } +} +``` + +Os comandos disponíveis são: + +- create - migration vazia. +- table - cria uma tabela. Use `--fields` para especificar a lista de + campos. Também é possível especificar os tipos, como em + `id:primaryKey,name:string:defaultValue("Alex"),user_id:integer:foreignKey,category_id2:integer:foreignKey(category + id2)`. +- dropTable - remove uma tabela. +- addColumn - adiciona uma coluna. +- dropColumn - remove uma coluna. +- junction - cria uma tabela de junção. Use `--and` para especificar a + segunda tabela. + +## Aplicando migrations + +Para atualizar um banco de dados para a estrutura mais recente, aplique +todas as migrations novas disponíveis com o seguinte comando: + +``` +./yii migrate:up +``` + +Esse comando lista todas as migrations que ainda não foram aplicadas. Se +você confirmar que quer aplicá-las, ele executa o método `up()` de cada nova +classe de migration, uma após a outra, na ordem de seus timestamps. Se +alguma das migrations falhar, o comando é encerrado sem aplicar as demais. + +Para cada migration aplicada com sucesso, o comando insere uma linha em uma +tabela do banco chamada `migration` para registrar a aplicação +bem-sucedida. Isso permite que a ferramenta de migrations identifique quais +migrations foram aplicadas e quais não foram. + +Às vezes, você pode querer aplicar apenas uma ou algumas migrations novas, +em vez de todas as disponíveis. Você pode fazer isso especificando o número +de migrations que quer aplicar ao executar o comando. Por exemplo, o +comando a seguir tenta aplicar as próximas três migrations disponíveis: + +``` +./yii migrate:up --limit=3 +``` + +## Revertendo migrations + +Para reverter (desfazer) uma ou várias migrations aplicadas anteriormente, +execute o seguinte comando: + +``` +./yii migrate:down # reverte a migration aplicada mais recentemente +./yii migrate:down --limit=3 # reverte as 3 migrations aplicadas mais recentemente +./yii migrate:down --all # reverte todas as migrations +``` + +> Nota: nem todas as migrations são reversíveis. Tentar reverter uma migration assim causa um erro e interrompe +todo o processo de reversão. + + +## Refazendo migrations + +Refazer migrations significa primeiro reverter as migrations especificadas e +depois aplicá-las novamente. Isso pode ser feito assim: + +``` +./yii migrate:redo # refaz a última migration aplicada +./yii migrate:redo --limit=3 # refaz as 3 últimas migrations aplicadas +./yii migrate:redo --all # refaz todas as migrations +``` + +> Nota: se uma migration não for reversível, você não conseguirá refazê-la. + +## Listando migrations + +Para listar quais migrations foram aplicadas e quais não foram, use os +seguintes comandos: + +``` +./yii migrate/history # mostra as 10 últimas migrations aplicadas +./yii migrate:history --limit=5 # mostra as 5 últimas migrations aplicadas +./yii migrate:history --all # mostra todas as migrations aplicadas + +./yii migrate:new # mostra as 10 primeiras migrations novas +./yii migrate:new --limit=5 # mostra as 5 primeiras migrations novas +./yii migrate:new --all # mostra todas as migrations novas +``` + +### Migrando do Yii 2.0 + +As migrations do Yii 2.0 e o pacote +[yiisoft/db-migration](https://github.com/yiisoft/db-migration/) não são +compatíveis, e a tabela `migration` também não é compatível. + +Uma solução possível é usar dumps da estrutura e renomear a tabela +`migration` antiga. Na primeira execução das migrations, uma nova tabela +`migration` com os novos campos será criada. Todas as mudanças seguintes no +schema do banco de dados são aplicadas usando o novo componente `migration` +e registradas na nova tabela de migrations. diff --git a/src/pt-BR/guide/glossary.md b/src/pt-BR/guide/glossary.md new file mode 100644 index 00000000..d726d331 --- /dev/null +++ b/src/pt-BR/guide/glossary.md @@ -0,0 +1,270 @@ +# A + +## action + +Action é um callable, uma classe ou um método de classe que trata uma rota +correspondida e retorna uma resposta. Leia mais em +["Actions"](structure/action.md). + +## alias + +Alias é uma string usada pelo Yii para se referir a uma classe ou a um +diretório, como `@app/vendor`. Leia mais em +["Aliases"](concept/aliases.md). + +## aplicação + +A aplicação é um objeto que inicializa, trata uma requisição passando pelos +middlewares configurados e encerra. Leia mais em +["Aplicação"](structure/application.md). + +## asset + +Asset é um arquivo de recurso. Normalmente contém código JavaScript ou CSS, +mas pode ser qualquer conteúdo estático acessado via HTTP. Leia mais em +["Assets"](views/asset.md). + +## asset bundle + +Asset bundle é uma classe PHP que declara um grupo de arquivos CSS, +JavaScript, imagens ou fontes que devem ser publicados e registrados +juntos. Leia mais em ["Asset bundles"](views/asset.md#asset-bundles). + +## autenticação + +Autenticação é o processo de determinar a identidade do usuário atual. Leia +mais em ["Autenticação"](security/authentication.md). + +## autorização + +Autorização é o processo de verificar se um usuário autenticado ou anônimo +tem permissão para realizar uma ação. Leia mais em +["Autorização"](security/authorization.md). + +## autoloading + +Autoloading é o processo de carregar classes PHP automaticamente quando elas +são usadas pela primeira vez. Leia mais em ["Autoloading de +classes"](concept/autoloading.md). + +# B + +## bootstrap + +Bootstrap é o código de inicialização da aplicação que prepara serviços, +configuração e estado de execução antes do tratamento da requisição. Leia +mais em ["Configuração"](concept/configuration.md). + +# C + +## configuração + +Configuração pode se referir tanto ao processo de definir propriedades de um +objeto quanto a um arquivo de configuração que guarda definições para um +objeto ou uma classe de objetos. Leia mais em +["Configuração"](concept/configuration.md). + +## container + +Container é um objeto que cria serviços, resolve suas dependências e retorna +instâncias configuradas. Leia mais em ["Container de +DI"](concept/di-container.md#container-de-di). + +## controller + +Controller é uma classe que agrupa métodos de action de rotas relacionadas. +Leia mais em ["Actions"](structure/action.md). + +## cookie + +Cookie é um pequeno pedaço de dados guardado pelo navegador e enviado nas +requisições seguintes ao mesmo site. Leia mais em +["Cookies"](runtime/cookies.md). + +## CSRF + +CSRF significa cross-site request forgery (falsificação de requisição entre +sites), um ataque em que outro site tenta fazer o navegador de um usuário +enviar uma requisição indesejada para sua aplicação. Leia mais em +["Evitando CSRF"](security/best-practices.md#evitando-csrf). + +# D + +## DI + +Injeção de dependência é uma técnica de programação em que um objeto recebe +suas dependências de fora. Leia mais em ["Injeção de dependência e +container"](concept/di-container.md). + +# E + +## entry script (script de entrada) + +O script de entrada é o primeiro script PHP executado em uma aplicação web +ou de console. Leia mais em ["Scripts de +entrada"](structure/entry-script.md). + +## evento + +Evento é um objeto que representa algo que aconteceu e que pode ser passado +para listeners. Leia mais em ["Eventos"](concept/events.md). + +# H + +## handler + +Handler é o código callable escolhido pelo roteamento ou por um middleware +para processar uma requisição e produzir uma resposta. Leia mais em +["Roteamento e geração de URLs"](runtime/routing.md). + +# I + +## instalação + +Instalação é o processo de preparar algo para funcionar, seja seguindo um +arquivo readme, seja executando um script preparado especialmente para +isso. No caso do Yii, é definir permissões e atender aos requisitos de +software. + +# L + +## layout + +Layout é um template de view que envolve o conteúdo específico de uma página +com a estrutura compartilhada da página. Leia mais em ["Trabalhando com +layouts"](views/view.md#trabalhando-com-layouts). + +# M + +## migration + +Migration é uma classe PHP versionada que aplica ou reverte uma mudança no +schema ou nos dados do banco de dados. Leia mais em +["Migrations"](databases/db-migrations.md). + +## middleware + +Middleware é um processador na pilha de processamento da requisição. Dada +uma requisição, ele pode produzir uma resposta ou fazer alguma ação e passar +o processamento para o próximo middleware. Leia mais em +["Middleware"](structure/middleware.md). + +## model + +Model é um objeto que representa dados da aplicação e normalmente contém +regras de validação ou de negócio para esses dados. Leia mais em +["Trabalhando com formulários"](start/forms.md). + +## módulo + +O módulo é um namespace que agrupa código com base em um caso de +uso. Normalmente é usado dentro da aplicação principal e pode conter +qualquer código-fonte, definir handlers de URL adicionais ou comandos de +console. + +# N + +## namespace + +Namespace é um [recurso da linguagem +PHP](https://www.php.net/manual/en/language.namespaces.php) para agrupar +várias classes sob um determinado nome. + +# P + +## pacote + +Um pacote normalmente é um [pacote do +Composer](https://getcomposer.org/doc/). É código pronto para reutilização e +redistribuição, que pode ser instalado automaticamente por um gerenciador de +pacotes. + +## parâmetro + +Parâmetro é um valor de configuração que pode ser usado pelos arquivos de +configuração da aplicação ou de pacotes. Leia mais em +["Parâmetros"](concept/configuration.md#parametros). + +# Q + +## queue (fila) + +Uma fila é uma estrutura de dados que processa itens na ordem em que +chegaram (primeiro a entrar, primeiro a sair). O Yii tem o pacote +[yiisoft/queue](https://github.com/yiisoft/queue). + +# R + +## requisição + +Requisição é um objeto PSR-7 que representa uma mensagem HTTP recebida, +incluindo método, URI, headers, corpo, arquivos enviados e atributos. Leia +mais em ["Requisição"](runtime/request.md). + +## resposta + +Resposta é um objeto PSR-7 que representa uma mensagem HTTP enviada, +incluindo código de status, headers e corpo. Leia mais em +["Resposta"](runtime/response.md). + +## rota + +A rota descreve qual método de requisição e qual padrão de URL devem ser +tratados por qual action ou middleware. Leia mais em ["Roteamento e geração +de URLs"](runtime/routing.md). + +## regra + +A regra normalmente se refere a uma regra de validação do pacote +[yiisoft/validator](https://github.com/yiisoft/validator). Ela guarda um +conjunto de parâmetros para verificar se um conjunto de dados é válido. O +"rule handler" faz o processamento de fato. + +# S + +## serviço + +Serviço é um objeto focado que realiza trabalho da aplicação ou fornece +comportamento de infraestrutura e normalmente fica registrado no container +de DI. Leia mais em ["Componentes de +serviço"](../cookbook/organizing-code/service.md). + +## service provider (provedor de serviços) + +Service provider é uma classe que registra definições de serviços +relacionados para o container de DI. Leia mais em ["Service +providers"](concept/configuration.md#service-providers). + +## sessão + +Sessão é um armazenamento no servidor associado a um navegador ao longo de +várias requisições. Leia mais em ["Sessões"](runtime/sessions.md). + +# T + +## template + +Template é um arquivo usado por uma view ou por um template engine para +produzir a saída de apresentação, como HTML. Leia mais em +["Views"](views/view.md). + +# V + +## vendor + +Vendor é uma organização ou um desenvolvedor individual que fornece código +na forma de pacotes. Também pode se referir ao [diretório `vendor` do +Composer](https://getcomposer.org/doc/). + +## view + +A view é responsável por apresentar dados aos usuários finais, normalmente +executando um template com os dados fornecidos. Leia mais em +["Views"](views/view.md). + +# W + +## widget + +Widget é um componente de view reutilizável que renderiza uma parte da +interface do usuário. Leia mais em ["Widgets"](views/widget.md). diff --git a/src/pt-BR/guide/index.md b/src/pt-BR/guide/index.md new file mode 100644 index 00000000..1466c52f --- /dev/null +++ b/src/pt-BR/guide/index.md @@ -0,0 +1,162 @@ +# O guia definitivo do Yii3 + +Este guia é publicado sob os [Termos da documentação do +Yii](https://www.yiiframework.com/license#docs). + +## Introdução + +- [Sobre o Yii](intro/what-is-yii.md) +- [Migrando da versão 1.1](intro/upgrade-from-v1.md) +- [Migrando da versão 2.0](intro/upgrade-from-v2.md) + +## Primeiros passos + +- [O que você precisa saber?](start/prerequisites.md) +- [Criando um projeto](start/creating-project.md) +- [Fluxo da aplicação](start/workflow.md) +- [Dizendo olá](start/hello.md) +- [Trabalhando com formulários](start/forms.md) +- [Trabalhando com bancos de dados](start/databases.md) +- [Gerando código com o Gii](start/gii.md) TODO +- [Seguindo em frente](start/looking-ahead.md) +- [Aplicações de demonstração](start/demo-apps.md) + +## Conceitos principais + +- [Aliases](concept/aliases.md) +- [Autoload](concept/autoloading.md) +- [Configuração](concept/configuration.md) +- [Container de injeção de dependência](concept/di-container.md) +- [Eventos](concept/events.md) +- [Imutabilidade](concept/immutability.md) + +## Estrutura da aplicação + +- [Visão geral da estrutura da aplicação](structure/overview.md) +- [Scripts de entrada](structure/entry-script.md) +- [Aplicação](structure/application.md) +- [Módulos](structure/module.md) +- [Actions](structure/action.md) +- [Middleware](structure/middleware.md) + +## Pacotes + +- [Usando pacotes](structure/package.md) +- [Projetando pacotes](structure/designing-packages.md) + +## Tratando requisições + +- [Roteamento e geração de URLs](runtime/routing.md) +- [Requisição](runtime/request.md) +- [Resposta](runtime/response.md) +- [Sessões](runtime/sessions.md) +- [Cookies](runtime/cookies.md) +- [Tratamento de erros](runtime/handling-errors.md) +- [Logs](runtime/logging.md) + +## Segurança + +- [Visão geral de segurança](security/overview.md) +- [Autenticação](security/authentication.md) +- [Autorização](security/authorization.md) TODO: verify and complete! +- [Trabalhando com senhas](security/passwords.md) +- [Criptografia](security/cryptography.md) +- [Requisição confiável](security/trusted-request.md) +- [Boas práticas](security/best-practices.md) + +## Cache + +- [Visão geral do cache](caching/overview.md) +- [Cache de dados](caching/data.md) +- Cache de fragmentos TODO +- Cache de páginas TODO +- Cache HTTP TODO + +## Trabalhando com bancos de dados + +- [Yii + DB](https://github.com/yiisoft/db/blob/master/docs/guide/en/README.md) +- [Active + Record](https://github.com/yiisoft/active-record/blob/master/README.md) +- [Migrations](databases/db-migrations.md) TODO: verify/update! + +## Views + +- [View](views/view.md) +- [Assets](views/asset.md) TODO: verify! +- [Scripts, estilos e meta tags](views/script-style-meta.md) TODO: verify! +- [Template engines](views/template-engines.md) TODO: verify! +- [Injeções de view](views/view-injections.md) +- [Widgets](views/widget.md) TODO: verify! + +## Recebendo dados dos usuários + +- Criando formulários TODO +- [Validando + entradas](https://github.com/yiisoft/validator/blob/master/docs/guide/en/README.md) +- Upload de arquivos TODO +- Coletando dados tabulares TODO + +## Exibindo dados + +- Formatação de dados TODO +- Paginação TODO +- Ordenação TODO +- Data providers TODO +- Widgets de dados TODO + +## APIs REST + +- [Início rápido](rest/quick-start.md) +- Recursos TODO +- Controllers TODO +- Roteamento TODO +- Autenticação TODO +- Limitação de requisições TODO +- Versionamento TODO +- Tratamento de erros TODO + +## Ferramentas de desenvolvimento + +- Barra e painel de debug +- Gerando código com o Gii +- Gerando documentação da API + + +## Testes + +- [Visão geral de testes](testing/overview.md) +- [Configurando o ambiente de testes](testing/environment-setup.md) +- [Testes unitários](testing/unit.md) +- [Testes funcionais](testing/functional.md) +- [Testes end-to-end](testing/end-to-end.md) +- [Análise estática e testes de mutação](testing/quality-tools.md) + + +## Tópicos especiais + +- [Aplicações de console](tutorial/console-applications.md) +- [Envio de e-mails](tutorial/mailing.md) +- [Ajuste de desempenho](tutorial/performance-tuning.md) +- [Usando o Yii com event loop](tutorial/using-with-event-loop.md) +- [Usando o Yii com FrankenPHP](tutorial/using-yii-with-frankenphp.md) +- [Usando o Yii com Rapira](tutorial/using-yii-with-rapira.md) +- [Usando o Yii com RoadRunner](tutorial/using-yii-with-roadrunner.md) +- [Usando o Yii com Swoole](tutorial/using-yii-with-swoole.md) +- [Docker nos templates de aplicação](tutorial/docker.md) +- [Internacionalização](tutorial/i18n.md) + +## Helpers + +- [Arrays](https://github.com/yiisoft/arrays/) +- [Arquivos](https://github.com/yiisoft/files/) +- [Html](https://github.com/yiisoft/html/) +- [Json](https://github.com/yiisoft/json) +- [Utilitários de rede](https://github.com/yiisoft/network-utilities/) +- [VarDumper](https://github.com/yiisoft/var-dumper) +- [Strings](https://github.com/yiisoft/strings) + +## Extras + +- [Cookbook](../cookbook/index.md) +- [Glossário](glossary.md) diff --git a/src/pt-BR/guide/intro/upgrade-from-v1.md b/src/pt-BR/guide/intro/upgrade-from-v1.md new file mode 100644 index 00000000..1541b296 --- /dev/null +++ b/src/pt-BR/guide/intro/upgrade-from-v1.md @@ -0,0 +1,765 @@ +# Migrando da versão 1.1 + +> Se você não usou o Yii 1.1, pode pular esta seção e ir direto para a seção +> "[primeiros passos](../start/prerequisites.md)". + +O Yii3 não é um upgrade incremental do Yii 1.1. O Yii 2.0 foi uma reescrita +completa, e o Yii3 muda a arquitetura de novo: pacotes Composer, namespaces, +PHP 8, interfaces PSR, injeção de dependência, rotas explícitas, middleware +e pacotes separados para funcionalidades que no Yii 1.1 eram embutidas no +framework. + +Encare isso como a construção de uma nova aplicação Yii3 aproveitando a +experiência com o Yii 1.1. Reaproveite o conhecimento do domínio, o esquema +do banco de dados, os fluxos dos usuários e partes selecionadas do código +após refatorá-las. Não tente reproduzir a estrutura da aplicação Yii 1.1 no +Yii3. Uma conversão direta por busca e substituição não é realista. + +Para mais contexto, leia a seção do guia do Yii 2.0 [Upgrading from Version +1.1](https://www.yiiframework.com/doc/guide/2.0/en/intro-upgrade-from-v1). +Ela explica a primeira grande ruptura com o Yii 1.1: Composer, namespaces, +configuração de objetos, mudanças nas views, valores de retorno dos +controllers, widgets, assets, helpers, formulários, query builder, Active +Record e gerenciamento de URLs. O Yii3 se apoia em muitas dessas mudanças e +torna as dependências mais explícitas. + +## Abordagem recomendada + +Escolha um destes caminhos: + +- Construa uma nova aplicação Yii3 diretamente quando a aplicação Yii 1.1 + for pequena ou você já estiver reescrevendo os fluxos de requisição. +- Migre primeiro os conceitos do Yii 1.1 para o Yii 2.0 quando o time + precisar de um passo conceitual menor. +- Mantenha o Yii 1.1 rodando e reconstrua os fluxos críticos no Yii3 um a + um. + +Para a maioria das aplicações de longa duração, a terceira opção é a de +menor risco. Crie uma aplicação Yii3, conecte-a ao mesmo banco de dados e +construa vertical slices: rota, action, validação de entrada, persistência, +view, assets e testes. Cada slice deve ser Yii3 idiomático, mesmo quando se +baseia no comportamento da aplicação Yii 1.1. + +## Prepare a aplicação Yii 1.1 + +Uma preparação útil pode acontecer antes de a aplicação Yii3 estar +pronta. Estas refatorações tornam o comportamento antigo mais fácil de +entender e reduzem a quantidade de estado do framework Yii 1.1 que passa +para o código novo: + +- Remova o acesso direto a `Yii::app()` do código reutilizável onde for + viável. Se uma refatoração completa for grande demais, mantenha as + chamadas a `Yii::app()` perto de controllers, widgets e comandos, e passe + valores e serviços explicitamente para o código de nível mais baixo. +- Introduza repositórios ou serviços de consulta para as leituras do banco + de dados hoje espalhadas por controllers, views, métodos de + `CActiveRecord` e widgets. O Yii3 pode usar Active Record, mas não o exige + para toda tarefa de persistência. +- Separe as regras de negócio da infraestrutura do framework. Código que não + estende `CComponent`, não lê o estado global da aplicação nem renderiza + views é mais fácil de reutilizar como especificação para o código Yii3. +- Mova o comportamento reutilizável de controllers e classes Active Record + grandes para componentes de aplicação do Yii 1.1 ou serviços simples. Os + serviços do Yii3 são configurados e injetados de outra forma, mas a + fronteira de responsabilidade é parecida. +- Adicione testes ou verificações de caracterização em torno das rotas e + fluxos que você planeja reconstruir primeiro. Eles se tornam a + especificação executável do slice Yii3. + +Por exemplo, em vez de ler os dados do arquivo de posts diretamente em +vários controllers ou widgets, crie um pequeno serviço que descreva a +necessidade da aplicação: + +```php +class PostRepository extends CComponent +{ + public function getArchive() + { + // ... + } + + public function getTopForFrontPage($limit = 10) + { + // ... + } +} +``` + +A implementação no Yii3 pode usar `yiisoft/active-record`, `yiisoft/db` ou +outra camada de persistência. O importante é que controllers e views não +precisem mais conhecer esse detalhe. + +## O que aprender antes de começar + +Algumas escolhas do template de aplicação do Yii3 provavelmente serão +novidade para uma base de código Yii 1.1: + +- [Composer](https://getcomposer.org/). Aplicações e pacotes Yii3 são + instalados pelo Composer e carregados com autoloading PSR-4. +- [Namespaces](https://www.php.net/manual/en/language.namespaces.php). As + classes do Yii3 usam namespaces em vez dos prefixos de classe e path + aliases do Yii 1.1 para o carregamento de classes. +- [Docker](https://www.docker.com/get-started/). O template de aplicação + padrão do Yii3 inclui configuração do Docker. Usá-lo dá a cada aplicação + seu próprio ambiente reproduzível e reduz as diferenças entre o + desenvolvimento local e a produção. +- [Variáveis de + ambiente](https://en.wikipedia.org/wiki/Environment_variable). Os + templates do Yii3 costumam usá-las para configurações específicas de + ambiente e segredos, especialmente em deploys baseados em Docker. Isso + segue a mesma ideia da [configuração de aplicações + 12-factor](https://12factor.net/config). +- [Actions](../structure/action.md). O Yii3 não exige herança de + controller. Uma rota pode apontar para qualquer callable, e o template + padrão usa classes de action invocáveis. +- [Estrutura da aplicação](../structure/overview.md). A estrutura padrão do + Yii3 é diferente da do Yii 1.1. Comece com o template do Yii3 e altere-o + apenas quando a aplicação precisar. + +## PHP, Composer e namespaces + +Aplicações Yii 1.1 costumam depender de código da era do PHP 5, prefixos de +classe como `CController` e autoloading pelo nome da classe. Aplicações Yii3 +exigem PHP moderno e autoloading do Composer. + +Yii 1.1: + +```php +class SiteController extends CController +{ +} +``` + +Yii3: + +```php +namespace App\Web\HomePage; + +final readonly class Action +{ +} +``` + +Configure o namespace da sua aplicação com PSR-4: + +```json +{ + "autoload": { + "psr-4": { + "App\\": "src/" + } + } +} +``` + +Execute: + +```shell +composer dump-autoload +``` + +Ao reutilizar uma classe, dê a ela um namespace, adicione strict types, +substitua as classes base do Yii 1.1 e injete as dependências em vez de +lê-las do estado global da aplicação. Se essas mudanças deixarem a classe +estranha, use a classe antiga como especificação e escreva uma nova classe +Yii3. + +## Estrutura do projeto + +Uma aplicação Yii 1.1 frequentemente usa: + +```text +protected/ + commands/ + components/ + config/ + controllers/ + extensions/ + messages/ + migrations/ + models/ + views/ +themes/ +webroot/ +``` + +O template de aplicação atual do Yii3 usa: + +```text +assets/ +config/ +public/ +runtime/ +src/ +tests/ +``` + +Mapeamentos típicos a considerar: + +| Yii 1.1 | Yii3 | +|---------|------| +| `protected/controllers` | `src/Web/*/Action.php` ou serviços no estilo controller | +| `protected/models` | `src/Domain`, `src/Shared`, `src/Db` ou form models, conforme a responsabilidade | +| `protected/views` | templates perto da funcionalidade, por exemplo `src/Web/HomePage/template.php` | +| `protected/views/layouts` | templates de layout e assets em `src/Web/Shared/Layout` | +| `protected/components` | serviços configurados no container de injeção de dependência | +| `protected/extensions` | pacotes Composer ou pacotes locais | +| `protected/commands` | `src/Console/*Command.php` | +| `protected/messages` | arquivos de mensagens do tradutor | +| `protected/config` | `config/common`, `config/web`, `config/console`, `config/environments` | +| `webroot` | `public` | + +Não recrie `protected` no Yii3. Coloque o código PHP em `src`, os arquivos +públicos em `public`, os arquivos gerados/de runtime em `runtime` e a +configuração em `config`. + +## Configuração e componentes da aplicação + +A configuração do Yii 1.1 geralmente é um único array grande: + +```php +return [ + 'basePath' => dirname(__DIR__), + 'components' => [ + 'db' => [ + 'connectionString' => 'mysql:host=localhost;dbname=app', + 'username' => 'root', + 'password' => '', + ], + 'urlManager' => [ + 'urlFormat' => 'path', + 'rules' => [ + 'post/' => 'post/view', + ], + ], + ], +]; +``` + +No Yii3, a configuração é dividida por finalidade e os serviços são +conectados pelo container: + +- aliases em `config/common/aliases.php`; +- parâmetros em `config/common/params.php` e nos arquivos de ambiente; +- definições de serviços compartilhadas em `config/common/di/*.php`; +- definições de serviços apenas para web em `config/web/di/*.php`; +- rotas em `config/common/routes.php`; +- comandos de console em `config/console/*.php`. + +O grupo de DI de console do template padrão reutiliza as definições +compartilhadas de `config/common/di/*.php`. Se você precisar de definições +de container apenas para o console, adicione arquivos para elas ao grupo +`di-console` em `config/configuration.php` e reconstrua o merge plan. + +Substitua `Yii::app()->componentName` por serviços injetados pelo construtor: + +```php +use Yiisoft\Db\Connection\ConnectionInterface; +use Yiisoft\Router\UrlGeneratorInterface; + +final readonly class PostRepository +{ + public function __construct( + private ConnectionInterface $db, + private UrlGeneratorInterface $urlGenerator, + ) { + } +} +``` + +Veja [Configuração](../concept/configuration.md), +[Aliases](../concept/aliases.md) e [Container de injeção de +dependência](../concept/di-container.md). + +## Script de entrada + +Os scripts de entrada do Yii 1.1 geralmente carregam `yii.php` e criam uma +aplicação web: + +```php +require_once __DIR__ . '/../framework/yii.php'; + +Yii::createWebApplication($config)->run(); +``` + +Os scripts de entrada do Yii3 carregam o Composer e inicializam a aplicação +configurada. Comece com o arquivo `public/index.php` do `yiisoft/app` e +ajuste a configuração em vez de montar a aplicação manualmente no script de +entrada. + +Veja [Scripts de entrada](../structure/entry-script.md) e [Fluxo da +aplicação](../start/workflow.md). + +## Controllers, actions e rotas + +Os controllers do Yii 1.1 estendem `CController`, e as actions são métodos +chamados `actionName`: + +```php +class PostController extends CController +{ + public function actionView($id) + { + $post = Post::model()->findByPk($id); + + if ($post === null) { + throw new CHttpException(404); + } + + $this->render('view', ['post' => $post]); + } +} +``` + +O Yii3 não exige herança de controller. O template atual usa classes de +action invocáveis: + +```php +namespace App\Web\Post\View; + +use App\Post\PostRepository; +use Psr\Http\Message\ResponseInterface; +use Yiisoft\Router\CurrentRoute; +use Yiisoft\Yii\View\Renderer\WebViewRenderer; + +final readonly class Action +{ + public function __construct( + private CurrentRoute $currentRoute, + private PostRepository $posts, + private WebViewRenderer $viewRenderer, + ) { + } + + public function __invoke(): ResponseInterface + { + $post = $this->posts->findById((int) $this->currentRoute->getArgument('id')); + + return $this->viewRenderer->render(__DIR__ . '/template', [ + 'post' => $post, + ]); + } +} +``` + +A rota é explícita: + +```php +use App\Web\Post\View; +use Yiisoft\Router\Route; + +return [ + Route::get('/post/{id:\d+}') + ->action(View\Action::class) + ->name('post/view'), +]; +``` + +Defina as rotas antes do corpo das actions. Isso dá a você uma checklist dos +fluxos de requisição que você decidiu manter na aplicação Yii3. + +Veja [Actions](../structure/action.md), +[Middleware](../structure/middleware.md) e [Roteamento e geração de +URLs](../runtime/routing.md). + +## Requisições, respostas, redirecionamentos, sessões e cookies + +O código Yii 1.1 frequentemente lê e escreve por meio de `Yii::app()`: + +```php +$id = Yii::app()->request->getParam('id'); +Yii::app()->user->setFlash('success', 'Saved.'); +$this->redirect(['post/view', 'id' => $id]); +``` + +O Yii3 usa objetos de requisição e resposta PSR-7 e serviços injetáveis. A +entrada da requisição está disponível em `ServerRequestInterface`; +redirecionamentos, sessões, cookies e respostas são dependências explícitas. + +Veja [Requisição](../runtime/request.md), +[Resposta](../runtime/response.md), [Sessões](../runtime/sessions.md) e +[Cookies](../runtime/cookies.md). + +## Views e layouts + +As views do Yii 1.1 usam `$this` como o contexto do controller ou do +widget. Layouts e partials são renderizados por métodos do controller: + +```php + + +

title); ?>

+``` + +Nos templates do Yii3, `$this` é uma instância de `Yiisoft\View\WebView`: + +```php +use Yiisoft\Html\Html; +use Yiisoft\View\WebView; + +/** + * @var WebView $this + * @var Post $post + */ + +$this->setTitle($post->getTitle()); +?> + +

getTitle()) ?>

+``` + +Mova a lógica de view específica do controller para a action ou para um +presenter. Passe apenas os dados de que o template precisa. + +Veja [View](../views/view.md), [Injeções de +view](../views/view-injections.md) e [Template +engines](../views/template-engines.md). + +## Assets e scripts do cliente + +Aplicações Yii 1.1 frequentemente usam `CClientScript`, temas e publicação +de assets específica de extensões: + +```php +Yii::app()->clientScript->registerCssFile('/css/site.css'); +Yii::app()->clientScript->registerScriptFile('/js/site.js'); +``` + +O Yii3 usa asset bundles do `yiisoft/assets`: + +```php +namespace App\Web\Shared\Layout\Main; + +use Yiisoft\Assets\AssetBundle; + +final class MainAsset extends AssetBundle +{ + public ?string $basePath = '@assets/main'; + public ?string $baseUrl = '@assetsUrl/main'; + public ?string $sourcePath = '@assetsSource/main'; + + public array $css = ['site.css']; + public array $js = ['site.js']; +} +``` + +Registre os bundles pelo gerenciador de assets nos layouts ou views. + +Veja [Assets](../views/asset.md) e [Scripts, estilos e +metatags](../views/script-style-meta.md). + +## Models, formulários e validação + +O Yii 1.1 tem `CModel`, `CFormModel` e `CActiveRecord`. É comum uma única +classe de model conter os dados de entrada, rótulos, regras de validação, +persistência no banco de dados e lógica de negócio. + +O Yii3 funciona melhor quando essas responsabilidades são separadas: + +- dados e rótulos do formulário: `yiisoft/form-model`; +- regras de validação: `yiisoft/validator`; +- renderização de formulários: `yiisoft/form`; +- persistência: repositórios, `yiisoft/db` ou `yiisoft/active-record`; +- fluxos de negócio: serviços da aplicação. + +Form model no Yii 1.1: + +```php +class ContactForm extends CFormModel +{ + public $name; + public $email; + + public function rules() + { + return [ + ['name, email', 'required'], + ['email', 'email'], + ]; + } +} +``` + +Form model no Yii3: + +```php +use Yiisoft\FormModel\FormModel; +use Yiisoft\Validator\Rule\Email; +use Yiisoft\Validator\Rule\Required; + +final class ContactForm extends FormModel +{ + #[Required] + public ?string $name = null; + + #[Required] + #[Email] + public ?string $email = null; +} +``` + +Veja [Trabalhando com formulários](../start/forms.md), [Validando a +entrada](https://github.com/yiisoft/validator/blob/master/docs/guide/en/README.md), +[yiisoft/form](https://github.com/yiisoft/form) e +[yiisoft/form-model](https://github.com/yiisoft/form-model). + +## Active Record + +O Active Record do Yii 1.1 usa `CActiveRecord::model()` e atributos +dinâmicos: + +```php +class Post extends CActiveRecord +{ + public static function model($className = __CLASS__) + { + return parent::model($className); + } + + public function tableName() + { + return '{{post}}'; + } + + public function rules() + { + return [ + ['title, body', 'required'], + ['title', 'length', 'max' => 255], + ]; + } +} +``` + +A opção incremental no Yii3 é o +[yiisoft/active-record](https://github.com/yiisoft/active-record): + +```php +use Yiisoft\ActiveRecord\ActiveRecord; + +final class Post extends ActiveRecord +{ + protected int $id; + protected string $title; + protected string $body; + + public function tableName(): string + { + return '{{%post}}'; + } + + public function getTitle(): ?string + { + return $this->title ?? null; + } + + public function setTitle(string $title): void + { + $this->title = $title; + } +} +``` + +Mova o `rules()` do Yii 1.1 para um form model, regras do validator ou um +serviço. Mantenha o Active Record focado em persistência: mapeamento de +tabelas, propriedades, relações e operações no banco de dados. + +Em aplicações mais complexas, considere substituir o código muito dependente +de Active Record por repositórios e objetos de domínio. Dá mais trabalho no +início, mas evita carregar o acoplamento entre formulário e persistência do +Yii 1.1 para a nova aplicação. + +Veja [Trabalhando com banco de dados](../start/databases.md), +[Migrations](../databases/db-migrations.md) e +[yiisoft/active-record](https://github.com/yiisoft/active-record). + +## Consultas ao banco de dados e migrations + +O código Yii 1.1 pode usar `CDbCriteria`, `CDbCommand`, +`CActiveDataProvider` e data providers do `CGridView`. No Yii3, use +`yiisoft/db` para acesso ao banco de dados e construção de consultas, e +`yiisoft/data` / `yiisoft/yii-dataview` para data readers e widgets. + +As migrations não são compatíveis entre o Yii 1.1 e o Yii3. Para uma +aplicação existente, crie uma base a partir do esquema atual e use +migrations do Yii3 para as novas mudanças. + +Veja [Trabalhando com banco de dados](../start/databases.md) e +[Migrations](../databases/db-migrations.md). + +## GridView e widgets de dados + +O `CGridView` do Yii 1.1 costuma ser configurado com `CActiveDataProvider`: + +```php +$this->widget('zii.widgets.grid.CGridView', [ + 'dataProvider' => $dataProvider, + 'columns' => [ + 'id', + 'title', + [ + 'class' => 'CButtonColumn', + ], + ], +]); +``` + +O Yii3 usa o +[yiisoft/yii-dataview](https://github.com/yiisoft/yii-dataview): + +```php +use Yiisoft\Data\Reader\ReadableDataInterface; +use Yiisoft\Yii\DataView\Column\DataColumn; +use Yiisoft\Yii\DataView\GridView\Column\ActionColumn; +use Yiisoft\Yii\DataView\GridView\GridView; + +/** + * @var ReadableDataInterface $dataReader + */ + +echo GridView::widget() + ->dataReader($dataReader) + ->columns( + new DataColumn('id'), + new DataColumn('title'), + new ActionColumn(), + ); +``` + +Substitua o antigo data provider por um serviço de consulta que retorne um +data reader. Modele os filtros como regras do validator e parâmetros de rota +ou de consulta. + +Veja [Usando htmx para recarregamentos +parciais](../../cookbook/using-htmx-for-partial-reloads.md) e a +[documentação do GridView do +yii-dataview](https://github.com/yiisoft/yii-dataview/blob/master/docs/en/guide/gridview.md). + +## Gerenciamento de URLs + +Yii 1.1: + +```php +echo CHtml::link('View', ['post/view', 'id' => $post->id]); +$url = Yii::app()->createUrl('post/view', ['id' => $post->id]); +``` + +Yii3: + +```php +use Yiisoft\Html\Html; +use Yiisoft\Router\UrlGeneratorInterface; + +$url = $urlGenerator->generate('post/view', ['id' => $post->getId()]); + +echo Html::a('View', $url)->render(); +``` + +Prefira rotas nomeadas. Elas tornam as views e as colunas de action do +GridView mais fáceis de projetar e manter. + +Veja [Roteamento e geração de URLs](../runtime/routing.md). + +## Filtros, controle de acesso e autenticação + +Os filtros de controller do Yii 1.1 são métodos do controller ou classes de +filtro: + +```php +public function filters() +{ + return [ + 'accessControl', + ]; +} +``` + +O Yii3 usa middleware e pacotes focados. Mova autenticação, autorização, +CSRF, detecção de idioma e parsing do corpo da requisição para fora dos +controllers, em middlewares ou serviços. + +Veja [Middleware](../structure/middleware.md), +[Autenticação](../security/authentication.md) e +[Autorização](../security/authorization.md). + +## Widgets, helpers e extensões + +Os widgets e helpers do Yii 1.1 geralmente dependem de classes base +específicas do Yii, como `CWidget` e `CHtml`, e do autoloading de +extensões. No Yii3: + +- substitua as chamadas a helpers por `yiisoft/html`, `yiisoft/arrays`, + `yiisoft/strings` ou helpers da aplicação; +- substitua as extensões por pacotes Composer; +- reconstrua widgets personalizados com `yiisoft/widget` ou com + serviços/templates simples; +- substitua os widgets do jQuery UI e do Bootstrap por pacotes de frontend + atuais ou pacotes de widgets do Yii3, quando disponíveis. + +Veja [Widgets](../views/widget.md). + +## Aplicações de console + +Os comandos de console do Yii 1.1 estendem `CConsoleCommand`: + +```php +class ReportCommand extends CConsoleCommand +{ + public function actionSend() + { + } +} +``` + +Os comandos de console do Yii3 são comandos do Symfony Console configurados +como serviços: + +```php +namespace App\Console; + +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +#[AsCommand(name: 'report/send')] +final class SendReportCommand extends Command +{ + protected function execute(InputInterface $input, OutputInterface $output): int + { + return Command::SUCCESS; + } +} +``` + +Veja [Aplicações de console](../tutorial/console-applications.md). + +## Internacionalização + +Os arquivos de mensagens do Yii 1.1 em `protected/messages` geralmente podem +ser mantidos conceitualmente, mas a configuração muda. O Yii3 usa pacotes de +tradução e fontes de mensagens explícitas. Mova os arquivos de mensagens +para a estrutura esperada pelo pacote de mensagens do tradutor escolhido e +injete os serviços de tradução onde for necessário. + +Veja [Internacionalização](../tutorial/i18n.md). + +## O que refatorar antes de reutilizar + +Estas refatorações no Yii 1.1 tornam o comportamento antigo mais fácil de +entender e reutilizar: + +- isole as consultas ao banco de dados dos controllers; +- remova o acesso direto a `Yii::app()` do código de domínio; +- tire a validação do Active Record quando ela descreve a entrada da + requisição, e não invariantes do banco de dados; +- substitua actions grandes de controller por serviços; +- documente todas as rotas e regras de URL; +- adicione testes em torno dos fluxos que você planeja reconstruir primeiro; +- atualize a sintaxe PHP gradualmente, se o runtime antigo permitir. + +O objetivo não é fazer o Yii 1.1 parecer com o Yii3. O objetivo é reduzir o +acoplamento oculto antes que o código cruze a fronteira do framework. diff --git a/src/pt-BR/guide/intro/upgrade-from-v2.md b/src/pt-BR/guide/intro/upgrade-from-v2.md new file mode 100644 index 00000000..f80fa548 --- /dev/null +++ b/src/pt-BR/guide/intro/upgrade-from-v2.md @@ -0,0 +1,884 @@ +# Migrando da versão 2.0 + +> Se você não usou o Yii 2.0, pode pular esta seção e ir direto para a seção "[primeiros passos](../start/prerequisites.md)" +> do guia. + +O Yii3 mantém muitas ideias do Yii, mas não é um substituto direto do Yii +2.0. Ele usa recursos do PHP 8, interfaces PSR, injeção de dependência, +composição explícita de pacotes e um template de aplicação diferente. Use +sua experiência com o Yii 2.0 para projetar uma nova aplicação Yii3 de forma +deliberada, em vez de tentar reproduzir a estrutura da aplicação antiga. + +Para as aplicações de origem, compare com: + +- [yiisoft/yii2-app-basic](https://github.com/yiisoft/yii2-app-basic) +- [yiisoft/yii2-app-advanced](https://github.com/yiisoft/yii2-app-advanced) + +Para a estrutura de destino, compare com: + +- [yiisoft/app](https://github.com/yiisoft/app) +- [Guia do Yii3](../index.md) + +Antes de começar, [confira a política de manutenção e as datas de fim de +vida do Yii 2.0](https://www.yiiframework.com/release-cycle). Manter uma +aplicação Yii 2.0 madura no Yii 2.0 pode ser uma escolha válida. Um projeto +Yii3 é mais útil quando você quer o novo ecossistema de pacotes, tipagem +mais rigorosa, middleware PSR e uma arquitetura mais explícita. + +## Abordagem recomendada + +Pense no trabalho como a construção de uma aplicação Yii3 guiada pela +antiga. O projeto antigo diz quais rotas, formulários, tabelas do banco de +dados, regras de negócio e fluxos dos usuários importam. O projeto Yii3 deve +decidir de novo onde cada uma dessas responsabilidades fica. + +Construa em vertical slices: + +1. Crie uma nova aplicação Yii3 com `yiisoft/app`. +2. Configure o autoloading do Composer e adicione só o código necessário + para o slice que você está construindo. +3. Defina a configuração e as rotas antes de escrever as actions. +4. Construa um fluxo de requisição por vez: rota, action, modelo de entrada, + serviço, persistência, view, assets, testes. +5. Mantenha a aplicação Yii 2.0 rodando até cada fluxo ser verificado no + Yii3. + +Evite mover toda a árvore de diretórios primeiro. Os padrões do Yii3 são +intencionalmente diferentes, e uma cópia mecânica tende a preservar as +suposições de service locator do Yii 2.0. Prefira decisões pequenas e +revisadas a carregar a estrutura antiga só porque ela é familiar. + +## Prepare a aplicação Yii 2.0 + +Uma preparação útil pode acontecer antes de a aplicação Yii3 estar +pronta. Estas refatorações melhoram o próprio projeto Yii 2.0 e deixam a +reescrita posterior menos dependente de estado oculto do framework: + +- Substitua o acesso a `Yii::$app` no código reutilizável por argumentos do + construtor onde for viável. Se uma refatoração completa para injeção de + dependência for grande demais, mantenha as chamadas a `Yii::$app` perto de + controllers e widgets, e passe valores e serviços explicitamente para o + código de nível mais baixo. +- Introduza repositórios ou serviços de consulta para as leituras do banco + de dados hoje espalhadas por controllers, views, widgets e métodos do + Active Record. O Yii3 não exige Active Record para persistência, então uma + fronteira de repositório dá a você um lugar natural para trocar a + implementação depois. +- Separe as regras de negócio da infraestrutura do framework. Código de + domínio que não estende classes do Yii, não lê o estado global da + aplicação nem renderiza views é muito mais fácil de reutilizar ou + reescrever. +- Mova o comportamento reutilizável para componentes ou serviços do Yii 2.0 + em vez de mantê-lo dentro de controllers e classes Active Record + grandes. Os serviços do Yii3 são configurados e injetados de outra forma, + mas a fronteira de responsabilidade é parecida. +- Adicione testes em torno das rotas e fluxos que você planeja reconstruir + primeiro. Eles se tornam a especificação executável do slice Yii3. + +Por exemplo, em vez de ler os dados do arquivo de posts diretamente em +vários controllers ou widgets, crie um pequeno serviço que descreva a +necessidade da aplicação: + +```php +final class PostRepository +{ + public function getArchive(): array + { + // ... + } + + public function getTopForFrontPage(int $limit = 10): array + { + // ... + } +} +``` + +A implementação no Yii3 ainda pode usar Active Record, ou pode usar +consultas do `yiisoft/db`. O importante é que controllers e views não +precisem mais conhecer esse detalhe. + +## O que aprender antes de começar + +Vale a pena conhecer algumas escolhas do template de aplicação do Yii3 antes +de começar a mover funcionalidades: + +- [Docker](https://www.docker.com/get-started/). O template de aplicação + padrão do Yii3 inclui configuração do Docker. Usá-lo dá a cada aplicação + seu próprio ambiente reproduzível e reduz as diferenças entre o + desenvolvimento local e a produção. +- [Variáveis de + ambiente](https://en.wikipedia.org/wiki/Environment_variable). Os + templates do Yii3 costumam usá-las para configurações específicas de + ambiente e segredos, especialmente em deploys baseados em Docker. Isso + segue a mesma ideia da [configuração de aplicações + 12-factor](https://12factor.net/config). +- [Actions](../structure/action.md). O Yii3 não exige herança de + controller. Uma rota pode apontar para qualquer callable, e o template + padrão usa classes de action invocáveis. +- [Estrutura da aplicação](../structure/overview.md). A estrutura padrão do + Yii3 é diferente da do Yii 2.0. Ela é flexível, mas comece com o template + do Yii3 e altere-o apenas quando a aplicação precisar. + +## Requisitos de PHP + +Os templates de aplicação do Yii3 exigem PHP 8.2 ou superior. Com isso, o +código da aplicação pode usar recursos da linguagem que não eram comuns em +aplicações Yii 2.0: + +- [Declarações de + tipo](https://www.php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration) +- [Declarações de tipo de + retorno](https://www.php.net/manual/en/functions.returning-values.php#functions.returning-values.type-declaration) +- [Visibilidade de constantes de + classe](https://www.php.net/manual/en/language.oop5.constants.php) +- [Argumentos + nomeados](https://www.php.net/manual/en/functions.arguments.php#functions.named-arguments) +- [Classes + anônimas](https://www.php.net/manual/en/language.oop5.anonymous.php) +- [::class](https://www.php.net/manual/en/language.oop5.basic.php#language.oop5.basic.class.class) +- [Generators](https://www.php.net/manual/en/language.generators.php) +- [Funções + variádicas](https://www.php.net/manual/en/functions.arguments.php#functions.variable-arg-list) +- [Propriedades + readonly](https://www.php.net/manual/en/language.oop5.properties.php#language.oop5.properties.readonly-properties) +- [Classes + readonly](https://www.php.net/manual/en/language.oop5.basic.php#language.oop5.basic.class.readonly) +- [Promoção de propriedades no + construtor](https://www.php.net/manual/en/language.oop5.decon.php#language.oop5.decon.constructor.promotion) +- [Atributos](https://www.php.net/manual/en/language.attributes.php) + +Rode análise estática e testes no Yii 2.0 antes de reutilizar código no +Yii3. Código com tipos explícitos, serviços pequenos e poucas dependências +implícitas de `Yii::$app` é mais fácil de entender e de encaixar na nova +aplicação. + +## Estrutura do projeto + +Aplicações Yii 2.0 costumam manter os papéis do framework em diretórios de +primeiro nível: + +```text +assets/ +commands/ +config/ +controllers/ +models/ +runtime/ +views/ +web/ +widgets/ +``` + +O template advanced do Yii 2.0 divide os mesmos papéis por aplicação: + +```text +backend/ +common/ +console/ +frontend/ +``` + +O template de aplicação atual do Yii3 é organizado em torno do código-fonte, +da configuração, dos arquivos públicos e dos arquivos de runtime: + +```text +assets/ +config/ +public/ +runtime/ +src/ +tests/ +``` + +Mapeamentos típicos a considerar: + +| Yii 2.0 basic | Yii 2.0 advanced | Yii3 | +|---------------|------------------|------| +| `controllers/` | `frontend/controllers/`, `backend/controllers/` | `src/Web/*/Action.php` ou classes no estilo controller | +| `models/` | `common/models/`, models específicos de cada app | `src/Domain`, `src/Shared`, `src/Web/*` ou `src/Db`, conforme a responsabilidade | +| `views/` | `frontend/views/`, `backend/views/` | templates perto da funcionalidade, por exemplo `src/Web/HomePage/template.php` | +| `views/layouts/` | diretórios de layout de cada app | classes/templates de layout, por exemplo `src/Web/Shared/Layout/Main` | +| `assets/` | asset bundles de cada app | `assets/` para os arquivos-fonte e `src/Web/.../*Asset.php` para os bundles | +| `web/` | `frontend/web/`, `backend/web/` | `public/` | +| `commands/` | `console/controllers/` | `src/Console/*Command.php` | +| `config/*.php` | arquivos de configuração do app e comuns | `config/common`, `config/web`, `config/console`, `config/environments` | + +Não existe um layout obrigatório único. A mudança importante é que +aplicações Yii3 devem agrupar o código por responsabilidade e tornar as +dependências explícitas. Se você vem do template advanced, trate `frontend` +e `backend` como contextos web separados. O código de domínio compartilhado +pode ficar em `src/Shared` ou em pacotes específicos da aplicação. + +## Composer e autoloading + +Aplicações Yii 2.0 geralmente fazem require de `vendor/autoload.php` e +`vendor/yiisoft/yii2/Yii.php` em `web/index.php`. Aplicações Yii3 precisam +apenas do autoloader do Composer e do código de bootstrap da aplicação. + +Configure o namespace da sua aplicação com PSR-4: + +```json +{ + "autoload": { + "psr-4": { + "App\\": "src/" + } + } +} +``` + +Depois, reconstrua os arquivos de autoload do Composer: + +```shell +composer dump-autoload +``` + +Instale os pacotes Yii3 de forma intencional. O Yii3 é dividido em pacotes +focados, então funcionalidades como acesso ao banco de dados, formulários, +validação, assets, widgets de dados, autenticação e cache são dependências +separadas do Composer. + +## Configuração e serviços + +No Yii 2.0, muitos serviços são configurados como componentes da aplicação e +acessados pelo service locator: + +```php +$cache = Yii::$app->cache; +$db = Yii::$app->db; +$url = Yii::$app->urlManager->createUrl(['post/view', 'id' => $id]); +``` + +No Yii3, os serviços são configurados no container e injetados onde são +necessários: + +```php +use Psr\SimpleCache\CacheInterface; +use Yiisoft\Db\Connection\ConnectionInterface; +use Yiisoft\Router\UrlGeneratorInterface; + +final readonly class PostService +{ + public function __construct( + private ConnectionInterface $db, + private CacheInterface $cache, + private UrlGeneratorInterface $urlGenerator, + ) { + } +} +``` + +Mova a configuração por grupos: + +- aliases para `config/common/aliases.php`; +- definições de rotas para `config/common/routes.php`; +- definições de serviços compartilhadas para `config/common/di/*.php`; +- definições de serviços apenas para web para `config/web/di/*.php`; +- parâmetros e comandos de console para `config/console/*.php`; +- parâmetros compartilhados para `config/common/params.php`; +- sobrescritas por ambiente para `config/environments`. + +O grupo `di-console` do template padrão reutiliza as definições +compartilhadas de `config/common/di/*.php`. Se você precisar de definições +de container apenas para o console, adicione os arquivos correspondentes ao +grupo `di-console` em `config/configuration.php` e reconstrua o merge plan. + +Veja [Configuração](../concept/configuration.md), +[Aliases](../concept/aliases.md) e [Container de injeção de +dependência](../concept/di-container.md). + +## Script de entrada e bootstrap + +Um script de entrada do template basic do Yii 2.0 geralmente cria a +aplicação diretamente: + +```php +defined('YII_DEBUG') or define('YII_DEBUG', true); +defined('YII_ENV') or define('YII_ENV', 'dev'); + +require __DIR__ . '/../vendor/autoload.php'; +require __DIR__ . '/../vendor/yiisoft/yii2/Yii.php'; + +$config = require __DIR__ . '/../config/web.php'; + +(new yii\web\Application($config))->run(); +``` + +No Yii3, use o script de entrada do template de aplicação como fonte da +verdade. Ele carrega o Composer e inicializa o runner da aplicação +configurada. Evite recriar o antigo padrão `yii\web\Application` em +`public/index.php`; coloque a configuração nos arquivos de configuração e as +dependências no container. + +Veja [Scripts de entrada](../structure/entry-script.md) e [Fluxo da +aplicação](../start/workflow.md). + +## Controllers, actions e roteamento + +As rotas do Yii 2.0 geralmente apontam para métodos de action de +controllers: + +```php +namespace app\controllers; + +use yii\web\Controller; + +final class SiteController extends Controller +{ + public function actionIndex(): string + { + return $this->render('index'); + } +} +``` + +O Yii3 não exige classes base de controller. O template de aplicação atual +usa classes de action invocáveis: + +```php +namespace App\Web\HomePage; + +use Psr\Http\Message\ResponseInterface; +use Yiisoft\Yii\View\Renderer\WebViewRenderer; + +final readonly class Action +{ + public function __construct( + private WebViewRenderer $viewRenderer, + ) { + } + + public function __invoke(): ResponseInterface + { + return $this->viewRenderer->render(__DIR__ . '/template'); + } +} +``` + +As rotas são explícitas: + +```php +use App\Web; +use Yiisoft\Router\Group; +use Yiisoft\Router\Route; + +return [ + Group::create() + ->routes( + Route::get('/') + ->action(Web\HomePage\Action::class) + ->name('home'), + ), +]; +``` + +Ao redesenhar o fluxo de um controller, liste todas as actions do Yii 2.0 e +crie rotas nomeadas para os fluxos de que você ainda precisa. Depois, +implemente cada fluxo como uma classe invocável ou um serviço no estilo +controller. A injeção pelo construtor substitui as chamadas a `Yii::$app` e +as propriedades do controller. + +Veja [Actions](../structure/action.md), +[Middleware](../structure/middleware.md) e [Roteamento e geração de +URLs](../runtime/routing.md). + +## Requisições, respostas, sessões e cookies + +As actions do Yii 2.0 frequentemente leem os dados da requisição e escrevem +os dados da resposta por meio de componentes da aplicação: + +```php +$id = Yii::$app->request->get('id'); +Yii::$app->session->setFlash('success', 'Saved.'); + +return $this->redirect(['post/view', 'id' => $id]); +``` + +O Yii3 usa objetos de requisição e resposta PSR-7 e serviços injetáveis: + +```php +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ResponseFactoryInterface; +use Psr\Http\Message\ServerRequestInterface; +use Yiisoft\Http\Status; +use Yiisoft\Router\UrlGeneratorInterface; + +final readonly class SavePostAction +{ + public function __construct( + private ResponseFactoryInterface $responseFactory, + private UrlGeneratorInterface $urlGenerator, + ) { + } + + public function __invoke(ServerRequestInterface $request): ResponseInterface + { + $id = (int) ($request->getQueryParams()['id'] ?? 0); + $url = $this->urlGenerator->generate('post/view', ['id' => $id]); + + return $this->responseFactory + ->createResponse(Status::SEE_OTHER) + ->withHeader('Location', $url); + } +} +``` + +Pense no tratamento de requisições logo no início, porque ele afeta +formulários, filtros, endpoints REST, redirecionamentos e testes. + +Veja [Requisição](../runtime/request.md), +[Resposta](../runtime/response.md), [Sessões](../runtime/sessions.md) e +[Cookies](../runtime/cookies.md). + +## Views, layouts, assets e URLs + +No Yii 2.0, a renderização do controller procura arquivos em +`views/{controller}` e layouts em `views/layouts`: + +```php +return $this->render('view', [ + 'model' => $model, +]); +``` + +No Yii3, o caminho do template é explícito na action: + +```php +return $this->viewRenderer->render(__DIR__ . '/view', [ + 'post' => $post, +]); +``` + +Um template do Yii3 recebe uma instância de `Yiisoft\View\WebView` como +`$this`: + +```php +use App\Shared\ApplicationParams; +use Yiisoft\Html\Html; +use Yiisoft\View\WebView; + +/** + * @var WebView $this + * @var ApplicationParams $applicationParams + * @var string $title + */ + +$this->setTitle($title . ' - ' . $applicationParams->name); +?> + +

+``` + +Os asset bundles passam de `yii\web\AssetBundle` para +`Yiisoft\Assets\AssetBundle`: + +```php +namespace App\Web\Shared\Layout\Main; + +use Yiisoft\Assets\AssetBundle; + +final class MainAsset extends AssetBundle +{ + public ?string $basePath = '@assets/main'; + public ?string $baseUrl = '@assetsUrl/main'; + public ?string $sourcePath = '@assetsSource/main'; + + public array $css = [ + 'site.css', + ]; +} +``` + +Registre os assets em um layout ou view pelo gerenciador de assets: + +```php +$assetManager->register(MainAsset::class); + +$this->addCssFiles($assetManager->getCssFiles()); +$this->addJsFiles($assetManager->getJsFiles()); +``` + +Substitua o uso de `yii\helpers\Url` e `Yii::$app->urlManager` por rotas nomeadas e +`Yiisoft\Router\UrlGeneratorInterface`: + +```php +$url = $urlGenerator->generate('post/view', ['id' => $post->getId()]); +``` + +Veja [View](../views/view.md), [Assets](../views/asset.md), [Scripts, +estilos e metatags](../views/script-style-meta.md) e [Template +engines](../views/template-engines.md). + +## Formulários e validação + +O Yii 2.0 frequentemente junta dados do formulário, rótulos, validação e às +vezes persistência em uma classe `yii\base\Model` ou `yii\db\ActiveRecord`: + +```php +final class ContactForm extends \yii\base\Model +{ + public $name; + public $email; + + public function rules(): array + { + return [ + [['name', 'email'], 'required'], + ['email', 'email'], + ]; + } +} +``` + +O Yii3 separa essas responsabilidades. Use `yiisoft/form-model` para os +dados e metadados do formulário, e `yiisoft/validator` para as regras: + +```php +use Yiisoft\FormModel\FormModel; +use Yiisoft\Validator\Rule\Email; +use Yiisoft\Validator\Rule\Required; + +final class ContactForm extends FormModel +{ + #[Required] + public ?string $name = null; + + #[Required] + #[Email] + public ?string $email = null; +} +``` + +Para a renderização de formulários, substitua `yii\widgets\ActiveForm` pelos +campos do `yiisoft/form` e pela integração com form models. Para a +hidratação da entrada, prefira os pacotes de form model e hydrator em vez de +atribuir em massa dados arbitrários da requisição a objetos de persistência. + +Veja [Trabalhando com formulários](../start/forms.md), [Validando a +entrada](https://github.com/yiisoft/validator/blob/master/docs/guide/en/README.md), +[yiisoft/form](https://github.com/yiisoft/form) e +[yiisoft/form-model](https://github.com/yiisoft/form-model). + +## Active Record e persistência + +Existem duas escolhas comuns no Yii3 para código que usava classes Active +Record do Yii 2.0. + +O primeiro caminho é arquitetural: mova a lógica de negócio para serviços e +objetos de domínio e use repositórios para a persistência. Ele é recomendado +quando o model do Yii 2.0 contém validação, cenários de formulário, +verificações de autorização, envio de e-mails, upload de arquivos e acesso +ao banco de dados na mesma classe. + +O segundo caminho é incremental: represente o modelo do banco de dados com o +[yiisoft/active-record](https://github.com/yiisoft/active-record). Ele é +mais próximo do Yii 2.0 e pode ser bem mais rápido quando suas classes +Active Record descrevem principalmente tabelas e relações. + +Yii 2.0: + +```php +final class Post extends \yii\db\ActiveRecord +{ + public static function tableName(): string + { + return '{{%post}}'; + } + + public function rules(): array + { + return [ + [['title', 'body'], 'required'], + ['title', 'string', 'max' => 255], + ]; + } +} +``` + +Active Record no Yii3: + +```php +use Yiisoft\ActiveRecord\ActiveRecord; + +final class Post extends ActiveRecord +{ + protected int $id; + protected string $title; + protected string $body; + + public function tableName(): string + { + return '{{%post}}'; + } + + public function getId(): ?int + { + return $this->id ?? null; + } + + public function getTitle(): ?string + { + return $this->title ?? null; + } + + public function setTitle(string $title): void + { + $this->title = $title; + } +} +``` + +Não mova o `rules()` do Yii 2.0 diretamente para a classe Active Record. No +Yii3, a validação pertence a regras do validator, form models, objetos de +comando ou serviços: + +```php +use Yiisoft\FormModel\FormModel; +use Yiisoft\Validator\Rule\Length; +use Yiisoft\Validator\Rule\Required; + +final class PostInput extends FormModel +{ + #[Required] + #[Length(max: 255)] + public ?string $title = null; + + #[Required] + public ?string $body = null; +} +``` + +Depois, copie os dados validados para o registro ou passe-os para um serviço +da aplicação: + +```php +$post = new Post(); +$post->setTitle($input->title); +$post->save(); +``` + +Ao decidir o que reutilizar, verifique cada método do Active Record: + +- o mapeamento de tabelas e as relações geralmente podem ir para o + `yiisoft/active-record`; +- a validação deve ir para o `yiisoft/validator`; +- rótulos e dicas de formulário devem ir para o `yiisoft/form-model`; +- os search models devem virar serviços de consulta/data reader; +- os fluxos de negócio devem virar serviços; +- os eventos devem usar eventos PSR-14 ou eventos específicos de pacotes; +- o uso direto de `Yii::$app->db` deve virar dependências de banco de dados + injetadas. + +As migrations do Yii 2.0 e as migrations do `yiisoft/db-migration` do Yii3 +não são compatíveis. Comece um novo histórico de migrations ou crie dumps da +estrutura do esquema atual, e use migrations do Yii3 para as mudanças +futuras no esquema. + +Veja [Trabalhando com banco de dados](../start/databases.md), +[Migrations](../databases/db-migrations.md) e +[yiisoft/active-record](https://github.com/yiisoft/active-record). + +## GridView e widgets de dados + +O `GridView` do Yii 2.0 costuma ser usado com `ActiveDataProvider`: + +```php +use yii\grid\GridView; + +echo GridView::widget([ + 'dataProvider' => $dataProvider, + 'filterModel' => $searchModel, + 'columns' => [ + 'id', + 'title', + 'created_at:datetime', + ['class' => 'yii\grid\ActionColumn'], + ], +]); +``` + +O Yii3 usa o +[yiisoft/yii-dataview](https://github.com/yiisoft/yii-dataview). Ele +renderiza dados a partir de um data reader e usa configuração fluente do +widget: + +```php +use Yiisoft\Data\Reader\ReadableDataInterface; +use Yiisoft\Yii\DataView\Column\DataColumn; +use Yiisoft\Yii\DataView\GridView\Column\ActionColumn; +use Yiisoft\Yii\DataView\GridView\GridView; + +/** + * @var ReadableDataInterface $dataReader + */ + +echo GridView::widget() + ->dataReader($dataReader) + ->columns( + new DataColumn('id'), + new DataColumn('title', header: 'Title'), + new DataColumn('created_at', header: 'Created'), + new ActionColumn(), + ); +``` + +Para ordenação, paginação, filtragem e URLs de actions, conecte o widget ao +Yii Router: + +```php +use Yiisoft\Yii\DataView\YiiRouter\ActionColumnUrlConfig; +use Yiisoft\Yii\DataView\YiiRouter\ActionColumnUrlCreator; +use Yiisoft\Yii\DataView\YiiRouter\UrlCreator; +use Yiisoft\Yii\DataView\YiiRouter\UrlParameterProvider; + +echo GridView::widget() + ->dataReader($dataReader) + ->urlParameterProvider(new UrlParameterProvider($currentRoute)) + ->urlCreator(new UrlCreator($urlGenerator)) + ->columns( + new DataColumn('id'), + new DataColumn('title'), + new ActionColumn( + urlCreator: new ActionColumnUrlCreator($urlGenerator, $currentRoute), + urlConfig: new ActionColumnUrlConfig(baseRouteName: 'post'), + ), + ); +``` + +Um search model do Yii 2.0 geralmente vira um serviço de consulta que: + +1. lê os parâmetros de filtro e ordenação da requisição; +2. valida esses parâmetros com `yiisoft/validator`; +3. monta uma consulta ao banco de dados ou ao repositório; +4. expõe um data reader para o GridView. + +Veja [Usando htmx para recarregamentos +parciais](../../cookbook/using-htmx-for-partial-reloads.md) para um fluxo +completo de GridView no Yii3 e a [documentação do GridView do +yii-dataview](https://github.com/yiisoft/yii-dataview/blob/master/docs/en/guide/gridview.md). + +## Filtros, middleware e controle de acesso + +Os filtros e behaviors de controller do Yii 2.0 geralmente são assim: + +```php +public function behaviors(): array +{ + return [ + 'access' => [ + 'class' => \yii\filters\AccessControl::class, + 'rules' => [ + ['allow' => true, 'roles' => ['@']], + ], + ], + ]; +} +``` + +No Yii3, o processamento das requisições é baseado em middleware. Mova +responsabilidades transversais, como autenticação, autorização, parsing do +corpo, negociação de idioma, verificação de CSRF e tratamento de erros, para +middlewares ou serviços dedicados. Mantenha as actions focadas no fluxo de +requisição que elas implementam. + +Veja [Middleware](../structure/middleware.md), +[Autenticação](../security/authentication.md) e +[Autorização](../security/authorization.md). + +## Comandos de console + +Os comandos de console do Yii 2.0 estendem `yii\console\Controller`: + +```php +final class ReportController extends \yii\console\Controller +{ + public function actionSend(): int + { + // ... + return self::EXIT_CODE_NORMAL; + } +} +``` + +Os comandos de console do Yii3 são serviços em `src/Console`: + +```php +namespace App\Console; + +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +#[AsCommand(name: 'report/send')] +final class SendReportCommand extends Command +{ + protected function execute(InputInterface $input, OutputInterface $output): int + { + // ... + return Command::SUCCESS; + } +} +``` + +Passe as dependências dos comandos para injeção pelo construtor e registre +os comandos na configuração de console. + +Veja [Aplicações de console](../tutorial/console-applications.md). + +## APIs REST + +Os controllers REST, serializers e formatadores de resposta do Yii 2.0 não +passam diretamente para o Yii3. Comece pelas respostas PSR-7 e pelo +roteamento explícito. Construa um recurso por vez: + +1. defina rotas para as operações de coleção e de item; +2. injete as dependências de requisição, persistência, serializer e response + factory; +3. valide a entrada com `yiisoft/validator`; +4. retorne respostas JSON pelos helpers de resposta do Yii3 ou por factories + PSR-7; +5. mova a autenticação e o rate limiting para middlewares. + +Veja [Resposta](../runtime/response.md), +[Autenticação](../security/authentication.md) e +[Autorização](../security/authorization.md). + +## Testes + +Não deixe os testes para quando a aplicação Yii3 inteira estiver +pronta. Para cada novo fluxo de requisição, adicione: + +- testes unitários para serviços e validadores; +- testes funcionais para actions e middlewares; +- testes end-to-end para os fluxos críticos no navegador; +- análise estática para verificações de tipo mais rigorosas. + +O código Yii3 é mais explícito, então os testes devem verificar os serviços +diretamente, em vez de montar grandes arrays de componentes da aplicação. + +Veja [Visão geral dos testes](../testing/overview.md), [Testes +unitários](../testing/unit.md), [Testes +funcionais](../testing/functional.md) e [Testes +end-to-end](../testing/end-to-end.md). + +## Refatorando o código Yii 2.0 antes de reutilizá-lo + +Estas mudanças são úteis mesmo que a aplicação antiga continue no Yii 2.0 +por um tempo: + +- Substitua o acesso a `Yii::$app` no código de domínio por argumentos do + construtor. +- Tire as consultas dos controllers e views e leve-as para repositórios ou + serviços de consulta. +- Tire os fluxos de negócio das classes Active Record. +- Separe os form models dos models de persistência. +- Adicione tipos de retorno e tipos de parâmetros. +- Substitua arrays de rotas espalhados pelas views por constantes de rotas + nomeadas ou métodos helper. +- Adicione testes em torno de cada fluxo antes de reconstruí-lo no Yii3. + +Quanto menos estado do framework o seu código Yii 2.0 pressupor, mais fácil +fica entender o que deve ser reutilizado e o que deve ser redesenhado para o +Yii3. diff --git a/src/pt-BR/guide/intro/what-is-yii.md b/src/pt-BR/guide/intro/what-is-yii.md new file mode 100644 index 00000000..1cd24513 --- /dev/null +++ b/src/pt-BR/guide/intro/what-is-yii.md @@ -0,0 +1,72 @@ +# O que é o Yii + +O Yii é um framework PHP de alto desempenho, baseado em pacotes, para +desenvolver aplicações modernas. O nome Yii (pronuncia-se `Yee` ou `[ji:]`) +significa "simples e evolutivo" em chinês. Você também pode pensar nele +como um acrônimo de **Yes It Is**! + +## Para que o Yii é mais indicado + +O Yii é um framework genérico de programação web. Você pode usá-lo para +desenvolver todo tipo de aplicação web com PHP. Por causa da sua +arquitetura e do suporte sofisticado a cache, ele é especialmente indicado +para aplicações de grande porte, como portais, sistemas de gerenciamento de +conteúdo, e-commerce, APIs REST etc. + +## Como o Yii se compara a outros frameworks? + +Se você já conhece outro framework, talvez queira saber como o Yii se +compara a ele: + +- O Yii segue a [filosofia de ser prático e + útil](../../internals/001-yii-values.md), buscando: + - Desempenho tanto no desenvolvimento quanto na execução. + - Padrões convenientes e personalizáveis. + - Foco na prática. + - Simplicidade. + - Clareza. + - Consistência. + + O Yii nunca tenta complicar o design só para seguir algum padrão de projeto. +- O Yii usa amplamente as interfaces PSR, o que permite reaproveitar o que a comunidade PHP criou e até + substituir implementações do core quando necessário. +- O Yii é ao mesmo tempo um conjunto de bibliotecas e um framework full-stack com muitos recursos testados e prontos para uso: + cache, logs, template engine, abstração de dados, ferramentas de desenvolvimento, geração de código e mais. +- O Yii é extensível. Você pode personalizar ou substituir qualquer parte do código do core. Também pode + aproveitar a arquitetura sólida do Yii para usar ou desenvolver pacotes redistribuíveis. +- Alto desempenho é sempre um objetivo principal do Yii. + +O Yii conta com um [time principal de desenvolvedores +sólido](https://www.yiiframework.com/team/), apoiado financeiramente pela +[fundação no OpenCollective](https://opencollective.com/yiisoft), e com uma +grande comunidade de profissionais que contribuem constantemente para o +desenvolvimento do Yii. O time do Yii acompanha de perto as tendências mais +recentes do desenvolvimento web e as boas práticas e recursos de outros +frameworks e projetos. As boas práticas e os recursos mais relevantes +encontrados em outros lugares são incorporados ao core do framework e +expostos por meio de interfaces simples e elegantes. + + +## Versões do Yii + +Atualmente o Yii tem três versões principais disponíveis: 1.1, 2.0 e 3.0. + +- A versão 1.1 é a geração antiga e está congelada, recebendo apenas + correções de bugs. +- A versão 2.0 é a versão estável atual e está congelada, recebendo apenas + correções de bugs. +- A versão 3.0 é a versão atual em desenvolvimento. Este guia trata + principalmente da versão 3. + + +## Requisitos e pré-requisitos + +O Yii3 exige PHP 8.2 ou superior, mas alguns pacotes funcionam com versões +mais antigas, como o PHP 7.4. + +Usar o Yii exige conhecimento básico de programação orientada a objetos +(POO), já que o Yii é um framework totalmente orientado a objetos. O Yii3 +também usa recursos recentes do PHP, como declarações de tipo e +generators. Entender esses conceitos vai ajudar você a aprender o Yii3 mais +rápido. + diff --git a/src/pt-BR/guide/rest/quick-start.md b/src/pt-BR/guide/rest/quick-start.md new file mode 100644 index 00000000..e6818b23 --- /dev/null +++ b/src/pt-BR/guide/rest/quick-start.md @@ -0,0 +1,362 @@ +# Início rápido + +O Yii trabalha com APIs JSON usando os mesmos objetos de requisição e +resposta PSR-7 das páginas web. Para endpoints de API, o fluxo comum é: + +* Ler o corpo da requisição quando o cliente envia JSON. +* Mapear os dados da requisição para um objeto de entrada tipado. +* Validar o objeto de entrada. +* Retornar uma resposta cujos dados são formatados como JSON. + +Este guia assume que você usa o [template de aplicação +API](https://github.com/yiisoft/app-api). Ele já inclui a leitura do corpo +da requisição, a resolução da entrada da requisição, respostas de dados em +JSON e exemplos de presenters. Para aplicações completas com outras +estruturas, veja [Aplicações demo](../start/demo-apps.md). + +## Criando a entrada da requisição + +Use o [yiisoft/input-http](https://github.com/yiisoft/input-http) para +descrever os dados da requisição como um objeto de entrada tipado. Adicione +`#[FromBody]` quando todos os valores devem vir do corpo da requisição já +interpretado. + +Crie `src/Api/Post/CreatePostInput.php`: + +```php +getValidationResult(); + + if (!$result->isValid()) { + return $responseFactory->failValidation($result); + } + + return $responseFactory + ->success([ + 'title' => $input->title, + 'content' => $input->content, + ]) + ->withStatus(Status::CREATED); + } +} +``` + +Você pode validar a entrada na action como mostrado acima. Outra opção é +configurar o `RequestInputParametersResolver` para lançar +`Yiisoft\Input\Http\InputValidationException` e converter essa exceção em +uma resposta JSON em um único tratador de erros. O template de aplicação +API usa essa abordagem centralizada. + +## Retornando respostas JSON + +Para endpoints pequenos, você pode escrever o JSON em uma resposta PSR-7 +manualmente, como mostrado em [Respondendo com +JSON](../runtime/response.md#respondendo-com-json). Para APIs, prefira o +[yiisoft/data-response](https://github.com/yiisoft/data-response), que +formata os dados da resposta e define o header `Content-Type`. + +O template de aplicação API mantém a formatação das respostas em +`src/Api/Shared/ResponseFactory.php`: + +```php +dataResponseFactory->createResponse([ + 'status' => 'success', + 'data' => $presenter->present($data), + ]); + } + + public function failValidation(Result $result): ResponseInterface + { + return $this->dataResponseFactory + ->createResponse([ + 'status' => 'failed', + 'error_message' => 'Validation failed.', + 'error_data' => (new ValidationResultPresenter())->present($result), + ]) + ->withStatus(Status::UNPROCESSABLE_ENTITY); + } +} +``` + +Presenters são abstrações da camada de aplicação que transformam objetos da +aplicação em arrays de saída da API. Mantenha-os separados das entidades de +domínio, para que mudar uma resposta da API não force mudanças nos objetos +de negócio. + +Crie `src/Api/Post/PostPresenter.php`: + +```php + + */ +final readonly class PostPresenter implements PresenterInterface +{ + public function present(mixed $value): array + { + return [ + 'id' => $value->id, + 'title' => $value->title, + 'content' => $value->content, + ]; + } +} +``` + +O template de API contém uma implementação mais completa da [response +factory](https://github.com/yiisoft/app-api/blob/master/src/Api/Shared/ResponseFactory.php) +e dos +[presenters](https://github.com/yiisoft/app-api/tree/master/src/Api/Shared/Presenter). + +## Roteando um endpoint + +Registre as rotas da API em `config/common/routes.php`: + +```php +use App\Api\Post\CreatePostAction; +use Yiisoft\Http\Method; +use Yiisoft\Router\Route; + +return [ + Route::methods([Method::POST], '/posts') + ->action(CreatePostAction::class) + ->name('api/posts/create'), +]; +``` + +Envie JSON definindo `Content-Type: application/json`. Peça respostas JSON +com `Accept: application/json`. + +```shell +curl -X POST http://localhost:8080/posts \ + -H 'Content-Type: application/json' \ + -H 'Accept: application/json' \ + -d '{"title":"First post","content":"Text"}' +``` + +Erros de validação são retornados como JSON com status HTTP `422 +Unprocessable Entity`. Uma criação bem-sucedida normalmente retorna `201 +Created`. + +## Aplicações existentes + +Se você for adicionar endpoints de API JSON a uma aplicação web existente, +primeiro instale os pacotes de API: + +```shell +composer require yiisoft/input-http yiisoft/request-body-parser yiisoft/data-response +``` + +Se você usa Docker: + +```shell +make composer require yiisoft/input-http yiisoft/request-body-parser yiisoft/data-response +``` + +Em `config/web/di/application.php`, adicione o `RequestBodyParser` antes do +`Router`, para que as requisições JSON sejam lidas antes de as actions +rodarem: + +```php +use Yiisoft\Request\Body\RequestBodyParser; +use Yiisoft\Router\Middleware\Router; + +return [ + RequestBodyParser::class, + Router::class, +]; +``` + +No mesmo arquivo, adicione o middleware de resposta de dados JSON antes do +tratamento de erros e do roteamento: + +```php +use Yiisoft\DataResponse\Formatter\JsonFormatter; +use Yiisoft\DataResponse\Middleware\ContentNegotiatorDataResponseMiddleware; + +return [ + static fn() => new ContentNegotiatorDataResponseMiddleware( + formatters: [ + 'application/json' => new JsonFormatter(), + ], + fallback: new JsonFormatter(), + ), + // tratamento de erros, leitor do corpo da requisição, router e middleware de não encontrado +]; +``` + +Também em `config/web/di/application.php`, configure os resolvedores de +parâmetros das actions: + +```php +use Yiisoft\Definitions\Reference; +use Yiisoft\Input\Http\HydratorAttributeParametersResolver; +use Yiisoft\Input\Http\RequestInputParametersResolver; +use Yiisoft\Middleware\Dispatcher\CompositeParametersResolver; +use Yiisoft\Middleware\Dispatcher\ParametersResolverInterface; + +return [ + ParametersResolverInterface::class => [ + 'class' => CompositeParametersResolver::class, + '__construct()' => [ + Reference::to(HydratorAttributeParametersResolver::class), + Reference::to(RequestInputParametersResolver::class), + ], + ], +]; +``` + +Use a [configuração do template de aplicação +API](https://github.com/yiisoft/app-api/blob/master/config/web/di/application.php) +como referência completa para a ordem dos middlewares e a configuração dos +resolvedores. diff --git a/src/pt-BR/guide/runtime/cookies.md b/src/pt-BR/guide/runtime/cookies.md new file mode 100644 index 00000000..7f76589c --- /dev/null +++ b/src/pt-BR/guide/runtime/cookies.md @@ -0,0 +1,215 @@ +# Cookies + +Os cookies servem para manter dados entre requisições, enviando-os ao +navegador do cliente por headers HTTP. O cliente devolve os dados ao +servidor nos headers da requisição. Por isso, os cookies são práticos para +guardar pequenas quantidades de dados, como tokens ou flags. + +## Lendo cookies + +Você pode obter os valores dos cookies a partir da requisição do servidor, +que está disponível como argumento do handler da rota (por exemplo, uma +action de controller): + +```php +private function actionProfile(\Psr\Http\Message\ServerRequestInterface $request) +{ + $cookieValues = $request->getCookieParams(); + $cookieValue = $cookieValues['cookieName'] ?? null; + // ... +} +``` + +Além de obter os valores dos cookies direto da requisição do servidor, você +também pode usar o pacote +[yiisoft/request-provider](https://github.com/yiisoft/request-provider), que +oferece uma forma mais estruturada de lidar com cookies por meio do +`\Yiisoft\RequestProvider\RequestCookieProvider`. Essa abordagem pode +simplificar o código e melhorar a legibilidade. + +Veja um exemplo de como trabalhar com cookies usando o +`\Yiisoft\RequestProvider\RequestCookieProvider`: + +```php +final readonly class MyService +{ + public function __construct( + private \Yiisoft\RequestProvider\RequestCookieProvider $cookies + ) {} + + public function go(): void + { + // Check if a specific cookie exists + if ($this->cookies->has('foo')) { + // Retrieve the value of the cookie + $fooValue = $this->cookies->get('foo'); + // Do something with the cookie value + } + + // Retrieve another cookie value + $barValue = $this->cookies->get('bar'); + // Do something with the bar cookie value + } +} + +## Sending cookies + +Since sending cookies is, in fact, sending a header but since forming the header isn't trivial, there is +`\Yiisoft\Cookies\Cookie` class to help with it: + +```php +$cookie = (new \Yiisoft\Cookies\Cookie('cookieName', 'value')) + ->withPath('/') + ->withDomain('yiiframework.com') + ->withHttpOnly(true) + ->withSecure(true) + ->withSameSite(\Yiisoft\Cookies\Cookie::SAME_SITE_STRICT) + ->withMaxAge(new \DateInterval('P7D')); + +return $cookie->addToResponse($response); +``` + +Depois de montar o cookie, chame `addToResponse()` passando uma instância de +`\Psr\Http\Message\ResponseInterface` para adicionar os headers HTTP +correspondentes a ela. + +## Assinando e criptografando cookies + +Para evitar que o valor do cookie seja substituído, o pacote oferece duas +implementações: + +`Yiisoft\Cookies\CookieSigner` - assina cada cookie com um prefixo de hash +único baseado no valor do cookie e em uma chave secreta. +`Yiisoft\Cookies\CookieEncryptor` - criptografa cada cookie com uma chave +secreta. + +A criptografia é mais segura que a assinatura, mas tem desempenho menor. + +```php +$cookie = new \Yiisoft\Cookies\Cookie('identity', 'identityValue'); + +// The secret key used to sign and validate cookies. +$key = '0my1xVkjCJnD_q1yr6lUxcAdpDlTMwiU'; + +$signer = new \Yiisoft\Cookies\CookieSigner($key); +$encryptor = new \Yiisoft\Cookies\CookieEncryptor($key); + +$signedCookie = $signer->sign($cookie); +$encryptedCookie = $encryptor->encrypt($cookie); +``` + +Para validar e obter de volta o valor puro, use os métodos `validate()` e +`decrypt()`. + +```php +$cookie = $signer->validate($signedCookie); +$cookie = $encryptor->decrypt($encryptedCookie); +``` + +Se o valor do cookie tiver sido adulterado ou não tiver sido +assinado/criptografado antes, uma `\RuntimeException` será lançada. Por +isso, se você não tem certeza de que o valor do cookie foi +assinado/criptografado antes, use primeiro os métodos `isSigned()` e +`isEncrypted()`, respectivamente. + +```php +if ($signer->isSigned($cookie)) { + $cookie = $signer->validate($cookie); +} + +if ($encryptor->isEncrypted($cookie)) { + $cookie = $encryptor->decrypt($cookie); +} +``` + +Faz sentido assinar ou criptografar o valor de um cookie quando você guarda +dados importantes que o usuário não deve alterar. + +### Automatizando a criptografia e a assinatura + +Para automatizar a criptografia/assinatura e a descriptografia/validação dos +valores dos cookies, use uma instância de +`Yiisoft\Cookies\CookieMiddleware`, que é um middleware +[PSR-15](https://www.php-fig.org/psr/psr-15/). + +Esse middleware oferece os seguintes recursos: + +- Valida e descriptografa os valores dos cookies vindos da requisição. +- Remove o cookie da requisição se ele tiver sido adulterado e registra essa + informação no log. +- Criptografa/assina os valores dos cookies e substitui os valores puros nos + headers `Set-Cookie` da resposta. + +Para o middleware saber quais valores de quais cookies precisam ser +criptografados/assinados, é preciso passar um array de configurações para o +construtor dele. As chaves do array são padrões de nomes de cookies e os +valores são as constantes `CookieMiddleware::ENCRYPT` ou +`CookieMiddleware::SIGN`. + +```php +use Yiisoft\Cookies\CookieMiddleware; + +$cookiesSettings = [ + // Exact match with the name `identity`. + 'identity' => CookieMiddleware::ENCRYPT, + // Matches any number from 1 to 9 after the underscore. + 'name_[1-9]' => CookieMiddleware::SIGN, + // Matches any string after the prefix, including an + // empty string, except for the delimiters "/" and "\". + 'prefix*' => CookieMiddleware::SIGN, +]; +``` + +Para mais informações sobre o uso de padrões com curinga, veja o pacote +[yiisoft/strings](https://github.com/yiisoft/strings#wildcardpattern-usage). + +Criando e usando o middleware: + +```php +/** + * @var \Psr\Http\Message\ServerRequestInterface $request + * @var \Psr\Http\Server\RequestHandlerInterface $handler + * @var \Psr\Log\LoggerInterface $logger + */ + +// The secret key used to sign and validate cookies. +$key = '0my1xVkjCJnD_q1yr6lUxcAdpDlTMwiU'; +$signer = new \Yiisoft\Cookies\CookieSigner($key); +$encryptor = new \Yiisoft\Cookies\CookieEncryptor($key); + +$cookiesSettings = [ + 'identity' => \Yiisoft\Cookies\CookieMiddleware::ENCRYPT, + 'session' => \Yiisoft\Cookies\CookieMiddleware::SIGN, +]; + +$middleware = new \Yiisoft\Cookies\CookieMiddleware( + $logger + $encryptor, + $signer, + $cookiesSettings, +); + +// The cookie parameter values from the request are decrypted/validated. +// The cookie values are encrypted/signed and appended to the response. +$response = $middleware->process($request, $handler); +``` + +Se o array `$cookiesSettings` estiver vazio, nenhum cookie será +criptografado ou assinado. + +## Segurança dos cookies + +Você deve configurar cada cookie para ser seguro. As configurações de +segurança importantes são: + +- `httpOnly`. Definir como `true` impede que o JavaScript acesse o valor do + cookie. +- `secure`. Definir como `true` impede o envio do cookie via `HTTP`. Ele só + será enviado via `HTTPS`. +- `sameSite`, se definido como `SAME_SITE_LAX` ou `SAME_SITE_STRICT`, impede + o envio do cookie em contexto de navegação entre sites. `SAME_SITE_LAX` + impede o envio do cookie em métodos de requisição sujeitos a CSRF (por + exemplo, POST, PUT, PATCH etc.). `SAME_SITE_STRICT` impede o envio dos + cookies em todos os métodos. +- Assine ou criptografe o valor do cookie para evitar falsificação quando os + dados não puderem ser adulterados. diff --git a/src/pt-BR/guide/runtime/handling-errors.md b/src/pt-BR/guide/runtime/handling-errors.md new file mode 100644 index 00000000..c178a5d7 --- /dev/null +++ b/src/pt-BR/guide/runtime/handling-errors.md @@ -0,0 +1,322 @@ +# Tratamento de erros + +O Yii tem o pacote +[yiisoft/error-handler](https://github.com/yiisoft/error-handler), que torna +o tratamento de erros muito mais agradável do que antes. Em particular, o +error handler do Yii oferece: + +- Middleware [PSR-15](https://www.php-fig.org/psr/psr-15/) para capturar + erros não tratados. +- Middleware PSR-15 para mapear certas exceções para respostas + personalizadas. +- Modos de produção e de debug. +- O modo debug mostra detalhes e o stacktrace, tem temas claro e escuro e + botões práticos para pesquisar o erro sem digitar. +- Leva em conta as configurações do PHP. +- Trata erros de falta de memória, erros fatais, warnings, notices e + exceções. +- Pode usar qualquer logger compatível com a + [PSR-3](https://www.php-fig.org/psr/psr-3/) para registrar os erros. +- Detecta o formato da resposta com base no mime type da requisição. +- Suporta respostas em HTML, texto puro, JSON, XML e headers sem + configuração extra. +- Você pode implementar a sua própria renderização de erros para outros + tipos. + +Este guia descreve como usar o error handler no [framework +Yii](https://www.yiiframework.com/). Para usá-lo separado do Yii, veja a +[descrição do pacote](https://github.com/yiisoft/error-handler). + +## Usando o error handler + +O error handler tem duas partes. Uma é o middleware +`Yiisoft\ErrorHandler\Middleware\ErrorCatcher`, que, quando registrado, +captura as exceções que podem surgir durante a execução da pilha de +middlewares e as passa para o handler. A outra é o próprio error handler, +`Yiisoft\ErrorHandler\ErrorHandler`, que captura as exceções que ocorrem +fora da pilha de middlewares e os erros fatais. O handler também converte +warnings e notices em exceções e faz outras coisas úteis. + +O error handler é registrado na própria aplicação. Normalmente isso acontece +no `ApplicationRunner`. Por padrão, a configuração do handler vem do +container. Você pode configurá-lo na configuração da aplicação, +`config/web.php`, assim: + +```php +use Psr\Log\LoggerInterface; +use Yiisoft\ErrorHandler\ErrorHandler; +use Yiisoft\ErrorHandler\Renderer\HtmlRenderer; +use Yiisoft\ErrorHandler\ThrowableRendererInterface; + +return [ + // ... + ErrorHandler::class => static function (LoggerInterface $logger, ThrowableRendererInterface $renderer) { + $errorHandler = new ErrorHandler($logger, $renderer); + // Set the size of the reserved memory to 512 KB. Defaults to 256KB. + $errorHandler->memoryReserveSize(524_288); + return $errorHandler; + }, + + ThrowableRendererInterface::class => static fn () => new HtmlRenderer([ + // Defaults to the package file "templates/production.php". + 'template' => '/full/path/to/production/template/file', + // Defaults to package file "templates/development.php". + 'verboseTemplate' => '/full/path/to/development/template/file', + // Maximum number of source code lines to be displayed. Defaults to 19. + 'maxSourceLines' => 20, + // Maximum number of trace source code lines to be displayed. Defaults to 13. + 'maxTraceLines' => 5, + // Trace the header line with placeholders (file, line, icon) to be substituted. Defaults to `null`. + 'traceHeaderLine' => '{icon}', + ]), + // ... +]; +``` + +Como dito acima, o error handler transforma todos os erros não fatais do PHP +em exceções que podem ser capturadas +(`Yiisoft\ErrorHandler\Exception\ErrorException`). Isso significa que você +pode usar o código a seguir para lidar com erros do PHP: + +```php +try { + 10 / 0; +} catch (\Yiisoft\ErrorHandler\Exception\ErrorException $e) { + // Write a log or something else. +} +// execution continues... +``` + +O pacote tem outro middleware, +`Yiisoft\ErrorHandler\Middleware\ExceptionResponder`. Esse middleware +mapeia certas exceções para respostas personalizadas. Configure-o na +configuração da aplicação assim: + +```php +use Psr\Http\Message\ResponseFactoryInterface; +use Yiisoft\ErrorHandler\Middleware\ExceptionResponder; +use Yiisoft\Injector\Injector; + +return [ + // ... + ExceptionResponder::class => static function (ResponseFactoryInterface $responseFactory, Injector $injector) { + $exceptionMap = [ + // Status code with which the factory creates the response. + MyNotFoundException::class => 404, + // PHP callable that must return a `Psr\Http\Message\ResponseInterface`. + MyHttpException::class => static fn (MyHttpException $exception) => new MyResponse($exception), + // ... + ]; + + return new ExceptionResponder($exceptionMap, $responseFactory, $injector); + }, +]; +``` + +Ao configurar a pilha de middlewares da aplicação, você deve colocar +`Yiisoft\ErrorHandler\Middleware\ExceptionResponder` antes de +`Yiisoft\ErrorHandler\Middleware\ErrorCatcher`. + +## Renderizando os dados do erro + +Cada renderer converte os dados do erro para um formato específico. Os +seguintes renderers já vêm prontos: + +- `Yiisoft\ErrorHandler\Renderer\HeaderRenderer` - Renderiza o erro em + headers HTTP. É usado em requisições `HEAD`. +- `Yiisoft\ErrorHandler\Renderer\HtmlRenderer` - Renderiza o erro em HTML. +- `Yiisoft\ErrorHandler\Renderer\JsonRenderer` - Renderiza o erro em JSON. +- `Yiisoft\ErrorHandler\Renderer\PlainTextRenderer` - Renderiza o erro em + texto puro. +- `Yiisoft\ErrorHandler\Renderer\XmlRenderer` - Renderiza o erro em XML. + +O renderer gera dados de erro mais ou menos detalhados conforme o modo debug +esteja ativado ou não. + +Exemplo de renderização em headers com o modo debug desativado: + +``` +... +X-Error-Message: An internal server error occurred. +... +``` + +Exemplo de renderização em headers com o modo debug ativado: + +``` +... +X-Error-Type: Error +X-Error-Message: Call to undefined function App\Controller\myFunc() +X-Error-Code: 0 +X-Error-File: /var/www/yii/app/src/Controller/SiteController.php +X-Error-Line: 21 +... +``` + +Exemplo de saída JSON com o modo debug desativado: + +```json +{"message":"An internal server error occurred."} +``` + +Exemplo de saída JSON com o modo debug ativado: + +```json +{ + "type": "Error", + "message": "Call to undefined function App\\Controller\\myFunc()", + "code": 0, + "file": "/var/www/yii/app/src/Controller/SiteController.php", + "line": 21, + "trace": [ + { + "function": "index", + "class": "App\\Controller\\SiteController", + "type": "->" + }, + { + "file": "/var/www/yii/app/vendor/yiisoft/injector/src/Injector.php", + "line": 63, + "function": "invokeArgs", + "class": "ReflectionFunction", + "type": "->" + }, + ... + ] +} +``` + +Exemplo de renderização HTML com o modo debug desativado: + +![Tela de produção](/images/guide/runtime/view-production.png) + +Exemplo de renderização HTML com o modo debug ativado e tema claro: + +![Tela de desenvolvimento com tema +claro](/images/guide/runtime/view-development-light.png) + +Exemplo de renderização HTML com o modo debug ativado e tema escuro: + +![Tela de desenvolvimento com tema +escuro](/images/guide/runtime/view-development-dark.png) + +O error catcher escolhe como renderizar uma exceção com base no header HTTP +`accept`. Se ele for `text/html` ou um tipo de conteúdo desconhecido, usa o +template HTML de erro ou de exceção para exibir os erros. Para outros mime +types, o error handler escolhe entre os renderers registrados em um renderer +provider. Por padrão, ele suporta JSON, XML e texto puro. + +### Implementando o seu próprio renderer + +Você pode personalizar o formato da resposta de erro implementando +`Yiisoft\ErrorHandler\ThrowableRendererInterface`. O renderer converte um +throwable em `Yiisoft\ErrorHandler\ErrorData`, que contém o corpo e os +headers da resposta. + +```php +use Psr\Http\Message\ServerRequestInterface; +use Throwable; +use Yiisoft\ErrorHandler\ErrorData; +use Yiisoft\ErrorHandler\ThrowableRendererInterface; +use Yiisoft\Http\Header; + +final readonly class MyRenderer implements ThrowableRendererInterface +{ + public function render(Throwable $t, ?ServerRequestInterface $request = null): ErrorData + { + return new ErrorData( + '{"message":"An internal server error occurred."}', + [Header::CONTENT_TYPE => 'application/problem+json'], + ); + } + + public function renderVerbose(Throwable $t, ?ServerRequestInterface $request = null): ErrorData + { + return new ErrorData( + json_encode( + [ + 'type' => $t::class, + 'message' => $t->getMessage(), + 'file' => $t->getFile(), + 'line' => $t->getLine(), + ], + JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES, + ), + [Header::CONTENT_TYPE => 'application/problem+json'], + ); + } +} +``` + +Registre o renderer em `config/common/di/error-handler.php`: + +```php +use Psr\Container\ContainerInterface; +use App\Error\MyRenderer; +use Yiisoft\Definitions\DynamicReference; +use Yiisoft\ErrorHandler\Renderer\HtmlRenderer; +use Yiisoft\ErrorHandler\Renderer\JsonRenderer; +use Yiisoft\ErrorHandler\Renderer\PlainTextRenderer; +use Yiisoft\ErrorHandler\Renderer\XmlRenderer; +use Yiisoft\ErrorHandler\RendererProvider\CompositeRendererProvider; +use Yiisoft\ErrorHandler\RendererProvider\ContentTypeRendererProvider; +use Yiisoft\ErrorHandler\RendererProvider\HeadRendererProvider; +use Yiisoft\ErrorHandler\ThrowableResponseFactory; +use Yiisoft\ErrorHandler\ThrowableResponseFactoryInterface; + +return [ + ThrowableResponseFactoryInterface::class => [ + 'class' => ThrowableResponseFactory::class, + '__construct()' => [ + 'rendererProvider' => DynamicReference::to( + static fn (ContainerInterface $container) => new CompositeRendererProvider( + new HeadRendererProvider(), + new ContentTypeRendererProvider($container, [ + 'application/problem+json' => MyRenderer::class, + 'application/json' => JsonRenderer::class, + 'application/xml' => XmlRenderer::class, + 'text/xml' => XmlRenderer::class, + 'text/plain' => PlainTextRenderer::class, + 'text/html' => HtmlRenderer::class, + '*/*' => HtmlRenderer::class, + ]), + ), + ), + ], + ], +]; +``` + +O array `renderers` mapeia os tipos de conteúdo do header `Accept` para +nomes de classes de renderer. Quando você informa esse array, ele substitui +o mapa padrão, então inclua as classes de renderer padrão que ainda +precisar. + +## Exceções amigáveis + +O renderer de erros do Yii suporta [exceções +amigáveis](https://github.com/yiisoft/friendly-exception), que deixam o +tratamento de erros ainda mais agradável para o seu time. A ideia é oferecer +um nome legível e possíveis soluções para o problema: + +```php +use Yiisoft\FriendlyException\FriendlyExceptionInterface; + +final readonly class RequestTimeoutException extends \RuntimeException implements FriendlyExceptionInterface +{ + public function getName(): string + { + return 'Request timed out'; + } + + public function getSolution(): ?string + { + return <<<'SOLUTION' +Likely it is a result of resource request is not responding in a timely fashion. Try increasing timeout. +SOLUTION; + } +} +``` + +Quando a aplicação lança uma exceção desse tipo, o renderer de erros mostra +o nome e a solução se o modo debug estiver ativado. diff --git a/src/pt-BR/guide/runtime/logging.md b/src/pt-BR/guide/runtime/logging.md new file mode 100644 index 00000000..81e15cce --- /dev/null +++ b/src/pt-BR/guide/runtime/logging.md @@ -0,0 +1,505 @@ +# Logs + +O Yii usa as [interfaces PSR-3](https://www.php-fig.org/psr/psr-3/) para +logs, então você pode configurar qualquer biblioteca de log compatível com a +PSR-3 para fazer o trabalho. + +O Yii oferece o seu próprio logger, que é bem personalizável e extensível. +Com ele, você pode registrar vários tipos de mensagens, filtrá-las e +reuni-las em destinos diferentes, como arquivos ou e-mails. + +Usar o sistema de logs do Yii envolve os seguintes passos: + +* Registrar [mensagens de log](#mensagens-de-log) em vários pontos do + código; +* Configurar [destinos de log](#destinos-de-log) na configuração da + aplicação para filtrar e exportar as mensagens; +* Examinar as mensagens filtradas exportadas pelos diferentes destinos (por + exemplo, o debugger do Yii). + +Esta seção foca nos dois primeiros passos. + +## Destino padrão dos logs + +Os templates de aplicação do Yii3 +([web](https://github.com/yiisoft/app/blob/master/config/common/di/logger.php) +e +[API](https://github.com/yiisoft/app-api/blob/master/config/common/di/logger.php)) +configuram o `Yiisoft\Log\StreamTarget`, que por padrão escreve na saída +padrão (`stdout`, ou `php://stdout`). Eles não criam arquivos de log da +aplicação, como `runtime/logs/app.log`. O `StreamTarget` também suporta a +saída de erro padrão (`stderr`, ou `php://stderr`), mas você precisa +configurá-la explicitamente. + +Isso funciona bem com o Docker, que [coleta a saída dos containers](https://docs.docker.com/engine/logging/). +Use `docker logs ` para lê-la quando o driver de log do container suportar esse comando. + +Sem containers, o destino depende de como você inicia o PHP e captura a +saída dele. Por exemplo, o PHP-FPM descarta a saída dos workers por padrão, +a menos que você ative `catch_workers_output`. Veja a [configuração de logs +do servidor +web](../../cookbook/configuring-webservers/general.md#logs-da-aplicacao). +Para o Yii escrever arquivos de log da aplicação diretamente, configure um +[destino em arquivo](#logs-em-arquivos). + +## Mensagens de log + +Para registrar mensagens de log, você precisa de uma instância de um logger +PSR-3. Uma classe que escreve mensagens de log deve recebê-lo como +dependência: + +```php +class MyService +{ + private $logger; + + public function __construct(\Psr\Log\LoggerInterface $logger) + { + $this->logger = $logger; + } +} +``` + +Registrar uma mensagem de log é tão simples quanto chamar um dos métodos a +seguir, que correspondem aos níveis de log: + +- `emergency` - O sistema está inutilizável. +- `alert` - É preciso agir imediatamente. Exemplo: site inteiro fora do ar, + banco de dados indisponível etc. Isso deve disparar os alertas por SMS e + acordar você. +- `critical` - Condições críticas. Exemplo: componente da aplicação + indisponível, exceção inesperada. +- `error` - Erros em tempo de execução que não exigem ação imediata, mas + normalmente devem ser registrados e monitorados. +- `warning` - Ocorrências excepcionais que não são erros. Exemplo: uso de + APIs obsoletas, uso inadequado de uma API, coisas indesejáveis que não + estão necessariamente erradas. +- `notice` - Eventos normais, mas significativos. +- `info` - Eventos interessantes. Exemplo: login de usuário, logs de SQL. +- `debug` - Informações detalhadas de debug. + +Cada método tem dois argumentos. O primeiro é a mensagem. O segundo é um +array de contexto, que normalmente tem dados estruturados que não cabem bem +na mensagem, mas trazem informações importantes. Se você passar uma exceção +no contexto, use a chave "exception". Outra chave especial é "category". As +categorias ajudam a organizar e filtrar melhor as mensagens de log. + +```php +use \Psr\Log\LoggerInterface; + +final readonly class MyService +{ + public function __construct( + private LoggerInterface $logger + ) + { + } + + public function serve(): void + { + $this->logger->info('MyService is serving', ['context' => __METHOD__]); + } +} +``` + +Ao escolher a categoria de uma mensagem, você pode adotar um esquema de +nomes hierárquico, o que facilita para os [destinos de +log](#destinos-de-log) filtrarem as mensagens pela categoria. Um esquema +simples e eficaz é usar a constante mágica do PHP `__METHOD__` como nome da +categoria. Essa também é a abordagem usada no código do core do Yii. + +A constante `__METHOD__` resulta no nome do método (prefixado com o nome +completo da classe) onde ela aparece. Por exemplo, ela é igual à string +`'App\\Service\\MyService::serve'` se a linha de código acima for chamada +dentro desse método. + +> [!IMPORTANT] +> Os métodos de log descritos acima são, na verdade, atalhos para [[\Psr\Log\LoggerInterface::log()]]. + +O pacote PSR-3 tem a classe `\Psr\Log\NullLogger`, que oferece o mesmo +conjunto de métodos, mas não registra nada. Isso significa que você não +precisa verificar se o logger está configurado com `if ($logger !== null)` e +pode assumir que o logger sempre existe. + + +## Destinos de log + +Um destino de log é uma instância de uma classe que estende +[[\Yiisoft\Log\Target]]. Ele filtra as mensagens de log pelo nível de +severidade e pela categoria e depois as exporta para algum meio. Por +exemplo, um [[\Yiisoft\Log\Target\File\FileTarget|destino em arquivo]] +exporta as mensagens filtradas para um arquivo, enquanto um +[[Yiisoft\Log\Target\Email\EmailTarget|destino por e-mail]] exporta as +mensagens para os endereços de e-mail definidos. + +Você pode registrar vários destinos de log em uma aplicação configurando-os +no construtor de `\Yiisoft\Log\Logger`: + +```php +use \Psr\Log\LogLevel; + +$fileTarget = new \Yiisoft\Log\Target\File\FileTarget('/path/to/app.log'); +$fileTarget->setLevels([LogLevel::ERROR, LogLevel::WARNING]); + +$emailTarget = new \Yiisoft\Log\Target\Email\EmailTarget($mailer, ['to' => 'log@example.com']); +$emailTarget->setLevels([LogLevel::EMERGENCY, LogLevel::ALERT, LogLevel::CRITICAL]); +$emailTarget->setCategories(['Yiisoft\Cache\*']); + +$logger = new \Yiisoft\Log\Logger([ + $fileTarget, + $emailTarget +]); +``` + +No código acima, dois destinos de log são registrados: + +* o primeiro seleciona as mensagens de erro e de warning e as grava no + arquivo `/path/to/app.log`; +* o segundo seleciona as mensagens de emergency, alert e critical das categorias cujos nomes começam com +`Yiisoft\Cache\` e as envia por e-mail para `admin@example.com` e `developer@example.com`. + +O Yii vem com os seguintes destinos de log embutidos. Consulte a +documentação da API dessas classes para saber como configurá-los e usá-los. + +* [[\Yiisoft\Log\PsrTarget]]: repassa as mensagens de log para outro logger + compatível com a PSR-3. +* [[\Yiisoft\Log\StreamTarget]]: escreve as mensagens de log em um stream de + saída definido. +* [[\Yiisoft\Log\Target\Db\DbTarget]]: salva as mensagens de log no banco de + dados. +* [[\Yiisoft\Log\Target\Email\EmailTarget]]: envia as mensagens de log para + endereços de e-mail definidos. +* [[\Yiisoft\Log\Target\File\FileTarget]]: salva as mensagens de log em + arquivos. +* [[\Yiisoft\Log\Target\Syslog\SyslogTarget]]: salva as mensagens de log no + syslog chamando a função PHP `syslog()`. + +### Logs em arquivos + +Para gravar os logs da aplicação em um arquivo, instale o pacote do destino +em arquivo: + +```shell +composer require yiisoft/log-target-file +``` + +No `config/common/di/logger.php` da sua aplicação, troque a referência ao +`StreamTarget` por `FileTarget`: + +```php +use Psr\Log\LoggerInterface; +use Yiisoft\Definitions\ReferencesArray; +use Yiisoft\Log\Logger; +use Yiisoft\Log\Target\File\FileTarget; + +return [ + LoggerInterface::class => [ + 'class' => Logger::class, + '__construct()' => [ + 'targets' => ReferencesArray::from([ + FileTarget::class, + ]), + ], + ], +]; +``` + +A configuração padrão do pacote grava em `@runtime/logs/app.log` e ativa a +rotação de logs. Para mudar o caminho, defina +`$params['yiisoft/log-target-file']['fileTarget']['file']` em +`config/common/params.php`. Garanta que o processo do PHP consiga escrever +no diretório de logs e mantenha esse diretório fora do document root do +servidor web. + +A configuração padrão do pacote de destino em arquivo também descarta as +mensagens `alert`, `critical` e `notice`. O `StreamTarget` dos templates +aceita os oito níveis de log. Para manter esse comportamento, adicione a +seguinte entrada ao array retornado por `config/common/params.php`: + +```php +use Psr\Log\LogLevel; + +return [ + // Other application parameters... + 'yiisoft/log-target-file' => [ + 'fileTarget' => [ + 'levels' => [ + LogLevel::EMERGENCY, + LogLevel::ALERT, + LogLevel::CRITICAL, + LogLevel::ERROR, + LogLevel::WARNING, + LogLevel::NOTICE, + LogLevel::INFO, + LogLevel::DEBUG, + ], + ], + ], +]; +``` + +A seguir, descrevemos os recursos comuns a todos os destinos de log. + +### Filtragem de mensagens + +Para cada destino de log, você pode configurar os níveis e as categorias, +definindo quais níveis de severidade e quais categorias de mensagens o +destino deve processar. + +O método `setLevels()` do destino recebe um array com uma ou mais constantes +de `\Psr\Log\LogLevel`. + +Por padrão, o destino processa mensagens de *qualquer* nível de severidade. + +O método `setCategories()` do destino recebe um array com nomes ou padrões +de categorias de mensagens. O destino só processa as mensagens cuja +categoria esteja no array ou case com um dos padrões dele. Um padrão de +categoria é um prefixo de nome de categoria com um asterisco `*` no +final. Um nome de categoria casa com o padrão se começar com o mesmo +prefixo. Por exemplo, `Yiisoft\Cache\Cache::set` e +`Yiisoft\Cache\Cache::get` casam com o padrão `Yiisoft\Cache\*`. + +Por padrão, o destino processa mensagens de *qualquer* categoria. + +Além de permitir categorias com o método `setCategories()`, você também pode +negar certas categorias com o método `setExcept()`. Se a categoria de uma +mensagem estiver nessa lista ou casar com um dos padrões dela, o destino NÃO +vai processá-la. + +A configuração a seguir define que o destino só deve processar mensagens de +erro e de warning das categorias cujos nomes casem com `Yiisoft\Cache\*` ou +`App\Exceptions\HttpException:*`, mas não com +`App\Exceptions\HttpException:404`. + +```php +$fileTarget = new \Yiisoft\Log\Target\File\FileTarget('/path/to/app.log'); +$fileTarget->setLevels([LogLevel::ERROR, LogLevel::WARNING]); +$fileTarget->setCategories(['Yiisoft\Cache\*', 'App\Exceptions\HttpException:*']); +$fileTarget->setExcept(['App\Exceptions\HttpException:404']); +``` + +### Formatação de mensagens + +Os destinos de log exportam as mensagens filtradas em um certo formato. Por +exemplo, se você instalar um destino de log da classe +[[\Yiisoft\Log\Target\File\FileTarget]], pode encontrar no arquivo de log +uma mensagem parecida com esta: + +``` +2020-12-05 09:27:52.223800 [info][application] Some message + +Message context: + +time: 1607160472.2238 +memory: 4398536 +category: 'application' +``` + +Por padrão, as mensagens de log têm o seguinte formato: + +``` +Timestamp Prefix[Level][Category] Message Context +``` + +Você pode personalizar esse formato chamando o método +[[\Yiisoft\Log\Target::setFormat()|setFormat()]], que recebe um callable PHP +que retorna a mensagem formatada. + +```php +$fileTarget = new \Yiisoft\Log\Target\File\FileTarget('/path/to/app.log'); + +$fileTarget->setFormat(static function (\Yiisoft\Log\Message $message) { + $category = strtoupper($message->context('category')); + return "({$category}) [{$message->level()}] {$message->message()}"; +}); + +$logger = new \Yiisoft\Log\Logger([$fileTarget]); +$logger->info('Text message', ['category' => 'app']); + +// Result: +// (APP) [info] Text message +``` + +Além disso, se o formato padrão da mensagem servir para você, mas for +preciso mudar o formato do timestamp ou adicionar dados à mensagem, você +pode chamar os métodos +[[\Yiisoft\Log\Target::setTimestampFormat()|setTimestampFormat()]] e +[[\Yiisoft\Log\Target::setPrefix()|setPrefix()]]. Por exemplo, o código a +seguir muda o formato do timestamp e configura um destino de log para +prefixar cada mensagem com o ID do usuário atual (o endereço IP e o ID da +sessão foram removidos por questões de privacidade). + +```php +$fileTarget = new \Yiisoft\Log\Target\File\FileTarget('/path/to/app.log'); +$userId = '123e4567-e89b-12d3-a456-426655440000'; + +// Default: 'Y-m-d H: i: s.u' +$fileTarget->setTimestampFormat('D d F Y'); +// Default: '' +$fileTarget->setPrefix(static fn () => "[{$userId}]"); + +$logger = new \Yiisoft\Log\Logger([$fileTarget]); +$logger->info('Text', ['category' => 'user']); + +// Result: +// Fri 04 December 2020 [123e4567-e89b-12d3-a456-426655440000][info][user] Text +// Message context: ... +// Common context: ... +``` + +O callable PHP passado para os métodos +[[\Yiisoft\Log\Target::setFormat()|setFormat()]] e +[[\Yiisoft\Log\Target::setPrefix()|setPrefix()]] tem a seguinte assinatura: + +```php +function (\Yiisoft\Log\Message $message, array $commonContext): string; +``` + +Além dos prefixos, os destinos de log também acrescentam algumas informações de contexto comuns a cada mensagem de log. +Você pode ajustar esse comportamento chamando o método [[\Yiisoft\Log\Target::setCommonContext()|setCommonContext()]] +do destino, passando um array de dados no formato `key => value` com o que você quer incluir. +Por exemplo, a configuração de destino a seguir define que apenas o +valor da variável `$_SERVER` será acrescentado às mensagens de log. + +```php +$fileTarget = new \Yiisoft\Log\Target\File\FileTarget('/path/to/app.log'); +$fileTarget->setCommonContext(['server' => $_SERVER]); +``` + + +### Nível de trace das mensagens + +Durante o desenvolvimento, muitas vezes é útil ver de onde vem cada mensagem +de log. Você pode fazer isso chamando o método +[[\Yiisoft\Log\Logger::setTraceLevel()|setTraceLevel()]] assim: + +```php +$logger = new \Yiisoft\Log\Logger($targets); +$logger->setTraceLevel(3); +``` + +Essa configuração define o nível de trace como 3, então cada mensagem de log +recebe no máximo três níveis da pilha de chamadas do ponto em que a mensagem +foi registrada. Você também pode definir uma lista de caminhos a excluir do +trace chamando o método +[[\Yiisoft\Log\Logger::setExcludedTracePaths()|setExcludedTracePaths()]]. + +```php +$logger = new \Yiisoft\Log\Logger($targets); +$logger->setExcludedTracePaths(['/path/to/file', '/path/to/folder']); +``` + +> [!IMPORTANT] +> Obter informações da pilha de chamadas não é trivial. Por isso, use esse recurso apenas durante o desenvolvimento +ou ao depurar uma aplicação. + + +### Envio (flush) e exportação de mensagens + +Como dito acima, as mensagens de log ficam em um array no +[[\Yiisoft\Log\Logger|objeto logger]]. Para limitar o consumo de memória +desse array, o logger envia as mensagens registradas para os [destinos de +log](#destinos-de-log) sempre que o array acumula um certo número de +mensagens. Você pode personalizar esse número chamando o método +[[\Yiisoft\Log\Logger::setFlushInterval()]]: + + +```php +$logger = new \Yiisoft\Log\Logger($targets); +$logger->setFlushInterval(100); // default is 1000 +``` + +> [!IMPORTANT] +> O envio das mensagens também acontece quando a aplicação termina, +o que garante que os destinos de log recebam as mensagens completas. + +Quando o [[\Yiisoft\Log\Logger|objeto logger]] envia as mensagens para os [destinos de log](#destinos-de-log), +elas não são exportadas imediatamente. A exportação só acontece quando um destino de log + acumula um certo número de mensagens filtradas. Você pode personalizar esse número chamando o método +[[\Yiisoft\Log\Target::setExportInterval()|setExportInterval()]] de cada +[destino de log](#destinos-de-log), assim: + +```php +$fileTarget = new \Yiisoft\Log\Target\File\FileTarget('/path/to/app.log'); +$fileTarget->setExportInterval(100); // default is 1000 +``` + +Por causa dessas configurações de envio e exportação, por padrão, quando +você chama qualquer método de log, NÃO vai ver a mensagem imediatamente nos +destinos de log. Isso pode ser um problema em aplicações de console de longa +duração. Para que cada mensagem apareça imediatamente nos destinos de log, +defina tanto o intervalo de envio quanto o de exportação como 1, como +mostrado abaixo: + +```php +$fileTarget = new \Yiisoft\Log\Target\File\FileTarget('/path/to/app.log'); +$fileTarget->setExportInterval(1); + +$logger = new \Yiisoft\Log\Logger([$fileTarget]); +$logger->setFlushInterval(1); +``` + +> [!NOTE] +> Enviar e exportar mensagens com frequência piora o desempenho da sua aplicação. + + +### Ativando e desativando destinos de log + +Você pode ativar ou desativar um destino de log chamando os métodos +[[\Yiisoft\Log\Target::enable()|enable()] ] e +[[\Yiisoft\Log\Target::disable()|disable()]]. Você pode fazer isso na +configuração do destino de log ou com a seguinte instrução PHP no seu +código: + +```php +$fileTarget = new \Yiisoft\Log\Target\File\FileTarget('/path/to/app.log'); +$logger = new \Yiisoft\Log\Logger([$fileTarget, /*Other targets*/]); + +foreach ($logger->getTargets() as $target) { + if ($target instanceof \Yiisoft\Log\Target\File\FileTarget) { + $target->disable(); + } +} +``` + +Para verificar se o destino de log está ativado, chame o método +`isEnabled()`. Você também pode passar um callable para +[[\Yiisoft\Log\Target::setEnabled()|setEnabled()]] para definir uma condição +dinâmica que diz se o destino de log deve estar ativado ou não. + + +### Criando novos destinos + +Criar uma nova classe de destino de log é simples. Basicamente, você precisa +implementar o método abstrato [[\Yii\Log\Target::export()]], que envia todas +as mensagens de log acumuladas para um meio definido. + +Os seguintes métodos protegidos também ficam disponíveis para os destinos +filhos: + +- `getMessages` - Retorna uma lista de mensagens de log (instâncias de + [[\Yii\Log\Message]]). +- `getFormattedMessages` - Retorna uma lista de mensagens de log formatadas + como strings. +- `formatMessages` - Retorna todas as mensagens de log formatadas como uma + string. +- `getCommonContext` - Retorna um array com os dados de contexto comuns no + formato `key => value`. + +Para mais detalhes, consulte qualquer uma das classes de destino de log +incluídas no pacote. + +> [!TIP] +> Em vez de criar os seus próprios loggers, você pode experimentar qualquer logger compatível com a PSR-3, como +o [Monolog](https://github.com/Seldaek/monolog), usando [[\Yii\Log\PsrTarget]]. + +```php +/** + * @var \Psr\Log\LoggerInterface $psrLogger + */ + +$psrTarget = new \Yiisoft\Log\PsrTarget($psrLogger); +$logger = new \Yiisoft\Log\Logger([$psrTarget]); + +$logger->info('Text message'); +``` diff --git a/src/pt-BR/guide/runtime/request.md b/src/pt-BR/guide/runtime/request.md new file mode 100644 index 00000000..da3eeef7 --- /dev/null +++ b/src/pt-BR/guide/runtime/request.md @@ -0,0 +1,340 @@ +# Requisição + +Uma requisição HTTP tem um método, uma URI, um conjunto de headers e um +corpo: + +``` +POST /contact HTTP/1.1 +Host: example.org +Accept-Language: en-us +Accept-Encoding: gzip, deflate + +{ + "subject": "Hello", + "body": "Hello there, we need to build Yii application together!" +} +``` + +O método é `POST` e a URI é `/contact`. Os headers extras informam o host, +o idioma preferido e a codificação. O corpo pode ser qualquer coisa. Neste +caso, é um payload JSON. + +O Yii usa o [`ServerRequest` da PSR-7](https://www.php-fig.org/psr/psr-7/) +para representar a requisição. O objeto está disponível nas actions de +controllers e em outros tipos de middleware: + +```php +public function view(ServerRequestInterface $request): ResponseInterface +{ + // ... +} +``` + +## Método + +O método pode ser obtido do objeto de requisição: + +```php +$method = $request->getMethod(); +``` + +Normalmente ele é um destes: + +- GET +- POST +- PUT +- DELETE +- HEAD +- PATCH +- OPTIONS + +Se você quiser garantir que o método da requisição é de um tipo específico, +existe uma classe especial com os nomes dos métodos: + +```php +use Yiisoft\Http\Method; + +if ($request->getMethod() === Method::POST) { + // method is POST +} +``` + +## URI + +Uma URI tem: + +- Esquema (`http`, `https`) +- Host (`yiiframework.com`) +- Porta (`80`, `443`) +- Caminho (`/posts/1`) +- Query string (`page=1&sort=+id`) +- Fragmento (`#anchor`) + +Você pode obter a `UriInterface` da requisição assim: + +```php +$uri = $request->getUri(); +``` + +Depois, pode obter vários detalhes pelos métodos dela: + +- `getScheme()` +- `getAuthority()` +- `getUserInfo()` +- `getHost()` +- `getPort()` +- `getPath()` +- `getQuery()` +- `getFragment()` + +## Headers + +Há vários métodos para inspecionar os headers da requisição. Para obter +todos os headers como array: + +```php +$headers = $request->getHeaders(); +foreach ($headers as $name => $values) { + // ... +} +``` + +Para obter um único header: + +```php +$values = $request->getHeader('Accept-Encoding'); +``` + + +Você também pode obter o valor como uma string separada por vírgulas em vez +de um array. Isso é bem prático quando o header tem um único valor: + +```php +if ($request->getHeaderLine('X-Requested-With') === 'XMLHttpRequest') { + // This is an AJAX request made with jQuery. + // Note that header presence and name may vary depending on the library used. +} +``` + +Para verificar se um header está presente na requisição: + +```php +if ($request->hasHeader('Accept-Encoding')) { + // ... +} +``` + +## Corpo + +Há dois métodos para obter o conteúdo do corpo. O primeiro retorna o corpo +como está, sem parsing: + +```php +$body = $request->getBody(); +``` + +`$body` será uma instância de `Psr\Http\Message\StreamInterface`. + +Você também pode obter o corpo já interpretado: + +```php +$bodyParameters = $request->getParsedBody(); +``` + +O parsing depende da implementação da PSR-7 e pode exigir um middleware para +formatos de corpo personalizados. + +```php +getHeaderLine('Content-Type'); + + if (strpos($contentType, 'application/json') !== false) { + $body = $request->getBody(); + $parsedBody = $this->parse($body); + $request = $request->withParsedBody($parsedBody); + + } + + return $next->handle($request); + } +} +``` + +## Upload de arquivos + +Os arquivos enviados pelo usuário em um formulário com o atributo `enctype` +igual a `multipart/form-data` são tratados por um método especial da +requisição: + +```php +$files = $request->getUploadedFiles(); +foreach ($files as $file) { + if ($file->getError() === UPLOAD_ERR_OK) { + $file->moveTo('path/to/uploads/new_filename.ext'); + } +} +``` + +Sempre valide o upload antes de ler o stream ou mover o arquivo. O arquivo +pode estar ausente, ser grande demais para a configuração do PHP, ter sido +enviado só em parte, ter sido rejeitado por uma extensão do PHP ou não +corresponder ao tipo e ao tamanho que a sua aplicação espera. O Yii +Validator oferece a regra `Yiisoft\Validator\Rule\File` para isso. Ela +aceita valores `UploadedFileInterface` da PSR-7 e valida os códigos de erro +do upload, a extensão, o tipo MIME e o tamanho. Use +`Yiisoft\Validator\Rule\Each` quando um campo tiver vários arquivos. + +O exemplo a seguir trata o upload de um único `avatar`. Ele valida o arquivo +enviado com o Yii Validator, guarda o arquivo fora do diretório público e +gera o próprio nome do arquivo em vez de confiar no nome informado pelo +cliente. + +```php + + */ + private const EXTENSIONS = [ + 'image/jpeg' => 'jpg', + 'image/png' => 'png', + 'image/webp' => 'webp', + ]; + + public function __construct( + private Aliases $aliases, + private ResponseFactoryInterface $responseFactory, + ) { + } + + public function __invoke(ServerRequestInterface $request): ResponseInterface + { + $file = $request->getUploadedFiles()['avatar'] ?? null; + + $result = (new Validator())->validate( + ['avatar' => $file], + [ + 'avatar' => [ + new File( + extensions: ['jpg', 'jpeg', 'png', 'webp'], + mimeTypes: array_keys(self::EXTENSIONS), + maxSize: self::MAX_SIZE, + ), + new Image(skipOnError: true), + ], + ], + ); + + if (!$result->isValid() || !$file instanceof UploadedFileInterface) { + $messages = $result->getPropertyErrorMessages('avatar'); + return $this->badRequest( + $messages === [] ? 'Upload a file in the "avatar" field.' : implode(' ', $messages), + ); + } + + $uploadDirectory = $this->aliases->get('@runtime/uploads/avatars'); + $this->ensureDirectory($uploadDirectory); + + $temporaryPath = $uploadDirectory . DIRECTORY_SEPARATOR . bin2hex(random_bytes(16)) . '.upload'; + $file->moveTo($temporaryPath); + + $mediaType = (new finfo(FILEINFO_MIME_TYPE))->file($temporaryPath); + + if (!is_string($mediaType) || !isset(self::EXTENSIONS[$mediaType])) { + unlink($temporaryPath); + return $this->badRequest('Only JPEG, PNG, and WebP images are allowed.'); + } + + $fileName = bin2hex(random_bytes(16)) . '.' . self::EXTENSIONS[$mediaType]; + $targetPath = $uploadDirectory . DIRECTORY_SEPARATOR . $fileName; + + if (!rename($temporaryPath, $targetPath)) { + unlink($temporaryPath); + throw new RuntimeException('Unable to store uploaded file.'); + } + + $response = $this->responseFactory->createResponse(Status::CREATED); + $response->getBody()->write('Stored as ' . $fileName); + + return $response; + } + + private function badRequest(string $message): ResponseInterface + { + $response = $this->responseFactory->createResponse(Status::BAD_REQUEST); + $response->getBody()->write($message); + + return $response; + } + + private function ensureDirectory(string $directory): void + { + if (!is_dir($directory) && !mkdir($directory, 0775, true) && !is_dir($directory)) { + throw new RuntimeException(sprintf('Directory "%s" was not created.', $directory)); + } + } +} +``` + +Observações: + +- Guarde os uploads em `@runtime` ou em outro diretório não público, a menos + que os arquivos sejam públicos de propósito. +- Não use `getClientFilename()` como caminho de armazenamento. Quem controla + esse valor é o navegador, então ele pode ter caracteres inseguros, valores + que parecem caminhos ou nomes duplicados. +- Não confie apenas em `getClientMediaType()`. Esse valor vem do + cliente. Use a validação de tipo MIME da regra `File`, a regra `Image` + para validar imagens e dimensões, ou outro parser no servidor adequado ao + formato do arquivo. +- Verifique limites do PHP como `upload_max_filesize`, `post_max_size` e + `max_file_uploads` quando arquivos esperados forem rejeitados antes de a + action rodar. +- Quando um formulário envia vários arquivos, o array retornado por + `getUploadedFiles()` tem o mesmo formato dos nomes dos inputs de + arquivo. Valide-os com `Each(new File(...))` e mova cada + `UploadedFileInterface` separadamente. +- A regra `File` também valida caminhos de arquivo em string e instâncias de + `SplFileInfo`. Não passe caminhos enviados pelo usuário diretamente: use + os objetos de arquivo enviado da PSR-7 vindos da requisição, ou verifique + a origem do upload antes de validar caminhos do sistema de arquivos. + +## Atributos + +Os middlewares da aplicação podem definir atributos personalizados na +requisição com o método `withAttribute()`. Você pode ler esses atributos +com `getAttribute()`. + +Argumentos de rota, como o `id` de um padrão de rota `/posts/{id}`, não são +atributos da requisição. Use `#[RouteArgument]` em um parâmetro da action +ou injete `Yiisoft\Router\CurrentRoute` quando precisar de argumentos ou +metadados da rota. diff --git a/src/pt-BR/guide/runtime/response.md b/src/pt-BR/guide/runtime/response.md new file mode 100644 index 00000000..01158446 --- /dev/null +++ b/src/pt-BR/guide/runtime/response.md @@ -0,0 +1,137 @@ +# Resposta + +Uma resposta HTTP tem um código e uma mensagem de status, um conjunto de +headers e um corpo: + +``` +HTTP/1.1 200 OK +Date: Mon, 27 Jul 2009 12:28:53 GMT +Server: Apache/2.2.14 (Win32) +Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT +Content-Length: 6 +Content-Type: text/html +Connection: Closed + +Hello! +``` + +O Yii usa o [`Response` da PSR-7](https://www.php-fig.org/psr/psr-7/) na +aplicação web para representar a resposta. + +O objeto deve ser criado e retornado como resultado da execução das actions +de controllers ou de outros middlewares. Normalmente, o middleware recebe +uma response factory injetada no construtor. + +```php +use Psr\Http\Message\ResponseFactoryInterface; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; + +final readonly class PostAction +{ + public function __construct( + private ResponseFactoryInterface $responseFactory + ) + { + } + + public function view(ServerRequestInterface $request): ResponseInterface + { + $response = $this->responseFactory->createResponse(); + $response->getBody()->write('Hello!'); + return $response; + } +} +``` + +## Código de status + +Você pode definir o código de status assim: + +```php +use Yiisoft\Http\Status; + +$response = $response->withStatus(Status::NOT_FOUND); +``` + +A maioria dos códigos de status está disponível na classe `Status`, por +conveniência e legibilidade. + +O router pode retornar uma resposta antes de a action rodar. Por exemplo, +uma requisição `OPTIONS` para o caminho de uma rota conhecida recebe +automaticamente uma resposta `204 No Content` com um header `Allow` listando +os métodos suportados. Veja [Respostas OPTIONS +automáticas](routing.md#respostas-options-automaticas) para os detalhes de +roteamento. + +## Headers + +Você pode definir headers assim: + +```php +$response = $response->withHeader('Content-type', 'application/json'); +``` + +Se for preciso acrescentar um valor a um header existente: + +```php +$response = $response->withAddedHeader('Set-Cookie', 'qwerty=219ffwef9w0f; Domain=somecompany.co.uk; Path=/; Expires=Wed, 30 Aug 2019 00:00:00 GMT'); +``` + +E, se necessário, os headers podem ser removidos: + +```php +$response = $response->withoutHeader('Set-Cookie'); +``` + +## Corpo + +O corpo da resposta é um objeto que implementa +`Psr\Http\Message\StreamInterface`. + +Você pode escrever nele pela própria interface: + +```php +$body = $response->getBody(); +$body->write('Hello'); +``` + + +## Exemplos + +### Redirecionando + +```php +use Yiisoft\Http\Status; + +return $response + ->withStatus(Status::PERMANENT_REDIRECT) + ->withHeader('Location', 'https://www.example.com'); +``` + +Existem status diferentes usados para redirecionamento: + +| Código | Constante | Para que serve | +|--------|------------------------------|----------------| +| 301 | `Status::MOVED_PERMANENTLY` | Mudança permanente na estrutura de URLs. Os mecanismos de busca atualizam os índices e os navegadores guardam em cache. | +| 308 | `Status::PERMANENT_REDIRECT` | Como o 301, mas garante que o método HTTP não muda. | +| 302 | `Status::FOUND` | Mudanças temporárias, como páginas de manutenção. A URL original ainda deve ser usada nas próximas requisições. Os mecanismos de busca normalmente não atualizam os índices. | +| 307 | `Status::TEMPORARY_REDIRECT` | Como o 302, mas garante que o método HTTP não muda. | +| 303 | `Status::SEE_OTHER` | Depois do envio de formulários, para evitar envios duplicados se o usuário recarregar a página. Indica explicitamente que o redirecionamento deve usar `GET`, mesmo que a requisição original tenha sido `POST`. | + +### Respondendo com JSON + +```php +use Yiisoft\Http\Status; +use Yiisoft\Json\Json; + +$data = [ + 'account' => 'samdark', + 'value' => 42 +]; + +$response->getBody()->write(Json::encode($data)); +return $response + ->withStatus(Status::OK) + ->withHeader('Content-Type', 'application/json'); +``` diff --git a/src/pt-BR/guide/runtime/routing.md b/src/pt-BR/guide/runtime/routing.md new file mode 100644 index 00000000..959142eb --- /dev/null +++ b/src/pt-BR/guide/runtime/routing.md @@ -0,0 +1,583 @@ +# Roteamento e geração de URLs + +Normalmente, uma aplicação Yii processa certas requisições com certos +handlers. Ela escolhe o handler com base na URL da requisição. A parte da +aplicação que faz esse trabalho é o router, e o processo de escolher um +handler, instanciá-lo e executar um método dele é o *roteamento*. + +O processo inverso do roteamento é a *geração de URLs*, que cria uma URL a +partir de uma rota nomeada, de argumentos de rota e de parâmetros de query. +Quando você requisita depois a URL criada, o roteamento consegue convertê-la +de volta nos argumentos de rota e parâmetros de query originais. + +Roteamento e geração de URLs são serviços separados, mas usam o mesmo +conjunto de rotas tanto para casar URLs quanto para gerá-las. + +## Configurando rotas + +Configurando rotas, você faz a aplicação reconhecer formatos arbitrários de +URL sem modificar o código existente. Você pode configurar as rotas em +`/config/routes.php`. A estrutura do arquivo é a seguinte: + +```php +action([SiteController::class, 'index']) + ->name('site/index') +]; +``` + +O arquivo retorna um array de rotas. Ao definir uma rota, você começa com um +método que corresponde a um tipo de requisição HTTP: + +- get +- post +- put +- delete +- patch +- head +- options + +Se você precisar de vários métodos, pode usar `methods()`: + +```php +action([SiteController::class, 'user']) + ->name('site/user') +]; +``` + +Todos esses métodos aceitam um padrão de rota. O padrão de rota define como +o router casa a URL durante o roteamento e como gera a URL a partir do nome +da rota e dos parâmetros. Você vai conhecer a sintaxe mais adiante neste +guia. Defina o handler com `action()` como: + +- Nome de uma classe de [middleware](../structure/middleware.md). +- Uma action de handler (um array no formato [HandlerClass, handlerMethod]). +- Um callable. + +No caso de uma action de handler, uma classe do tipo `HandlerClass` é +instanciada e o seu método `handlerMethod` é chamado: + +```php +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\ResponseInterface; + +final readonly class HandlerClass +{ + public function handle(ServerRequestInterface $request): ResponseInterface + { + // ... + } +} +``` + +O callable é chamado como está: + +```php +static function (ServerRequestInterface $request, RequestHandlerInterface $next) use ($responseFactory) { + $response = $responseFactory->createResponse(); + $response->getBody()->write('You are at homepage.'); + return $response; +} +``` + +Para actions de handler e callables, os parâmetros tipados são injetados +automaticamente pelo container de injeção de dependência passado para a +rota. + +Obtenha a requisição e o handler atuais usando os type hints +`ServerRequestInterface` e `RequestHandlerInterface`. + +### Argumentos de rota nas actions + +Os parâmetros nomeados da rota ficam guardados em `CurrentRoute`. Para +passar um parâmetro de rota para um parâmetro do método da action, use o +atributo `RouteArgument`: + +```php +action([PostController::class, 'view']) + ->name('post/view') +]; + +final readonly class PostController +{ + public function view(#[RouteArgument('id')] int $id): ResponseInterface + { + // $id contains the value from the {id} route parameter. + } +} +``` + +Se o parâmetro tiver o mesmo nome do parâmetro da action, você pode omitir o +nome no atributo: + +```php +public function view(#[RouteArgument] int $id): ResponseInterface +{ + // ... +} +``` + +Você também pode injetar `CurrentRoute` em uma action ou em um serviço +quando precisar de vários argumentos ou de metadados da rota: + +```php +getArgument('id'); + $routeName = $currentRoute->getName(); + + // ... + } +} +``` + +Argumentos de rota não são atributos da requisição. Leia-os de +`CurrentRoute` ou de parâmetros da action marcados com `RouteArgument`. + +Para parâmetros de rota opcionais, informe um valor padrão na rota com +`defaults()` ou na assinatura do método da action. + +Você pode adicionar handlers extras em volta do principal com o método +`middleware()`: + +```php +action([DownloadController::class, 'download']) + ->name('download/id') + ->middleware(LimitDownloadRate::class) +]; +``` + +Veja o guia sobre ["middleware"](../structure/middleware.md) para saber mais +sobre como implementar middlewares. + +Isso é especialmente útil ao agrupar rotas: + +```php +middleware(ApiDataWrapper::class) + ->routes( + Route::get('/info/v2') + ->action(ApiInfo::class) + ->name('api/info/v2') + ->middleware(JsonDataResponseMiddleware::class), + Route::get('/user') + ->action([ApiUserController::class, 'index']) + ->name('api/user/index'), + Route::get('/user/{login}') + ->action([ApiUserController::class, 'profile']) + ->middleware(JsonDataResponseMiddleware::class) + ->name('api/user/profile'), + ) +]; +``` + +O router executa `ApiDataWrapper` antes de tratar qualquer URL que comece +com `/api`. + +Você pode dar um nome a uma rota com o método `name()`. É uma boa ideia +escolher o nome da rota com base no nome do handler. + +Você pode definir um valor padrão para um parâmetro de rota. Por exemplo: + + +```php +action([SiteController::class, 'user']) + ->name('site/user') + ->defaults(['id' => '42']) +]; +``` + +Essa configuração casa tanto com `/user` quanto com `/user/123`. Nos dois +casos, o serviço `CurrentRoute` vai ter o argumento `id` preenchido. No +primeiro caso, ele será o padrão `42` e, no segundo, `123`. + +Se a URL só deve valer para um host, você pode defini-lo com `host()`. + +## Roteamento + +O roteamento do Yii é flexível e, internamente, pode usar diferentes +implementações. O algoritmo de casamento pode variar, mas a ideia básica é +a mesma. + +O router casa as rotas definidas na configuração de cima para baixo. Se +houver um casamento, ele para de procurar e executa o handler da rota para +obter a resposta. Se nenhuma rota casar, o router passa o tratamento para o +próximo middleware do [conjunto de middlewares da +aplicação](../structure/middleware.md). + +### Respostas OPTIONS automáticas + +Quando o caminho da requisição casa com uma rota, mas o método HTTP não, o +router retorna uma resposta `405 Method Not Allowed` com o header `Allow`: + +```http +HTTP/1.1 405 Method Not Allowed +Allow: GET +``` + +Para uma requisição `OPTIONS` no mesmo caminho, o router retorna uma +resposta vazia `204 No Content` com o mesmo header `Allow`: + +```http +HTTP/1.1 204 No Content +Allow: GET +``` + +Essa resposta é gerada a partir das rotas configuradas, antes de a action da +rota ser executada. Se um endpoint de API precisar de headers CORS, +adicione um middleware de CORS a um grupo de rotas: + +```php +withCors(CorsMiddleware::class) + ->routes( + Route::methods([Method::GET, Method::POST], '/posts') + ->action([PostController::class, 'index']) + ->name('api/posts') + ) +]; +``` + +## Gerando URLs + +Para gerar uma URL a partir de uma rota, a rota precisa ter um nome: + +```php +action([TestController::class, 'index']) + ->name('test/index'), + Route::post('/test/submit/{id}') + ->action([TestController::class, 'submit']) + ->name('test/submit') +]; +``` + + +A geração fica assim: + +```php +generate('test/submit', ['id' => '42']); + // ... + } +} +``` + +No código acima, obtemos uma instância do gerador com a ajuda da [injeção de +dependência automática](../concept/di-container.md), que funciona com +handlers de action. Em outro serviço, você pode obter a instância com uma +injeção no construtor parecida. Nas views, o gerador de URLs está +disponível como `$url`. + +Depois usamos o método `generate()` para obter a URL. Ele aceita o nome da +rota, argumentos de rota, parâmetros de query e um fragmento (hash). O +código retorna `/test/submit/42`. + +Os argumentos de rota preenchem os placeholders do padrão da rota. Os +argumentos que não aparecem no padrão são adicionados à query string, desde +que o array de parâmetros de query ainda não tenha o mesmo nome: + +```php +$url = $urlGenerator->generate( + 'test/submit', + ['id' => '42', 'utm' => 'newsletter'], + ['page' => '1'] +); +// $url is "/test/submit/42?page=1&utm=newsletter". +``` + +Se você precisar de uma URL absoluta, use `generateAbsolute()`. + +### Gerando a URL a partir da rota atual + +Use `generateFromCurrent()` quando um link deve manter a rota atual e a +maior parte dos seus argumentos. Por exemplo, uma página de detalhes pode +apontar para outro número de página mantendo o nome da rota atual e o +argumento `id`: + +```php +$url = $urlGenerator->generateFromCurrent(['page' => '2']); +``` + +O método também mantém os parâmetros de query da requisição atual. Passe +parâmetros de query explícitos quando o link precisar substituir ou +adicionar valores na query string. + +### URLs com locale + +Quando o locale faz parte do caminho da URL, defina-o como um argumento de +rota. Em uma aplicação Yii com as rotas em `config/common/routes.php`, +coloque as rotas localizadas em um grupo com um parâmetro de locale: + +```php +routes( + Route::get('/') + ->action(HomePageAction::class) + ->name('home'), + Route::get('/posts/{slug}') + ->action(PostViewAction::class) + ->name('post/view') + ) +]; +``` + +A rota `/de/posts/welcome` casa com a rota `post/view` e guarda `_locale` +como argumento de rota com o valor `de`. + +No middleware que escolhe o locale da requisição, leia esse argumento de +`CurrentRoute`: + +```php +currentRoute->getArgument('_locale', self::DEFAULT_LOCALE); + + $this->translator->setLocale($locale); + $this->view->setLocale($locale); + $this->urlGenerator->setDefaultArgument('_locale', $locale); + + return $handler->handle($request); + } +} +``` + +Registre esse middleware no grupo de rotas localizadas, antes da action da +rota: + +```php +use App\Web\HomePage\Action as HomePageAction; +use App\Web\Middleware\LocaleMiddleware; +use Yiisoft\Router\Group; +use Yiisoft\Router\Route; + +return [ + Group::create('/{_locale:en-US|de}') + ->middleware(LocaleMiddleware::class) + ->routes( + Route::get('/') + ->action(HomePageAction::class) + ->name('home') + ) +]; +``` + +Depois que o middleware define o argumento padrão `_locale`, a geração de +URLs pode omiti-lo: + +```php +$url = $urlGenerator->generate('post/view', ['slug' => 'welcome']); +// On a German page, $url is "/de/posts/welcome". +``` + +Para um seletor de idioma, use `generateFromCurrent()` e substitua apenas o +argumento de locale: + +```php +$url = $urlGenerator->generateFromCurrent( + ['_locale' => 'en-US'], + fallbackRouteName: 'home' +); +``` + +## Padrões de rota + +Os padrões de rota dependem da implementação usada por baixo. A +implementação padrão é o +[nikic/FastRoute](https://github.com/nikic/FastRoute). + +Os padrões básicos são estáticos, como `/test`. Isso significa que eles +precisam casar exatamente para a rota ser escolhida. + +### Parâmetros nomeados + +Um padrão pode ter um ou mais parâmetros nomeados, escritos no formato +`{ParamName:RegExp}`, onde `ParamName` é o nome do parâmetro e `RegExp` é +uma expressão regular opcional usada para casar o valor. Se `RegExp` não +for informada, o valor do parâmetro deve ser uma string sem barras. + +> [!NOTE] +> Você só pode usar expressões regulares dentro dos parâmetros. O resto do padrão é tratado como texto puro. + +Você não pode usar grupos de captura. Por exemplo, `{lang:(en|de)}` não é um +placeholder válido, porque `()` é um grupo de captura. Em vez disso, use +`{lang:en|de}` ou `{lang:(?:en|de)}`. + +Quando uma rota casa, o router preenche os argumentos de `CurrentRoute` com +os valores das partes correspondentes da URL. Quando você usa a regra para +criar uma URL, ela pega os valores dos parâmetros informados e os insere nas +posições onde os parâmetros foram declarados. + +Vamos usar alguns exemplos para mostrar como os parâmetros nomeados +funcionam. Suponha que você declarou os três padrões a seguir: + + +1. `'posts/{year:\d{4}}/{category}` +2. `'posts'` +3. `'post/{id:\d+}'` + +- `/posts` casa com o segundo padrão; +- `/posts/2014/php` casa com o primeiro padrão. Os parâmetros são `year`, + com valor 2014, e `category`, com valor `php`; +- `/post/100` casa com o terceiro padrão. O valor do parâmetro `id` é 100; +- `/posts/php` não casa. + +Ao gerar URLs, você deve usar os seguintes parâmetros: + +```php +echo $url->generate('first', ['year' => '2020', 'category' => 'Virology']); +echo $url->generate('second'); +echo $url->generate('third', ['id' => '42']); +``` + +### Partes opcionais + +Coloque as partes opcionais do padrão entre `[` e `]`. Por exemplo, o +padrão `/posts[/{id}]` casa tanto com `http://example.com/posts` quanto com +`http://example.com/posts/42`. O router só preenche o argumento `id` do +serviço `CurrentRoute` no segundo caso. Nesse caso, você pode definir o +valor padrão: + +```php +use \Yiisoft\Router\Route; + +Route::get('/posts[/{id}]')->defaults(['id' => '1']); +``` + +Partes opcionais só são suportadas no final da rota, não no meio dela. diff --git a/src/pt-BR/guide/runtime/sessions.md b/src/pt-BR/guide/runtime/sessions.md new file mode 100644 index 00000000..4c6fb3e4 --- /dev/null +++ b/src/pt-BR/guide/runtime/sessions.md @@ -0,0 +1,164 @@ +# Sessões + +As sessões mantêm dados entre requisições sem precisar enviá-los ao cliente +e de volta. O Yii tem [um pacote de +sessão](https://github.com/yiisoft/session) para trabalhar com os dados da +sessão. + +Para adicioná-lo à sua aplicação, use o composer: + +```shell +composer require yiisoft/session +``` + +## Configurando o middleware + +Para manter a sessão entre requisições, você precisa adicionar o +`SessionMiddleware` ao seu grupo de rotas ou aos middlewares da aplicação. +Prefira um grupo de rotas quando a mesma aplicação tiver uma API com +autenticação por token e rotas web comuns. Assim, a sessão não é iniciada +nos endpoints da API. + +Para adicionar a sessão a um grupo específico de rotas, edite +`config/routes.php` assim: + +```php +middleware(SessionMiddleware::class) + ->routes( + // ... + ) +]; +``` + +Para adicionar a sessão à aplicação inteira, edite `config/application.php` +assim: + +```php +return [ + Yiisoft\Yii\Web\Application::class => [ + '__construct()' => [ + 'dispatcher' => DynamicReference::to(static function (Injector $injector) { + return ($injector->make(MiddlewareDispatcher::class)) + ->withMiddlewares( + [ + Router::class, + CsrfTokenMiddleware::class, + SessionMiddleware::class, // <-- add this + ErrorCatcher::class, + ] + ); + }), + ], + ], +]; +``` + +## Abrindo e fechando a sessão + +```php +public function actionProfile(\Yiisoft\Session\SessionInterface $session) +{ + // start a session if it's not yet started + $session->open(); + + // work with session + + // write session values and then close it + $session->close(); +} +``` + +> [!NOTE] +> Fechar a sessão o quanto antes é uma boa prática, já que muitas implementações de sessão bloqueiam outras +> requisições enquanto a sessão está aberta. + +Há mais duas formas de fechar uma sessão: + +```php +public function actionProfile(\Yiisoft\Session\SessionInterface $session) +{ + // discard changes and close the session + $session->discard(); + + // destroy the session completely + $session->destroy(); +} +``` + +## Trabalhando com os dados da sessão + +Normalmente você vai usar os seguintes métodos para trabalhar com os dados +da sessão: + +```php +public function actionProfile(\Yiisoft\Session\SessionInterface $session) +{ + // get a value + $lastAccessTime = $session->get('lastAccessTime'); + + // get all values + $sessionData = $session->all(); + + // set a value + $session->set('lastAccessTime', time()); + + // check if the value exists + if ($session->has('lastAccessTime')) { + // ... + } + + // remove value + $session->remove('lastAccessTime'); + + // get value and then remove it + $sessionData = $session->pull('lastAccessTime'); + + // clear session data from runtime + $session->clear(); +} +``` + +## Mensagens flash + +Quando você precisa que um dado fique na sessão até ser lido, como ao exibir +uma mensagem na próxima página, o que você precisa são as mensagens +"flash". Uma mensagem flash é um tipo especial de dado que só fica +disponível na requisição atual e na próxima. Depois disso, ela é apagada +automaticamente. + +O uso de `FlashInteface` é o seguinte: + +```php +/** @var Yiisoft\Session\Flash\FlashInterface $flash */ + +// request 1 +$flash->set('warning', 'Oh no, not again.'); + +// request 2 +$warning = $flash->get('warning'); +if ($warning !== null) { + // do something with it +} +``` + +## Armazenamento de sessão personalizado + +Ao usar `Yiisoft\Session\Session`, você pode usar a sua própria +implementação de armazenamento: + +```php +$handler = new MySessionHandler(); +$session = new \Yiisoft\Session\Session([], $handler); +``` + +O armazenamento personalizado precisa implementar +`\SessionHandlerInterface`. diff --git a/src/pt-BR/guide/security/authentication.md b/src/pt-BR/guide/security/authentication.md new file mode 100644 index 00000000..7bf0123d --- /dev/null +++ b/src/pt-BR/guide/security/authentication.md @@ -0,0 +1,262 @@ +# Autenticação + +Autenticação é o processo de verificar a identidade de um +usuário. Normalmente ela usa um identificador (por exemplo, um nome de +usuário ou um endereço de e-mail) e um token secreto (como uma senha ou um +token de acesso) para decidir se o usuário é quem diz ser. A autenticação é +a base do recurso de login. + +O Yii fornece um framework de autenticação que conecta vários componentes +para dar suporte ao login. Para usar esse framework, você precisa +basicamente fazer o seguinte: + +* Configurar o serviço `Yiisoft\User\CurrentUser`; +* Criar uma classe que implementa a interface + `\Yiisoft\Auth\IdentityInterface`; +* Criar uma classe que implementa a interface + `\Yiisoft\Auth\IdentityRepositoryInterface`; + +Para usar o serviço `Yiisoft\User\CurrentUser`, instale o pacote +[yiisoft/user](https://github.com/yiisoft/user): + +```shell +composer require yiisoft/user +``` + +## Configurando `Yiisoft\User\CurrentUser` + +O serviço de aplicação `Yiisoft\User\CurrentUser` gerencia o estado de +autenticação do usuário. Ele depende de +`Yiisoft\Auth\IdentityRepositoryInterface`, que deve retornar uma instância +de `\Yiisoft\Auth\IdentityInterface` contendo a lógica de autenticação de +fato. + +```php +use Yiisoft\Session\Session; +use Yiisoft\Session\SessionInterface; +use Yiisoft\Auth\IdentityRepositoryInterface; +use Yiisoft\Definitions\Reference; + +return [ + // ... + + SessionInterface::class => [ + 'class' => Session::class, + '__construct()' => [ + $params['session']['options'] ?? [], + $params['session']['handler'] ?? null, + ], + ], + IdentityRepositoryInterface::class => IdentityRepository::class, + CurrentUser::class => [ + 'withSession()' => [Reference::to(SessionInterface::class)] + ], +]; +``` + +## Implementando`\Yiisoft\Auth\IdentityInterface` + +A classe de identidade deve implementar a `\Yiisoft\Auth\IdentityInterface`, +que tem um único método: + +* [[yii\web\IdentityInterface::getId()|getId()]]: retorna o ID do usuário + representado por esta instância de identidade. + +No exemplo a seguir, a classe de identidade é implementada como um objeto +PHP puro. + +```php +id; + } +} +``` + +## Implementando`\Yiisoft\Auth\IdentityRepositoryInterface` + +A classe de repositório de identidades deve implementar a +`\Yiisoft\Auth\IdentityRepositoryInterface`, que tem os seguintes métodos: + +* `findIdentity(string $id): ?IdentityInterface`: procura uma instância da + classe de identidade usando o ID informado. Esse método é usado quando + você precisa manter o estado de login via sessão. +* `findIdentityByToken(string $token, string $type): ?IdentityInterface`: + procura uma instância da classe de identidade usando o token de acesso + informado. Esse método é usado quando você precisa autenticar um usuário + por um único token secreto (por exemplo, numa API REST sem estado). + +Uma implementação fictícia pode ficar assim: + +```php +namespace App\User; + +use App\User\Identity; +use \Yiisoft\Auth\IdentityInterface; +use \Yiisoft\Auth\IdentityRepositoryInterface; + +final readonly class IdentityRepository implements IdentityRepositoryInterface +{ + private const USERS = [ + [ + 'id' => 1, + 'token' => '12345' + ], + [ + 'id' => 42, + 'token' => '54321' + ], + ]; + + public function findIdentity(string $id) : ?IdentityInterface + { + foreach (self::USERS as $user) { + if ((string)$user['id'] === $id) { + return new Identity($id); + } + } + + return null; + } + + public function findIdentityByToken(string $token, string $type) : ?IdentityInterface + { + foreach (self::USERS as $user) { + if ($user['token'] === $token) { + return new Identity((string)$user['id']); + } + } + + return null; + } +} +``` + +## Usando `Yiisoft\User\CurrentUser` + +Você pode usar o serviço `Yiisoft\User\CurrentUser` para obter a identidade +do usuário atual. Como qualquer serviço, ele pode ser injetado +automaticamente (autowiring) no construtor ou no método do handler da +action: + +```php +use Psr\Http\Message\ServerRequestInterface; +use Yiisoft\User\CurrentUser; + +final readonly class SiteController +{ + public function __construct(private CurrentUser $user) {} + + public function index(ServerRequestInterface $request): ResponseInterface + { + if ($this->user->isGuest()) { + // o usuário é visitante + } else { + $identity = $this->user->getIdentity(); + // faça algo com base na identidade + } + } +} +``` + +`isGuest()` determina se o usuário está logado ou não. `getIdentity()` +retorna uma instância da identidade. + +Para fazer o login de um usuário, você pode usar o seguinte código: + +```php +$identity = $identityRepository->findByEmail($email); + +/* @var $user \Yiisoft\User\CurrentUser */ +$user->login($identity); +``` + +O método `login()` define a identidade no serviço de usuário. Ele armazena +a identidade na sessão, para que o estado de autenticação do usuário seja +mantido. + +Para fazer o logout de um usuário, chame + +```php +/* @var $user \Yiisoft\User\CurrentUser */ +$user->logout(); +``` + +## Protegendo rotas + +O middleware `Yiisoft\Auth\Middleware\Authentication` pode ser usado para +restringir o acesso a uma rota apenas a usuários autenticados. + +Primeiro, configure a `Yiisoft\Auth\AuthenticationMethodInterface`: + +```php +use Yiisoft\Auth\AuthenticationMethodInterface; +use Yiisoft\User\Method\WebAuth; + +return [ + // ... + AuthenticationMethodInterface::class => WebAuth::class, +]; +``` + +Depois, aplique o middleware `Yiisoft\Auth\Middleware\Authentication` a uma +rota: + +```php +use Yiisoft\Auth\Middleware\Authentication; + +Route::post('/create') + ->middleware(Authentication::class) + ->action([SiteController::class, 'create']) + ->name('site/create') +``` + + Ou a um grupo de rotas: + +```php +use Yiisoft\Auth\Middleware\Authentication; + +Group::create() + ->middleware(Authentication::class) + ->routes( + Route::post('/create') + ->action([SiteController::class, 'create']) + ->name('site/create'), + Route::put('/update/{id}') + ->action([SiteController::class, 'update']) + ->name('site/update') + ) +``` + +## Eventos de autenticação + +O serviço de usuário dispara alguns eventos durante os processos de login e +logout. + + +* `\Yiisoft\User\Event\BeforeLogin`: disparado no início de `login()`. Se o + handler do evento chamar `invalidate()` no objeto do evento, o processo de + login será cancelado. +* `\Yiisoft\User\Event\AfterLogin`: disparado após um login bem-sucedido. +* `\Yiisoft\User\Event\BeforeLogout`: disparado no início de `logout()`. Se + o handler do evento chamar `invalidate()` no objeto do evento, o processo + de logout será cancelado. +* `\Yiisoft\User\Event\AfterLogout`: disparado após um logout bem-sucedido. + +Você pode responder a esses eventos para implementar recursos como auditoria +de login ou estatísticas de usuários online. Por exemplo, no handler de +`\Yiisoft\User\Event\AfterLogin`, você pode registrar o horário e o endereço +IP do login na tabela `user` do banco de dados. diff --git a/src/pt-BR/guide/security/authorization.md b/src/pt-BR/guide/security/authorization.md new file mode 100644 index 00000000..8c50236b --- /dev/null +++ b/src/pt-BR/guide/security/authorization.md @@ -0,0 +1,615 @@ +# Autorização + +Autorização é o processo de verificar se um usuário tem permissão suficiente +para fazer algo. + +## Verificando permissões + +Você pode verificar se um usuário tem determinadas permissões usando o +serviço `\Yiisoft\User\CurrentUser`: + +```php +namespace App\Blog\Post; + +use Yiisoft\User\CurrentUser; +use Yiisoft\Router\HydratorAttribute\RouteArgument; +use Psr\Http\Message\ResponseInterface; + +final readonly class PostController +{ + public function __construct( + private PostRepositoryInterface $postRepository, + private CurrentUser $user + ) + { + } + + public function update(#[RouteArgument('id')] int $id): ResponseInterface + { + $post = $this->postRepository->findByPK($id); + if ($post === null) { + // responda com 404 + } + + if (!$this->canCurrentUserUpdatePost($post)) { + // responda com 403 + } + + // continue com a atualização do post + } + + private function canCurrentUserUpdatePost(Post $post): bool + { + return $post->getAuthorId() === $this->user->getId() && + $this->user->can('updatePost'); + } +} +``` + +Por baixo dos panos, o método `Yiisoft\User\CurrentUser::can()` chama +`Yiisoft\Access\AccessCheckerInterface::userHasPermission()`, então você +precisa fornecer uma implementação no container de dependências para que ele +funcione. + +## Controle de acesso baseado em papéis (RBAC) + +O controle de acesso baseado em papéis (RBAC, Role-Based Access Control) +oferece um controle de acesso centralizado simples e flexível. Consulte a +[Wikipedia](https://en.wikipedia.org/wiki/Role-based_access_control) para +detalhes sobre a comparação do RBAC com outros esquemas de controle de +acesso mais tradicionais. + +O Yii implementa um RBAC hierárquico geral, seguindo o [modelo RBAC do +NIST](https://csrc.nist.gov/CSRC/media/Publications/conference-paper/2000/07/26/the-nist-model-for-role-based-access-control-towards-a-unified-/documents/sandhu-ferraiolo-kuhn-00.pdf). + +Usar RBAC envolve duas partes de trabalho. A primeira é montar os dados de +autorização do RBAC, e a segunda é usar esses dados para fazer a verificação +de acesso onde for necessário. Como o RBAC implementa +`\Yiisoft\Access\AccessCheckerInterface`, usá-lo é parecido com usar +qualquer outra implementação de verificador de acesso. + +Para facilitar a explicação a seguir, primeiro alguns conceitos básicos de +RBAC. + +### Conceitos básicos + +Um papel representa um conjunto de *permissões* (por exemplo, criar posts, +atualizar posts). Você pode atribuir um papel a um ou mais usuários. Para +verificar se um usuário tem uma determinada permissão, você pode verificar +se ele tem um papel com essa permissão. + +Cada papel ou permissão pode ter uma *regra* associada. Uma regra +representa um trecho de código que o verificador de acesso executa para +decidir se o papel ou a permissão correspondente se aplica ao usuário +atual. Por exemplo, a permissão "atualizar post" pode ter uma regra que +verifica se o usuário atual é o criador do post. Durante a verificação de +acesso, se o usuário NÃO for o criador do post, ele não tem a permissão +"atualizar post". + +Tanto papéis quanto permissões ficam em uma hierarquia. Em particular, um +papel pode ser composto de outros papéis ou permissões. E uma permissão +pode ser composta de outras permissões. O Yii implementa uma hierarquia de +*ordem parcial*, que inclui a hierarquia mais específica em *árvore*. +Embora um papel possa conter uma permissão, o inverso não é verdadeiro. + +### Configurando o RBAC + +O RBAC do Yii exige que um armazenamento seja fornecido. + +Um dos seguintes armazenamentos pode ser instalado: + +- [Armazenamento PHP](https://github.com/yiisoft/rbac-php) - armazenamento + em arquivos PHP; +- [Armazenamento em DB](https://github.com/yiisoft/rbac-db) - armazenamento + em banco de dados baseado no [Yii DB](https://github.com/yiisoft/db); +- [Armazenamento Cycle DB](https://github.com/yiisoft/rbac-cycle-db) - + armazenamento em banco de dados baseado no [Cycle + DBAL](https://github.com/cycle/database). + +Você também pode fornecer seu próprio armazenamento usando o pacote +[yiisoft/rbac](https://github.com/yiisoft/rbac). + +#### Configurando o RBAC com o [armazenamento PHP](https://github.com/yiisoft/rbac-php) + +Instale o pacote [yiisoft/rbac-php](https://github.com/yiisoft/rbac-php): + +``` +composer require yiisoft/rbac-php +``` + +Antes de definir os dados de autorização e fazer verificações de acesso, +você precisa configurar a `Yiisoft\Access\AccessCheckerInterface` no +container de dependências: + +```php +use Yiisoft\Rbac\ItemsStorageInterface; +use Yiisoft\Rbac\AssignmentsStorageInterface; +use Yiisoft\Rbac\ManagerInterface; +use Yiisoft\Rbac\Php\ItemsStorage; +use Yiisoft\Rbac\Php\AssignmentsStorage; +use Yiisoft\Access\AccessCheckerInterface; +use Yiisoft\User\CurrentUser; + +return [ + // ... + ItemsStorageInterface::class => [ + 'class' => ItemsStorage::class, + '__construct()' => [ + 'filePath' => $params['rbacItemsStorageFilePath'] + ] + ], + AssignmentsStorageInterface::class => [ + 'class' => AssignmentsStorage::class, + '__construct()' => [ + 'filePath' => $params['rbacAssignmentsStorageFilePath'] + ] + ], + AccessCheckerInterface::class => ManagerInterface::class, + + CurrentUser::class => [ + 'withAccessChecker()' => [Reference::to(AccessCheckerInterface::class)] + ], +]; +``` + +O `Yiisoft\Rbac\Manager` usa arquivos de script PHP para armazenar os dados +de autorização. Garanta que o diretório e todos os arquivos dentro dele +tenham permissão de escrita para o processo do servidor web, se você quiser +alterar a hierarquia de permissões em tempo de execução. + +#### Configurando o RBAC com o [armazenamento em DB](https://github.com/yiisoft/rbac-db) + +Instale o pacote [yiisoft/rbac-db](https://github.com/yiisoft/rbac-db): + +``` +composer require yiisoft/rbac-db +``` + +Instale um dos seguintes drivers: + - [SQLite](https://github.com/yiisoft/db-sqlite) (a versão mínima exigida é a 3.8.3) + - [MySQL](https://github.com/yiisoft/db-mysql) + - [PostgreSQL](https://github.com/yiisoft/db-pgsql) + - [Microsoft SQL Server](https://github.com/yiisoft/db-mssql) + - [Oracle](https://github.com/yiisoft/db-oracle) + +[Configure a +conexão](https://yiisoft.github.io/docs/guide/start/databases.html#configuring-connection). + +Antes de definir os dados de autorização e fazer verificações de acesso, +você precisa configurar a `Yiisoft\Access\AccessCheckerInterface` no +container de dependências: + +```php +use Yiisoft\Rbac\ItemsStorageInterface; +use Yiisoft\Rbac\AssignmentsStorageInterface; +use Yiisoft\Rbac\ManagerInterface; +use Yiisoft\Rbac\Db\ItemsStorage; +use Yiisoft\Rbac\Db\AssignmentsStorage; +use Yiisoft\Access\AccessCheckerInterface; + +return [ + // ... + ItemsStorageInterface::class => ItemsStorage::class, + AssignmentsStorageInterface::class => AssignmentsStorage::class, + AccessCheckerInterface::class => ManagerInterface::class, +]; +``` + +Adicione os caminhos das migrations do [armazenamento em +DB](https://github.com/yiisoft/rbac-db) do RBAC ao params.php: + +```php +return [ + // ... + 'yiisoft/db-migration' => [ + 'sourcePaths' => [ + __DIR__ . '/../../vendor/yiisoft/rbac-db/migrations/items', + __DIR__ . '/../../vendor/yiisoft/rbac-db/migrations/assignments', + ], + ], +]; +``` + +Aplique as migrations: + +``` +./yii migrate:up +``` + +### Montando os dados de autorização + +Montar os dados de autorização consiste nas seguintes tarefas: + +- definir papéis e permissões; +- estabelecer relações entre papéis e permissões; +- definir regras; +- associar regras a papéis e permissões; +- atribuir papéis a usuários. + +Dependendo da flexibilidade de autorização exigida, você pode fazer essas +tarefas de maneiras diferentes. Se apenas desenvolvedores alteram sua +hierarquia de permissões, você pode usar migrations ou um comando de +console. A vantagem da migration é que você pode executá-la junto com as +outras migrations. A vantagem do comando de console é que você tem uma boa +visão da hierarquia no código, sem precisar ler muitas migrations. + +De qualquer forma, no fim você terá a seguinte hierarquia RBAC: + +![Hierarquia RBAC simples](/images/guide/security/rbac-hierarchy-1.svg +"Hierarquia RBAC simples") + +Caso você queira montar a hierarquia de permissões dinamicamente, precisa de +uma interface de usuário ou de um comando de console. A API usada para +montar a hierarquia em si não muda. + +### Usando um comando de console + +Se a sua hierarquia de permissões não muda nunca e você tem um número fixo +de usuários, pode criar um [comando de +console](../tutorial/console-applications.md) que inicializa os dados de +autorização uma única vez, usando as APIs oferecidas por +`\Yiisoft\Rbac\ManagerInterface`: + +```php +removeAll(); + + $this->manager->addPermission((new Permission(RbacCommand::CREATE_POST_PERMISSION))->withDescription('Create a post')); + $this->manager->addPermission((new Permission(RbacCommand::UPDATE_POST_PERMISSION))->withDescription('Update post')); + + // adiciona o papel "author" e dá a ele a permissão "createPost" + $this->manager->addRole(new Role(RbacCommand::ROLE_AUTHOR)); + $this->manager->addChild(RbacCommand::ROLE_AUTHOR, RbacCommand::CREATE_POST_PERMISSION); + + // adiciona o papel "admin" e dá a ele a permissão "updatePost" + // além das permissões do papel "author" + $this->manager->addRole(new Role(RbacCommand::ROLE_ADMIN)); + $this->manager->addChild(RbacCommand::ROLE_ADMIN, RbacCommand::UPDATE_POST_PERMISSION); + $this->manager->addChild(RbacCommand::ROLE_ADMIN, RbacCommand::ROLE_AUTHOR); + + // Atribui papéis aos usuários. 1 e 2 são IDs retornados por IdentityInterface::getId(), + // normalmente implementado no seu model User. + $this->manager->assign(RbacCommand::ROLE_AUTHOR, 2); + $this->manager->assign(RbacCommand::ROLE_ADMIN, 1); + + return ExitCode::OK; + } + + private function removeAll(): void + { + $this->manager->revokeAll(2); + $this->manager->revokeAll(1); + + $this->manager->removeRole(RbacCommand::ROLE_ADMIN); + $this->manager->removeRole(RbacCommand::ROLE_AUTHOR); + + $this->manager->removePermission(RbacCommand::CREATE_POST_PERMISSION); + $this->manager->removePermission(RbacCommand::UPDATE_POST_PERMISSION); + } +} +``` + +Adicione o comando em `config/console/commands.php`: + +```php +return [ + // ... + 'rbac:init' => App\Command\RbacCommand::class +]; +``` + +Você pode executar o comando acima no console da seguinte forma: + +``` +./yii rbac:init +``` + +> Se você não quer deixar fixo no código quais usuários têm determinados papéis, não coloque chamadas `->assign()` no comando. Em vez disso, + crie uma interface de usuário ou um comando de console para gerenciar as atribuições. + +#### Usando migrations + +**TODO**: terminar quando as migrations forem implementadas. + +Você pode usar [migrations](../databases/db-migrations.md) para inicializar +e alterar a hierarquia via APIs oferecidas por +`\Yiisoft\Rbac\ManagerInterface`. + +Crie uma nova migration com `./yii migrate:create init_rbac` e implemente a +criação da hierarquia: + +```php +manager->addPermission((new Permission(M260112125812InitRbac::CREATE_POST_PERMISSION))->withDescription('Create a post')); + $this->manager->addPermission((new Permission(M260112125812InitRbac::UPDATE_POST_PERMISSION))->withDescription('Update post')); + + // adiciona o papel "author" e dá a ele a permissão "createPost" + $this->manager->addRole(new Role(M260112125812InitRbac::ROLE_AUTHOR)); + $this->manager->addChild(M260112125812InitRbac::ROLE_AUTHOR, M260112125812InitRbac::CREATE_POST_PERMISSION); + + // adiciona o papel "admin" e dá a ele a permissão "updatePost" + // além das permissões do papel "author" + $this->manager->addRole(new Role(M260112125812InitRbac::ROLE_ADMIN)); + $this->manager->addChild(M260112125812InitRbac::ROLE_ADMIN, M260112125812InitRbac::UPDATE_POST_PERMISSION); + $this->manager->addChild(M260112125812InitRbac::ROLE_ADMIN, M260112125812InitRbac::ROLE_AUTHOR); + + // Atribui papéis aos usuários. 1 e 2 são IDs retornados por IdentityInterface::getId(), + // normalmente implementado no seu model User. + $this->manager->assign(M260112125812InitRbac::ROLE_AUTHOR, 2); + $this->manager->assign(M260112125812InitRbac::ROLE_ADMIN, 1); + } + + public function down(MigrationBuilder $b): void + { + $this->manager->revokeAll(2); + $this->manager->revokeAll(1); + + $this->manager->removeRole(M260112125812InitRbac::ROLE_ADMIN); + $this->manager->removeRole(M260112125812InitRbac::ROLE_AUTHOR); + + $this->manager->removePermission(M260112125812InitRbac::CREATE_POST_PERMISSION); + $this->manager->removePermission(M260112125812InitRbac::UPDATE_POST_PERMISSION); + } +} +``` + +> Se você não quer deixar fixo no código quais usuários têm determinados papéis, não coloque chamadas `->assign()` nas migrations. Em vez disso, + crie uma interface de usuário ou um comando de console para gerenciar as atribuições. + +Você pode aplicar a migration com `./yii migrate:up`. + +## Atribuindo papéis a usuários + +TODO: atualizar quando o cadastro for implementado no demo / template. + +O autor pode criar um post, o admin pode atualizar o post e fazer tudo o que +o autor pode. + +Se sua aplicação permite o cadastro de usuários, você precisa atribuir +papéis a esses novos usuários imediatamente. Por exemplo, para que todos os +usuários cadastrados se tornem autores no seu template de projeto avançado, +você precisa alterar `frontend\models\SignupForm::signup()` da seguinte +forma: + +```php +public function signup() +{ + if ($this->validate()) { + $user = new User(); + $user->username = $this->username; + $user->email = $this->email; + $user->setPassword($this->password); + $user->generateAuthKey(); + $user->save(false); + + // as três linhas a seguir foram adicionadas: + $authorRole = $this->manager->getRole('author'); + if ($authorRole !== null) { + $this->manager->assign($authorRole->getName(), $user->getId()); + } + + return $user; + } + + return null; +} +``` + +Para aplicações que exigem controle de acesso complexo com dados de +autorização atualizados dinamicamente (como um painel administrativo), +talvez você precise desenvolver interfaces de usuário específicas usando as +APIs oferecidas por `Yiisoft\Rbac\Manager`. + + +### Usando regras + +Como mencionado, regras adicionam restrições extras a papéis e permissões. +Uma regra é uma classe que estende `\Yiisoft\Rbac\Rule`. Ela deve +implementar o método `execute()`. Na hierarquia que você criou antes, o +autor não pode editar o próprio post. Vamos corrigir isso. Primeiro, você +precisa de uma regra para verificar se o usuário é o autor do post: + +```php +namespace App\User\Rbac; + +use Yiisoft\Rbac\Item; +use Yiisoft\Rbac\RuleContext; +use Yiisoft\Rbac\RuleInterface; + +/** + * Checks if the authorID matches user passed via params. + */ +final readonly class AuthorRule implements RuleInterface +{ + public function execute(?string $userId, Item $item, RuleContext $context): bool + { + $post = $context->getParameterValue('post'); + return $post !== null && $post->getAuthorId() == $userId; + } +} +``` + +A regra verifica se o usuário criou o `post`. Crie uma permissão especial +`updateOwnPost` no comando que você usou antes: + +```php +use Yiisoft\Rbac\Permission; +use Yiisoft\Rbac\ManagerInterface; + +// adiciona a permissão "updateOwnPost" e associa a regra a ela. +$updateOwnPost = (new Permission('updateOwnPost')) + ->withDescription('Update own post') + ->withRuleName(AuthorRule::class); +$this->manager->addPermission($updateOwnPost); + +// "updateOwnPost" será usada a partir de "updatePost" +$this->manager->addChild($updateOwnPost->getName(), $updatePost->getName()); + +// permite que "author" atualize os próprios posts +$this->manager->addChild($authorRole->getName(), $updateOwnPost->getName()); + +// Remova esta linha, já que não queremos que a AuthorRule seja aplicada ao papel 'admin' +$this->manager->addChild('admin', 'author'); +``` + +Agora você tem a seguinte hierarquia: + +![Hierarquia RBAC com uma regra](/images/guide/security/rbac-hierarchy-2.svg +"Hierarquia RBAC com uma regra") + + +### Verificação de acesso + +A verificação é feita de forma semelhante à da primeira seção deste guia: + +```php +namespace App\Blog\Post; + +use Yiisoft\User\CurrentUser; +use Yiisoft\Router\HydratorAttribute\RouteArgument; +use Psr\Http\Message\ResponseInterface; + +final readonly class PostController +{ + public function __construct( + private PostRepositoryInterface $postRepository, + private CurrentUser $user + ) + { + } + + public function update(#[RouteArgument('id')] int $id): ResponseInterface + { + $post = $this->postRepository->findByPK($id); + if ($post === null) { + // responda com 404 + } + + if (!$this->canCurrentUserUpdatePost($post)) { + // responda com 403 + } + + // continue com a atualização do post + } + + private function canCurrentUserUpdatePost(Post $post): bool + { + return $this->user->can('updatePost', ['post' => $post]); + } +} +``` + +A diferença é que agora a verificação do próprio post do usuário faz parte +do RBAC. + +Se o usuário atual for Jane, com `ID=1`, você começa em `createPost` e tenta +chegar a `Jane`: + +![Verificação de acesso](/images/guide/security/rbac-access-check-1.svg +"Verificação de acesso") + +Para verificar se um usuário pode atualizar um post, você precisa passar um +parâmetro extra exigido pela `AuthorRule` descrita antes: + +```php +if ($user->can('updatePost', ['post' => $post])) { + // atualiza o post +} +``` + +Veja o que acontece se o usuário atual for John: + + +![Verificação de acesso](/images/guide/security/rbac-access-check-2.svg +"Verificação de acesso") + +Você começa em `updatePost` e passa por `updateOwnPost`. Para passar na verificação de acesso, a `AuthorRule` +deve retornar `true` no método `execute()`. O método recebe seus `$params` da chamada do método `can()`, então o valor é +`['post' => $post]`. +Se tudo estiver certo, você chega a `author`, atribuído a John. + +No caso de Jane, é um pouco mais simples, já que ela é admin: + +![Verificação de acesso](/images/guide/security/rbac-access-check-3.svg +"Verificação de acesso") + +## Implementando seu próprio verificador de acesso + +Se o RBAC não atende às suas necessidades, você pode implementar seu próprio +verificador de acesso sem alterar o código da aplicação: + + +```php +namespace App\User; + +use \Yiisoft\Access\AccessCheckerInterface; + +final readonly class AccessChecker implements AccessCheckerInterface +{ + private const PERMISSIONS = [ + [ + 1 => ['editPost'], + 42 => ['editPost', 'deletePost'], + ], + ]; + + public function userHasPermission($userId, string $permissionName, array $parameters = []) : bool + { + if (!array_key_exists($userId, self::PERMISSIONS)) { + return false; + } + + return in_array($permissionName, self::PERMISSIONS[$userId], true); + } +} +``` diff --git a/src/pt-BR/guide/security/best-practices.md b/src/pt-BR/guide/security/best-practices.md new file mode 100644 index 00000000..a4fb35fe --- /dev/null +++ b/src/pt-BR/guide/security/best-practices.md @@ -0,0 +1,286 @@ +# Boas práticas de segurança + +A seguir, vamos revisar princípios comuns de segurança e descrever como +evitar ameaças ao desenvolver aplicações com o Yii. A maioria desses +princípios não é exclusiva do Yii e vale para o desenvolvimento de sites e +software em geral, por isso você também vai encontrar links para leitura +adicional sobre as ideias gerais por trás deles. + + +## Princípios básicos + +Há dois princípios principais quando o assunto é segurança, não importa qual +aplicação esteja sendo desenvolvida: + +1. Filtre a entrada. +2. Escape a saída. + + +### Filtre a entrada + +Filtrar a entrada significa que você nunca deve considerar uma entrada +segura e deve sempre verificar se o valor recebido está de fato entre os +permitidos. Por exemplo, se você sabe que a ordenação é feita por três +campos, `title`, `created_at` e `status`, e o campo vem da entrada do +usuário, é melhor verificar o valor no mesmo lugar em que você o recebe. Em +PHP puro, isso ficaria assim: + +```php +$sortBy = $_GET['sort']; +if (!in_array($sortBy, ['title', 'created_at', 'status'])) { + throw new \InvalidArgumentException('Invalid sort value.'); +} +``` + +No Yii, você provavelmente vai usar a validação de formulários para fazer +verificações parecidas. + +Leitura adicional sobre o assunto: + +- +- + + +### Escape a saída + +Escapar a saída significa que, dependendo do contexto em que você usa os dados, +você deve prefixá-los com caracteres especiais para anular seu significado especial. +No contexto de HTML, você deve escapar `<`, `>` e caracteres especiais semelhantes. +No contexto de JavaScript ou SQL, o conjunto de caracteres será outro. +Como escapar manualmente é propenso a erros, o Yii fornece várias ferramentas para fazer o escape em diferentes contextos. + +Leitura adicional sobre o assunto: + +- +- +- + + +## Evitando SQL injection + +SQL injection acontece quando você monta o texto de uma consulta +concatenando strings não escapadas, como a seguir: + +```php +$username = $_GET['username']; +$sql = "SELECT * FROM user WHERE username = '$username'"; +``` + +Em vez de informar um nome de usuário correto, um atacante pode passar para +sua aplicação algo como `'; DROP TABLE user; --`. O SQL resultante será o +seguinte: + +```sql +SELECT * FROM user WHERE username = ''; DROP TABLE user; --' +``` + +Essa é uma consulta válida, que vai buscar usuários com nome de usuário +vazio e depois apagar a tabela `user`, o que provavelmente resulta em um +site quebrado e perda de dados (você configurou backups regulares, certo?). + +Use prepared statements do PDO diretamente ou garanta que a biblioteca que +você prefere faça isso. Com prepared statements, é impossível manipular a +consulta como demonstrado acima. + +Se você usa dados para especificar nomes de colunas ou de tabelas, o melhor +é permitir apenas um conjunto predefinido de valores: + +```php +function actionList($orderBy = null) +{ + if (!in_array($orderBy, ['name', 'status'])) { + throw new \InvalidArgumentException('Only name and status are allowed to order by.'); + } + + // ... +} +``` + +Leitura adicional sobre o assunto: + +- + + +## Evitando XSS + +XSS, ou cross-site scripting, acontece quando a saída não é escapada corretamente ao enviar HTML para o navegador. Por exemplo, +se o usuário pode informar o nome dele e, em vez de `Alexander`, ele digita ``, toda página que +exibe o nome do usuário sem escapá-lo vai executar o JavaScript `alert('Hello!');`, fazendo uma caixa de alerta aparecer +no navegador. Dependendo do site, em vez de um alerta inofensivo, um script assim poderia enviar mensagens em seu nome ou até +fazer transações bancárias. + +Evitar XSS no Yii é bem fácil. Há dois casos: + +1. Você quer exibir os dados como texto puro. +2. Você quer exibir os dados como HTML. + +Se tudo o que você precisa é de texto puro, escapar é tão simples quanto o +seguinte: + + +```php + +``` + +Se precisar ser HTML, você pode ter a ajuda do +[HtmlPurifier](https://github.com/ezyang/htmlpurifier). Note que o +processamento do HtmlPurifier é bem pesado, então considere usar cache. + +Leitura adicional sobre o assunto: + +- + + +## Evitando CSRF + +CSRF é a sigla de cross-site request forgery (falsificação de requisição +entre sites). A ideia é que muitas aplicações assumem que as requisições +vindas do navegador de um usuário são feitas pelo próprio usuário. Essa +suposição pode ser falsa. + +Por exemplo, o site `an.example.com` tem uma URL `/logout` que, quando acessada com uma simples requisição GET, faz o logout do usuário. Enquanto +for o próprio usuário que faz a requisição, está tudo certo, mas um dia alguém mal-intencionado consegue publicar +`` em um fórum que o usuário visita com frequência. O navegador não faz diferença entre +requisitar uma imagem e requisitar uma página, então, quando o usuário abre uma página com essa tag `` manipulada, +o navegador envia a requisição GET para aquela URL e o usuário é deslogado de `an.example.com`. + +Essa é a ideia básica de como um ataque CSRF funciona. Alguém pode dizer que deslogar um usuário não é grave. +Porém, isso foi só um exemplo. +Há muito mais coisas que se pode fazer com essa abordagem. +Por exemplo, disparar pagamentos ou alterar dados. Imagine que um site tem uma URL +`http://an.example.com/purse/transfer?to=anotherUser&amount=2000`. Acessá-la com uma requisição GET causa a transferência de $2000 +da conta de um usuário autorizado para o usuário `anotherUser`. +Você sabe que o navegador sempre envia uma requisição GET para carregar uma imagem, +então pode alterar o código para aceitar apenas requisições POST nessa URL. +Infelizmente, isso não vai salvar você, porque um atacante +pode colocar algum código JavaScript no lugar da tag ``, o que permite enviar requisições POST para essa URL também. + +Por isso, o Yii aplica mecanismos extras para proteger contra ataques CSRF. + +Para evitar CSRF, você deve sempre: + +1. Seguir a especificação HTTP. GET não deve alterar o estado da aplicação. + Veja a [RFC2616](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html) + para mais detalhes. +2. Manter a proteção CSRF do Yii ativada. + +O Yii tem proteção CSRF via `Yiisoft\Csrf\CsrfTokenMiddleware`, do pacote +[`yiisoft/csrf`](https://github.com/yiisoft/csrf). Garanta que ele esteja +na pilha de middlewares da sua aplicação. Para backends AJAX/SPA que usam +autenticação baseada em cookie, o mesmo pacote fornece o +`Yiisoft\Csrf\CsrfHeaderMiddleware`, uma abordagem alternativa que depende +de headers de requisição personalizados e do mecanismo de preflight do CORS +em vez de um token no formulário. + +Leitura adicional sobre o assunto: + +- +- + + +## Evitando a exposição de arquivos + +Por padrão, o webroot do servidor deve apontar para o diretório `public`, onde fica o `index.php`. Em ambientes de hospedagem + compartilhada, isso pode ser impossível, e você acaba com todo o código, as configurações e os logs no webroot do servidor. + +Nesse caso, lembre-se de negar o acesso a tudo, exceto `web`. Se isso for +impossível, considere hospedar sua aplicação em outro lugar. + + +## Evitando informações e ferramentas de debug em produção + +No modo debug, o Yii mostra erros bem detalhados, que certamente ajudam no +desenvolvimento. O problema é que esses erros detalhados também são úteis +para um atacante, já que podem revelar a estrutura do banco de dados, +valores de configuração e partes do seu código. + +Nunca rode aplicações em produção com o debugger ou o Gii acessíveis a +todos. Alguém poderia usá-los para obter informações sobre a estrutura do +banco de dados e o código, ou simplesmente reescrever o código com o que o +Gii gera. + +Evite a barra de debug em produção, a menos que seja necessário. Ela expõe +todos os detalhes possíveis da aplicação e da configuração. Se você +realmente precisar dela, confira duas vezes se o acesso está restrito apenas +ao seu IP. + +Leitura adicional sobre o assunto: + +- +- + + +## Usando conexão segura via TLS + +O Yii fornece recursos que dependem de cookies e/ou sessões do PHP. Eles +podem ficar vulneráveis caso sua conexão seja comprometida. O risco diminui +se a aplicação usar conexão segura via TLS (muitas vezes chamado de +[SSL](https://en.wikipedia.org/wiki/Transport_Layer_Security)). + +Hoje em dia, qualquer pessoa pode obter um certificado de graça e renová-lo +automaticamente graças ao [Let's Encrypt](https://letsencrypt.org/). + +## Configuração segura do servidor + +O objetivo desta seção é destacar os riscos que precisam ser considerados ao +criar a configuração de um servidor para servir um site baseado em Yii. Além +dos pontos tratados aqui, pode haver outras opções de configuração +relacionadas à segurança a considerar, então não considere esta seção +completa. + +### Evitando ataques via header `Host` + +Se o servidor web estiver configurado para servir o mesmo site +independentemente do valor do header `Host`, essa informação pode não ser +confiável e [pode ser falsificada pelo usuário que envia a requisição +HTTP](https://www.acunetix.com/vulnerabilities/web/host-header-attack). +Nessas situações, você deve corrigir a configuração do servidor web para +servir o site apenas para os nomes de host especificados. + +Para mais informações sobre a configuração do servidor, consulte a +documentação do seu servidor web: + +- Apache 2: + +- Nginx: + + +### Configurando a validação SSL do peer + +Há um equívoco comum sobre como resolver problemas de validação de +certificado SSL, como: + +``` +cURL error 60: SSL certificate problem: unable to get local issuer certificate +``` + +ou + +``` +stream_socket_enable_crypto(): SSL operation failed with code 1. OpenSSL Error messages: error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed +``` + +Muitas fontes sugerem, erroneamente, desativar a verificação SSL do peer. +Isso nunca deve ser feito, porque abre caminho para ataques do tipo +man-in-the-middle. Em vez disso, o PHP deve ser configurado corretamente: + +1. Baixe + [https://curl.haxx.se/ca/cacert.pem](https://curl.haxx.se/ca/cacert.pem). +2. Adicione o seguinte ao seu php.ini: + ``` + openssl.cafile="/path/to/cacert.pem" + curl.cainfo="/path/to/cacert.pem". + ``` + +Note que você deve manter o arquivo atualizado. + +## Referências + +- [OWASP top 10](https://owasp.org/Top10/) +- [The Basics of Web Application + Security](https://martinfowler.com/articles/web-security-basics.html), de + Martin Fowler +- [Manual do PHP: segurança](https://www.php.net/manual/en/security.php) +- [Segurança da informação no + StackExchange](https://security.stackexchange.com/) + diff --git a/src/pt-BR/guide/security/cryptography.md b/src/pt-BR/guide/security/cryptography.md new file mode 100644 index 00000000..f2542d3d --- /dev/null +++ b/src/pt-BR/guide/security/cryptography.md @@ -0,0 +1,123 @@ +# Criptografia + +Nesta seção, vamos ver os seguintes aspectos de segurança: + +- Geração de dados aleatórios +- Cifrar e decifrar dados +- Confirmação da integridade dos dados + +Para usar esses recursos, você precisa instalar o pacote `yiisoft/security`: + +``` +composer install yiisoft/security +``` + +## Geração de dados pseudoaleatórios + +Dados pseudoaleatórios são úteis em muitas situações. Por exemplo, ao +redefinir uma senha por e-mail, você precisa gerar um token, salvá-lo no +banco de dados e enviá-lo por e-mail ao usuário final, o que permite a ele +provar que é o dono daquela conta. É importante que esse token seja único e +difícil de adivinhar; caso contrário, existe a possibilidade de um atacante +prever o valor do token e redefinir a senha do usuário. + +`\Yiisoft\Security\Random` torna simples gerar dados pseudoaleatórios: + +```php +$key = \Yiisoft\Security\Random::string(42); +``` + +O código acima gera uma string aleatória com 42 caracteres. + +Se você precisar de bytes ou inteiros, use as funções do PHP diretamente: + +- `random_bytes()` para bytes. Note que a saída pode não ser ASCII. +- `random_int()` para inteiros. + +## Cifrar e decifrar dados + +O Yii fornece funções auxiliares práticas para cifrar e decifrar dados +usando uma chave secreta. Os dados passam pela função de cifragem de modo +que apenas quem tem a chave secreta consiga decifrá-los. Por exemplo, você +precisa armazenar alguma informação no banco de dados, mas precisa garantir +que apenas o usuário que tem a chave secreta possa vê-la (mesmo que alguém +comprometa o banco de dados da aplicação): + +```php +$encryptedData = (new \Yiisoft\Security\Crypt())->encryptByPassword($data, $password); + +// salve os dados em um banco de dados ou outro armazenamento +saveData($encryptedData); +``` + +Para decifrar: + +```php +// obtenha os dados cifrados de um banco de dados ou outro armazenamento +$encryptedData = getEncryptedData(); + +$data = (new \Yiisoft\Security\Crypt())->decryptByPassword($encryptedData, $password); +``` + +Você pode usar uma chave em vez de uma senha: + +```php +$encryptedData = (new \Yiisoft\Security\Crypt())->encryptByKey($data, $key); + +// salve os dados em um banco de dados ou outro armazenamento +saveData($encryptedData); +``` + +Para decifrar: + +```php +// obtenha os dados cifrados de um banco de dados ou outro armazenamento +$encryptedData = getEncryptedData(); + +$data = (new \Yiisoft\Security\Crypt())->decryptByKey($encryptedData, $key); +``` + +## Confirmação da integridade dos dados + +Há situações em que você precisa verificar se seus dados não foram +adulterados por terceiros ou até corrompidos de alguma forma. O Yii oferece +uma maneira de confirmar a integridade dos dados por meio de assinatura MAC. + +A `$key` deve estar presente tanto no lado que envia quanto no que +recebe. No lado que envia: + +```php +$signedMessage = (new \Yiisoft\Security\Mac())->sign($message, $key); + +sendMessage($signedMessage); +``` + +No lado que recebe: + +```php +$signedMessage = receiveMessage($signedMessage); + +try { + $message = (new \Yiisoft\Security\Mac())->getMessage($signedMessage, $key); +} catch (\Yiisoft\Security\DataIsTamperedException $e) { + // os dados foram adulterados +} +``` + +## Mascaramento do comprimento do token + +Mascarar um token ajuda a mitigar um ataque BREACH, tornando aleatória a +forma como o token é exibido em cada requisição. Uma máscara aleatória é +aplicada ao token, fazendo com que a string seja sempre única. + +Para mascarar um token: + +```php +$maskedToken = \Yiisoft\Security\TokenMask::apply($token); +``` + +Para obter o valor original a partir do mascarado: + +```php +$token = \Yiisoft\Security\TokenMask::remove($maskedToken); +``` diff --git a/src/pt-BR/guide/security/overview.md b/src/pt-BR/guide/security/overview.md new file mode 100644 index 00000000..d37ea2ec --- /dev/null +++ b/src/pt-BR/guide/security/overview.md @@ -0,0 +1,19 @@ +# Segurança + +Uma boa segurança é vital para a saúde e o sucesso de qualquer +aplicação. Infelizmente, muitos desenvolvedores negligenciam a segurança, +seja por falta de entendimento, seja porque a implementação parece um +obstáculo grande demais. Para deixar sua aplicação Yii o mais segura +possível, o Yii inclui vários recursos de segurança excelentes e fáceis de +usar. + +* [Autenticação](authentication.md) +* [Autorização](authorization.md) +* [Trabalhando com senhas](passwords.md) +* [Criptografia](cryptography.md) +* [Boas práticas](best-practices.md) +* [Requisição confiável](trusted-request.md) + +Veja também: + +* [Segurança de views](../views/view.md#security) diff --git a/src/pt-BR/guide/security/passwords.md b/src/pt-BR/guide/security/passwords.md new file mode 100644 index 00000000..57ab89c8 --- /dev/null +++ b/src/pt-BR/guide/security/passwords.md @@ -0,0 +1,45 @@ +# Trabalhando com senhas + +A maioria dos desenvolvedores sabe que senhas não podem ser armazenadas em +texto puro, mas muitos ainda acreditam que é seguro gerar o hash de senhas +com `md5`, `sha1`, `sha256` etc. Houve um tempo em que esses algoritmos de +hash bastavam, mas o hardware moderno permite reverter esses hashes, e até +outros mais fortes, com ataques de força bruta. + +Para oferecer mais segurança às senhas dos usuários, mesmo no pior cenário +(quando alguém invade sua aplicação), você precisa usar um algoritmo de hash +resistente a ataques de força bruta. A melhor escolha atual é o `argon2`. +O pacote `yiisoft/security` do Yii facilita gerar e verificar hashes com +segurança e garante que a melhor solução de hash possível seja usada. + +Para usá-lo, primeiro instale o pacote: + +``` +composer require yiisoft/security +``` + +Quando um usuário fornece uma senha pela primeira vez (por exemplo, no +cadastro), é preciso gerar o hash da senha e armazená-lo: + + +```php +$hash = (new PasswordHasher())->hash($password); + +// salve o hash em um banco de dados ou outro armazenamento +saveHash($hash); +``` + +Quando um usuário tenta fazer login, a senha enviada deve ser verificada +contra o hash armazenado anteriormente: + + +```php +// obtenha o hash de um banco de dados ou outro armazenamento +$hash = getHash(); + +if ((new PasswordHasher())->validate($password, $hash)) { + // tudo certo, fazendo login do usuário +} else { + // senha incorreta +} +``` diff --git a/src/pt-BR/guide/security/trusted-request.md b/src/pt-BR/guide/security/trusted-request.md new file mode 100644 index 00000000..fc6a0e46 --- /dev/null +++ b/src/pt-BR/guide/security/trusted-request.md @@ -0,0 +1,44 @@ +# Requisição confiável + +Obter informações do usuário, como host e endereço IP, funciona de imediato +em uma configuração normal, em que um único servidor web atende o +site. Porém, se sua aplicação Yii roda atrás de um proxy reverso, você +precisa adicionar configuração para obter essas informações, já que o +cliente direto passa a ser o proxy e o endereço IP do usuário é repassado +para a aplicação Yii por um header definido pelo proxy. + +Você não deve confiar cegamente nos headers fornecidos por proxies, a menos +que confie explicitamente no proxy. O Yii permite configurar proxies +confiáveis via `Yiisoft\Yii\Web\Middleware\TrustedHostsNetworkResolver`. +Você deve adicioná-lo à [pilha de middlewares](../structure/middleware.md). + +A seguir está uma configuração de requisição para uma aplicação que roda +atrás de um conjunto de proxies reversos localizados na rede IP +`10.0.2.0/24`: + +```php +/** @var \Yiisoft\Yii\Web\Middleware\TrustedHostsNetworkResolver $trustedHostsNetworkResolver */ +$trustedHostsNetworkResolver = $trustedHostsNetworkResolver->withAddedTrustedHosts(['1.0.2.0/24']); +``` + +Por padrão, o proxy envia o IP no header `X-Forwarded-For` e o protocolo +(`http` ou `https`) em `X-Forwarded-Proto`. + +Caso seus proxies usem headers diferentes, você pode ajustá-los na +configuração da requisição, por exemplo: + +```php +/** @var \Yiisoft\Yii\Web\Middleware\TrustedHostsNetworkResolver $trustedHostsNetworkResolver */ +$trustedHostsNetworkResolver = $trustedHostsNetworkResolver + ->withAddedTrustedHosts( + ['1.0.2.0/24'], + ['X-ProxyUser-Ip'], + ['Front-End-Https'], + [], + [], + ['X-Proxy-User-Ip'] + ); +``` + +Com a configuração acima, os headers `X-ProxyUser-Ip` e `Front-End-Https` +são usados para obter o IP e o protocolo do usuário. diff --git a/src/pt-BR/guide/start/creating-project.md b/src/pt-BR/guide/start/creating-project.md new file mode 100644 index 00000000..21d3bf86 --- /dev/null +++ b/src/pt-BR/guide/start/creating-project.md @@ -0,0 +1,67 @@ +# Criando um projeto + +Neste guia mostramos os comandos tanto para o +[Docker](https://docs.docker.com/get-started/get-docker/) quanto para o +servidor de desenvolvimento embutido, com tudo instalado localmente. + +> [!NOTE] +> Se você quiser usar outro servidor web, +> veja ["Configurando servidores web"](../../cookbook/configuring-webservers/general.md). + +Recomendamos começar com um template de projeto, que é um projeto Yii mínimo +e funcional com alguns recursos básicos. Ele serve como um bom ponto de +partida para os seus projetos. + +Você pode criar um novo projeto a partir de um template usando o gerenciador +de pacotes [Composer](https://getcomposer.org): + +```sh +composer create-project yiisoft/app your_project +``` + +Quem usa Docker pode rodar os seguintes comandos: + +```sh +docker run --rm -it -v "$(pwd):/app" --user $(id -u):$(id -g) composer/composer create-project yiisoft/app your_project +sudo chown -R $(id -u):$(id -g) your_project +cd your_project +make composer update +``` + +Se você quiser a versão de desenvolvimento em vez da versão de release: + +```sh +git clone https://github.com/yiisoft/app.git --depth 1 your_project && \ +cd your_project && \ +rm -rf .git && \ +make composer update +``` + +Isso instala a versão estável mais recente do template de projeto do Yii em +um diretório chamado `your_project`. Você pode escolher outro nome de +diretório se quiser. + +> [!TIP] +> Se você quiser instalar a versão de desenvolvimento mais recente do Yii, pode adicionar `--stability=dev` ao comando. +> Não use a versão de desenvolvimento do Yii em produção, porque ela pode quebrar o seu código em execução. + +Entre no diretório recém-criado, copie `.env.example` para `.env` e rode: + +```sh +./yii serve --port=80 +``` + +Se você usa Docker, rode: + +```sh +make up +``` + +Abra no navegador a URL `http://localhost/`. + +> [!NOTE] +> Para mudar a porta do servidor embutido, passe `--port` para `./yii serve`. No Docker, defina `DEV_PORT` +> em `docker/.env`. + +![Instalação do Yii concluída com +sucesso](/images/guide/start/app-installed.png) diff --git a/src/pt-BR/guide/start/databases.md b/src/pt-BR/guide/start/databases.md new file mode 100644 index 00000000..b83a4d5d --- /dev/null +++ b/src/pt-BR/guide/start/databases.md @@ -0,0 +1,912 @@ +# Trabalhando com bancos de dados + +O Yii não impõe um banco de dados ou armazenamento específico para a sua +aplicação. Há muitas formas de trabalhar com bancos de dados relacionais: + +- [Yii DB](https://github.com/yiisoft/db) +- [Yii Active Record](https://github.com/yiisoft/active-record) +- [Cycle](https://github.com/cycle) pelo [pacote Yii + Cycle](https://github.com/yiisoft/yii-cycle) +- [Doctrine](https://www.doctrine-project.org/) pelo [pacote Yii + Doctrine](https://github.com/stargazer-team/yii-doctrine) +- [PDO](https://www.php.net/manual/en/book.pdo.php) + +Para os não relacionais, geralmente existem bibliotecas oficiais: + +- [ElasticSearch](https://github.com/elastic/elasticsearch-php) +- [Redis](https://redis.io/docs/latest/develop/clients/php/) +- ... + +## Escolhendo uma forma de acesso aos dados + +O Yii3 deixa o acesso ao banco de dados em pacotes opcionais. Uma aplicação nova não ganha automaticamente um componente global `Yii::$app->db` +nem uma camada de Active Record embutida, então escolha o pacote e a fronteira que fazem sentido para a sua aplicação. + +Se você usava a camada de acesso ao banco de dados do Yii 2.0, o `yiisoft/db` é o equivalente mais próximo no Yii3. Ele oferece +conexões, comandos, suporte a esquema e um query builder. Em vez de chamar `Yii::$app->db`, configure uma +conexão como serviço e injete `ConnectionInterface` onde o banco de dados for necessário. + +Se você usava o Active Record do Yii 2.0, pode instalar o +`yiisoft/active-record`. Ele é útil quando suas classes de model descrevem +principalmente tabelas e relações. Em aplicações em que as classes Active +Record do Yii 2.0 também contêm validação de formulário, cenários de +requisição, verificações de autorização ou fluxos de negócio, mova essas +responsabilidades para form models, serviços e objetos de domínio em vez de +colocá-las de volta na classe do registro. + +Na maior parte do código da aplicação, coloque um repositório ou serviço de +consulta entre a camada de actions/serviços e o armazenamento: + +- actions e serviços da aplicação dependem de métodos do repositório como + `findOneBySlug()`, `findAll()`, `save()` e `deleteBySlug()`; +- o repositório esconde se a persistência é feita com `yiisoft/db`, Active + Record, Cycle, Doctrine ou outro armazenamento; +- o repositório é o lugar para converter as linhas brutas do banco de dados + ou os registros em objetos tipados usados pelo resto do código. + +Aplicações CRUD pequenas podem começar com uma classe de repositório +concreta. Aplicações maiores costumam se beneficiar de uma interface de +repositório no domínio ou módulo e de uma implementação na camada de +infraestrutura. + +Neste guia, vamos focar no trabalho com bancos de dados relacionais usando o +Yii DB. Vamos usar PostgreSQL para implementar um CRUD simples (create, +read, update, delete: criar, ler, atualizar e excluir). + +## Instalando o PostgreSQL + +Você precisa instalar o PostgreSQL. Se preferir não usar Docker, [baixe o +instalador no site oficial](https://www.postgresql.org/download/), instale e +crie um banco de dados. + +Se você usa Docker, é um pouco mais simples. Altere +`docker/dev/compose.yml`: + +```yaml +services: + app: + build: + dockerfile: docker/Dockerfile + context: .. + target: dev + args: + USER_ID: ${UID} + GROUP_ID: ${GID} + env_file: + - path: ./dev/.env + - path: ./dev/override.env + required: false + ports: + - "${DEV_PORT:-80}:80" + volumes: + - ../:/app + - ../runtime:/app/runtime + - caddy_data:/data + - caddy_config:/config + tty: true + depends_on: + db: + condition: service_healthy + + db: + image: postgres:${POSTGRES_VERSION:-18}-alpine + environment: + POSTGRES_DB: app + POSTGRES_PASSWORD: password + POSTGRES_USER: user + POSTGRES_INITDB_ARGS: "--locale-provider=icu --icu-locale=und --encoding=UTF8" + volumes: + - ../runtime/db:/var/lib/postgresql:rw + ports: + - "${DEV_DB_PORT:-5432}:5432" + healthcheck: + test: [ "CMD-SHELL", "pg_isready -U user -d app" ] + interval: 5s + timeout: 5s + retries: 5 +``` + +Repare que adicionamos `depends_on` para que a aplicação espere o banco de +dados subir. + +> [!IMPORTANT] +> Também vamos precisar da extensão `pdo_pgsql` para falar com o PostgreSQL. Você pode habilitá-la localmente no `php.ini`. + +Se você usa Docker, abra `docker/Dockerfile` e adicione `pdo_pgsql` à lista +do `install-php-extensions`: + +```dockerfile +RUN install-php-extensions \ + opcache \ + mbstring \ + intl \ + dom \ + ctype \ + curl \ + phar \ + openssl \ + xml \ + xmlwriter \ + simplexml \ + pdo \ + pdo_pgsql +``` + +Depois, reconstrua a imagem do PHP com + +```sh +make build && make down && make up +``` + +## Configurando a conexão + +Agora que temos o banco de dados, é hora de definir a conexão. + +Primeiro, precisamos instalar um pacote: + +```sh +make composer require yiisoft/db-pgsql:2.* +``` + +Agora crie `config/common/di/db-pgsql.php`: + +```php + [ + 'class' => Connection::class, + '__construct()' => [ + 'driver' => new Driver( + $params['yiisoft/db-pgsql']['dsn'], + $params['yiisoft/db-pgsql']['username'], + $params['yiisoft/db-pgsql']['password'], + ), + ], + ], +]; +``` + +E defina os parâmetros em `config/common/params.php`. Para o Docker, fica +assim: + +```php +use Yiisoft\Db\Pgsql\Dsn; + +return [ + // ... + 'yiisoft/db-pgsql' => [ + 'dsn' => new Dsn('pgsql', 'db', 'app', '5432'), + 'username' => 'user', + 'password' => 'password', + ], +]; +``` + +O host `db` é resolvido automaticamente dentro da rede do Docker. + +Em uma instalação local sem Docker, o host no Dsn seria `localhost`. Ajuste +o resto conforme a forma como você configurou o banco de dados. + +### Várias conexões de banco de dados + +Quando a aplicação trabalha com vários bancos de dados, mantenha +`ConnectionInterface` para a conexão principal e adicione um alias de classe +para cada conexão nomeada: + +```php + MainDatabase::class, + + MainDatabase::class => [ + 'class' => Connection::class, + '__construct()' => [ + 'driver' => new Driver( + $params['app/db']['main']['dsn'], + $params['app/db']['main']['username'], + $params['app/db']['main']['password'], + ), + ], + ], + + AnalyticsDatabase::class => [ + 'class' => Connection::class, + '__construct()' => [ + 'driver' => new Driver( + $params['app/db']['analytics']['dsn'], + $params['app/db']['analytics']['username'], + $params['app/db']['analytics']['password'], + ), + ], + ], +]; +``` + +Os nomes das classes alias são usados como IDs de serviço e type hints. Eles +não precisam de arquivos PHP próprios. + +Defina os parâmetros correspondentes: + +```php +use Yiisoft\Db\Pgsql\Dsn; + +return [ + // ... + 'app/db' => [ + 'main' => [ + 'dsn' => new Dsn('pgsql', 'db', 'app', '5432'), + 'username' => 'user', + 'password' => 'password', + ], + 'analytics' => [ + 'dsn' => new Dsn('pgsql', 'analytics-db', 'analytics', '5432'), + 'username' => 'analytics_user', + 'password' => 'analytics_password', + ], + ], +]; +``` + +Serviços que precisam do banco de dados principal continuam podendo depender +de `ConnectionInterface`. Serviços que precisam de outro banco de dados +devem usar o alias correspondente como type hint: + +```php + [ + 'newMigrationNamespace' => 'App\\Migration', + 'sourceNamespaces' => ['App\\Migration'], +], +``` + +Agora você pode usar `make yii migrate:create page` para criar uma nova +migration. No nosso exemplo, precisamos de uma tabela `page` com algumas +colunas: + +```php +columnBuilder(); + + $b->createTable('page', [ + 'id' => $column::uuidPrimaryKey(), + 'title' => $column::string()->notNull(), + 'slug' => $column::string()->notNull()->unique(), + 'text' => $column::text()->notNull(), + 'created_at' => $column::dateTime(), + 'updated_at' => $column::dateTime(), + ]); + } + + public function down(MigrationBuilder $b): void + { + $b->dropTable('page'); + } +} +``` + +O nome `M251102141707Page` da classe da migration é gerado, então substitua +o sufixo `Page` pelo nome real da migration. O prefixo `M251102141707` é +necessário para encontrar e ordenar as migrations na ordem em que foram +adicionadas. + +Repare que usamos UUID como chave primária. Vamos gerar esses IDs nós +mesmos, em vez de depender do banco de dados, então precisamos de um pacote +extra do Composer para isso. + +```shell +make composer require ramsey/uuid +``` + +O espaço de armazenamento é um pouco maior do que com int, mas o fluxo de +trabalho com esse tipo de ID compensa. Como você mesmo gera o ID, pode +definir um conjunto de dados relacionados e salvá-lo em uma única +transação. As entidades que definem esse conjunto de dados no código +costumam ser chamadas de "agregado". + +Aplique a migration com `make yii migrate:up`. + +## Uma entidade + +Agora que você tem uma tabela, é hora de definir uma entidade no +código. Crie `src/Web/Page/Page.php`: + +```php +toSlug($title), + text: $text, + createdAt: $createdAt, + updatedAt: $updatedAt, + ); + } +} +``` + +## Repositório + +Agora que temos uma entidade, precisamos de um lugar para os métodos que a +salvam, a excluem e selecionam uma única página ou várias. Essa é a +fronteira de repositório descrita antes: o resto da aplicação trabalha com +objetos `Page` e não precisa saber como eles são armazenados. + +Crie `src/Web/Page/PageRepository.php`: + +```php + $page->id, + 'title' => $page->title, + 'slug' => $page->slug, + 'text' => $page->text, + 'created_at' => $page->createdAt, + 'updated_at' => $page->updatedAt, + ]; + + if ($this->exists($page->id)) { + $this->connection->createCommand()->update('{{%page}}', $row, ['id' => $page->id])->execute(); + } else { + $this->connection->createCommand()->insert('{{%page}}', $row)->execute(); + } + } + + public function findOneBySlug(string $slug): ?Page + { + $query = $this->connection + ->select() + ->from('{{%page}}') + ->where('slug = :slug', ['slug' => $slug]); + + return $this->createPage($query->one()); + } + + /** + * @return iterable + */ + public function findAll(): iterable + { + $rows = $this->connection + ->select() + ->from('{{%page}}') + ->all(); + + foreach ($rows as $row) { + yield $this->createPage($row); + } + } + + private function createPage(?array $row): ?Page + { + if ($row === null) { + return null; + } + + return Page::create( + id: $row['id'], + title: $row['title'], + text: $row['text'], + slug: $row['slug'], + createdAt: new DateTimeImmutable($row['created_at']), + updatedAt: new DateTimeImmutable($row['updated_at']), + ); + } + + public function deleteBySlug(string $slug): void + { + $this->connection->createCommand()->delete( + '{{%page}}', + ['slug' => $slug], + )->execute(); + } + + public function exists(string $id): bool + { + return $this->connection->createQuery() + ->from('{{%page}}') + ->where(['id' => $id]) + ->exists(); + } +} +``` + +Neste repositório há tanto métodos para buscar dados quanto o `save()`, que +faz insert ou update. O DB retorna os dados brutos como arrays, mas o nosso +repositório cria entidades automaticamente a partir deles, e daí em diante +trabalhamos com dados tipados. + +## Actions e rotas + +Precisamos de algumas actions para: + +1. Listar todas as páginas. +2. Ver uma página. +3. Excluir uma página. +4. Criar uma página. +5. Atualizar uma página. + +Depois, precisamos do roteamento para tudo isso. + +Vamos resolver uma coisa de cada vez. + +### Listar todas as páginas + +Crie `src/Web/Page/ListAction.php`: + +```php +viewRenderer->render(__DIR__ . '/list', [ + 'pages' => $this->pageRepository->findAll(), + ]); + } +} +``` + +Defina a view da lista em `src/Web/Page/list.php`: + +```php + $pages */ +/** @var UrlGeneratorInterface $urlGenerator */ +?> + +
    + +
  • + title, $urlGenerator->generate('page/view', ['slug' => $page->slug])) ?> +
  • + +
+ +generate('page/edit', ['slug' => 'new'])) ?> +``` + +### Ver uma página + +Crie `src/Web/Page/ViewAction.php`: + +```php +pageRepository->findOneBySlug($slug); + if ($page === null) { + return $this->responseFactory->createResponse(Status::NOT_FOUND); + } + + return $this->viewRenderer->render(__DIR__ . '/view', [ + 'page' => $page, + ]); + } +} +``` + +Agora, um template em `src/Web/Page/view.php`: + +```php + + +

generate('page/list')) ?> → title) ?>

+ +

+ text) ?> +

+ +generate('page/edit', ['slug' => $page->slug])) ?> | + + +post($urlGenerator->generate('page/delete', ['slug' => $page->slug])) + ->csrf($csrf); +?> +open() ?> + +close() ?> +``` + +Nesta view há um formulário que envia uma requisição para excluir a +página. Tratar isso com `GET` também é comum, mas é muito errado. Como a +exclusão altera dados, ela precisa ser tratada por um dos métodos HTTP não +idempotentes. No nosso exemplo usamos POST e um formulário, mas poderia ser +`DELETE` e uma requisição assíncrona feita com JavaScript. Depois, o botão +pode ganhar um estilo adequado para ficar parecido com o "Edit". + +### Excluir uma página + +Crie `src/Web/Page/DeleteAction.php`: + +```php +pageRepository->deleteBySlug($slug); + + return $this->responseFactory + ->createResponse(Status::SEE_OTHER) + ->withHeader('Location', $this->urlGenerator->generate('page/list')); + } +} +``` + +### Criar ou atualizar uma página + +Antes de tudo, precisamos de um formulário em `src/Web/Page/Form.php`: + +```php +findOneBySlug($slug); + if ($page === null) { + return $this->responseFactory->createResponse(Status::NOT_FOUND); + } + + $form->title = $page->title; + $form->text = $page->text; + } + + $this->formHydrator->populateFromPostAndValidate($form, $request); + + if ($form->isValid()) { + $id = $isNew ? Uuid::uuid7()->toString() : $page->id; + + $page = Page::create( + id: $id, + title: $form->title, + text: $form->text, + ); + + $pageRepository->save($page); + + return $this->responseFactory + ->createResponse(Status::SEE_OTHER) + ->withHeader( + 'Location', + $this->urlGenerator->generate('page/view', ['slug' => $page->slug]), + ); + } + + return $this->viewRenderer->render(__DIR__ . '/edit', [ + 'form' => $form, + 'isNew' => $isNew, + 'slug' => $slug, + ]); + } +} +``` + +Repare que `Uuid::uuid7()->toString()` não funciona no MySQL; lá você vai precisar dos bytes, com `Uuid::uuid7()->getBytes()`. + +Acima, usamos um slug especial na URL para páginas novas, então a URL fica +como `http://localhost/pages/new`. Se a página não for nova, preenchemos o +formulário com os dados do banco de dados. Assim como fizemos em +[Trabalhando com formulários](forms.md), tratamos o envio do +formulário. Depois de salvar com sucesso, redirecionamos para a view da +página. + +Agora, um template em `src/Web/Page/edit.php`: + +```php +post($urlGenerator->generate('page/edit', ['slug' => $slug])) + ->csrf($csrf); +?> + +open() ?> + required() ?> + required() ?> + +close() ?> +``` + +### Roteamento + +Ajuste `config/common/routes.php`: + +```php +routes( + Route::get('/') + ->action(Web\HomePage\Action::class) + ->name('home'), + Route::methods([Method::GET, Method::POST], '/say') + ->action(Web\Echo\Action::class) + ->name('echo/say'), + + Group::create('/pages')->routes( + Route::get('') + ->action(Web\Page\ListAction::class) + ->name('page/list'), + Route::get('/{slug}') + ->action(Web\Page\ViewAction::class) + ->name('page/view'), + Route::methods([Method::GET, Method::POST], '/{slug}/edit') + ->action(Web\Page\EditAction::class) + ->name('page/edit'), + Route::post('/{slug}/delete') + ->action(Web\Page\DeleteAction::class) + ->name('page/delete'), + ), + ), +]; +``` + +Repare que agrupamos todas as rotas relacionadas a páginas em um grupo com o +prefixo `/pages`. É uma forma prática de não se repetir e também de +adicionar algum middleware extra, como autenticação, ao grupo inteiro. + +## Testando + +Agora teste abrindo `http://localhost/pages` no navegador. diff --git a/src/pt-BR/guide/start/demo-apps.md b/src/pt-BR/guide/start/demo-apps.md new file mode 100644 index 00000000..9fcb85a7 --- /dev/null +++ b/src/pt-BR/guide/start/demo-apps.md @@ -0,0 +1,24 @@ +# Aplicações de demonstração + +Existem várias aplicações de demonstração que mostram diferentes abordagens +de arquitetura e recursos do framework. + +**[Demo Blog](https://github.com/yiisoft/demo-blog) — Arquitetura DDD em camadas** + +Uma aplicação de blog que demonstra uma arquitetura em camadas seguindo os +princípios do Domain-Driven Design (DDD). Esta demo é um bom ponto de +partida se você quer aprender a estruturar uma aplicação Yii3 com uma +separação clara de responsabilidades entre as camadas de domínio, aplicação +e infraestrutura. + +**[Demo Diary](https://github.com/yiisoft/demo-diary) — Arquitetura de vertical slices** + +Uma aplicação de diário construída com o padrão de arquitetura de vertical +slices. Nessa abordagem, cada funcionalidade é implementada de ponta a +ponta em vez de ser dividida em camadas horizontais, o que facilita +adicionar ou modificar funcionalidades de forma independente. + +**[Demo Summarizer](https://github.com/yiisoft/demo-summarizer) — Resumidor de documentos com modelo de linguagem (LLM)** + +Uma demo executável do Yii3 para enviar documentos, extrair Markdown +legível, resumir o conteúdo e acompanhar o progresso do processamento. diff --git a/src/pt-BR/guide/start/forms.md b/src/pt-BR/guide/start/forms.md new file mode 100644 index 00000000..caf61cb7 --- /dev/null +++ b/src/pt-BR/guide/start/forms.md @@ -0,0 +1,429 @@ +# Trabalhando com formulários + +Esta seção continua a melhorar o "Dizendo olá". Em vez de usar a URL, agora +você vai pedir a mensagem ao usuário por meio de um formulário. + +Neste tutorial, você vai aprender a: + +* Criar um form model para representar os dados que o usuário informa em um + formulário. +* Declarar regras para validar os dados informados. +* Montar um formulário HTML em uma view. + +## Instalando o pacote de formulários + +Para instalar o pacote de formulários, rode o seguinte comando no diretório +da sua aplicação: + +``` +composer require yiisoft/form-model +``` + +No Docker, fica assim: + +``` +make composer require yiisoft/form-model +``` + +## Criando um formulário + +Os dados que serão pedidos ao usuário ficam representados por uma classe +`Form`, como mostrado abaixo, salva no arquivo `/src/Web/Echo/Form.php`: + +```php + Nota: os atributos de validação são regras do Yii Validator. Para verificações comuns, procure primeiro uma regra existente. Se um campo +> também precisar de validação específica da aplicação, use `Callback` para essa lógica de domínio. Com atributos PHP, use a opção `method`, +> porque atributos PHP não podem conter closures. Por exemplo, valide a sintaxe do UUID com `Uuid` e só então adicione +> `#[Callback(method: 'validateUuidV7', skipOnError: true)]` quando o seu domínio exigir especificamente UUID versão 7. + +```php +use Yiisoft\Validator\Result; +use Yiisoft\Validator\Rule\Callback; +use Yiisoft\Validator\Rule\Uuid; + +#[Uuid(skipOnError: true)] +#[Callback(method: 'validateUuidV7', skipOnError: true)] +public string $id = ''; + +private function validateUuidV7(mixed $value): Result +{ + return \App\Support\Uuid::isVersion7($value) + ? new Result() + : (new Result())->addError('ID must be a UUID version 7.'); +} +``` + +O método de callback retorna um `Result`: retorne um resultado vazio quando +o valor for válido ou adicione um erro quando não for. O corpo do método +pode chamar qualquer código de validação que a sua aplicação já usa, como +`App\Support\Uuid::isValid($value, 'v7')`. Veja os [detalhes da regra +Callback](https://github.com/yiisoft/validator/blob/master/docs/guide/en/built-in-rules-callback.md) +para exemplos completos e as assinaturas de método disponíveis. + +Para uma lógica de validação reaproveitada em vários formulários, crie uma +regra e um handler personalizados do Yii Validator em vez de copiar métodos +de callback. Veja o [guia de regras +personalizadas](https://github.com/yiisoft/validator/blob/master/docs/guide/en/creating-custom-rules.md) +para a estrutura de regra/handler. + +## Validação personalizada + +Os atributos de validação são regras do Yii Validator. Para verificações +comuns, procure primeiro uma regra existente. Por exemplo, para validar uma +string UUID, use `Uuid`: + +```php +use Yiisoft\FormModel\FormModel; +use Yiisoft\Validator\Rule\Uuid; + +final class Form extends FormModel +{ + #[Uuid] + public string $id = ''; +} +``` + +Quando um campo precisa de uma validação específica da aplicação que nenhuma +regra embutida cobre, use `Callback`. Isso é útil para verificações pontuais +ou para delegar a um método do domínio ou de uma biblioteca. Com atributos +PHP, use a opção `method`, porque atributos PHP não podem conter +closures. Por exemplo, o formulário a seguir valida o dígito verificador de +um número de cartão: + +```php +addError('Card number must be a string.'); + } + + $digits = str_replace([' ', '-'], '', $value); + + if ($digits === '' || !ctype_digit($digits)) { + return (new Result())->addError('Card number must contain digits only.'); + } + + $sum = 0; + $double = false; + + foreach (array_reverse(str_split($digits)) as $digit) { + $number = (int) $digit; + + if ($double) { + $number *= 2; + if ($number > 9) { + $number -= 9; + } + } + + $sum += $number; + $double = !$double; + } + + if ($sum % 10 !== 0) { + return (new Result())->addError('Card number checksum is invalid.'); + } + + return new Result(); + } +} +``` + +O método de callback retorna um `Result`: retorne um resultado vazio quando +o valor for válido ou adicione um erro quando não for. O corpo do método +pode chamar qualquer código de validação que a sua aplicação já usa, como +`App\Payment\CardNumber::hasValidChecksum($value)`. + +Para uma lógica de validação reaproveitada em vários formulários, crie uma +regra e um handler personalizados do Yii Validator em vez de copiar métodos +de callback. Veja o [guia de regras +personalizadas](https://github.com/yiisoft/validator/blob/master/docs/guide/en/creating-custom-rules.md) +para a estrutura de regra/handler. + +## Validando vários campos juntos + +Atributos nas propriedades bastam quando cada campo pode ser validado de +forma independente. Quando uma regra depende de vários campos, coloque uma +regra `Callback` na classe do form model e associe o erro ao campo que deve +exibi-lo. + +Por exemplo, um filtro de relatório pode exigir que a data inicial seja +anterior ou igual à data final: + +```php +dateFrom === '' || $this->dateTo === '') { + return $result; + } + + $dateFrom = $this->parseDate($this->dateFrom); + $dateTo = $this->parseDate($this->dateTo); + + if ($dateFrom === null || $dateTo === null) { + return $result; + } + + if ($dateFrom > $dateTo) { + $result->addError('The start date must be earlier than or equal to the end date.', [], ['dateFrom']); + } + + return $result; + } + + private function parseDate(string $value): ?DateTimeImmutable + { + $date = DateTimeImmutable::createFromFormat('!Y-m-d', $value); + $errors = DateTimeImmutable::getLastErrors(); + + if ($date === false || ($errors !== false && ($errors['warning_count'] > 0 || $errors['error_count'] > 0))) { + return null; + } + + return $date; + } +} +``` + +O `Callback` no nível da classe recebe o objeto inteiro como `$value`, mas +usar `$this` costuma ser mais claro em um método do form model. Retornar um +`Result` vazio significa que a regra entre campos passou. O terceiro +argumento de `addError()` é o caminho do valor; `['dateFrom']` faz o erro +aparecer no campo `dateFrom` quando o formulário é renderizado. + +## Usando o formulário + +Agora que você tem um formulário, use-o na sua action do "[Dizendo +olá](hello.md)". + +Este é o resultado final em `/src/Web/Echo/Action.php`: + +```php +formHydrator->populateFromPostAndValidate($form, $request); + + return $this->viewRenderer->render(__DIR__ . '/template', [ + 'form' => $form, + ]); + } +} +``` + +Em vez de ler da rota, você preenche o formulário com os dados POST da +requisição e o valida com a ajuda do `FormHydrator`. Depois, passa o +formulário para a view. + +Para o formulário funcionar, precisamos permitir tanto GET, para renderizar +o formulário, quanto POST, para enviar os dados. Ajuste a sua rota em +`config/common/routes.php`: + +```php +routes( + Route::get('/') + ->action(Web\HomePage\Action::class) + ->name('home'), + Route::methods([Method::GET, Method::POST], '/say') + ->action(Web\Echo\Action::class) + ->name('echo/say'), + ), +]; +``` + +## Ajustando a view + +Para renderizar um formulário, você precisa alterar a sua view, +`src/Web/Echo/template.php`: + +```php +post($urlGenerator->generate('echo/say')) + ->csrf($csrf); +?> + +open() ?> + required() ?> + +close() ?> + +isValid()): ?> + Echo said: message) ?> + +``` + +Se o formulário for válido, você exibe uma mensagem. O restante inicializa e +renderiza o formulário. + +Primeiro, você inicializa `$htmlForm` com o tipo POST e a URL da action +gerada com a ajuda do gerador de URLs. Você pode acessá-lo como +`$urlGenerator` em todas as views. Também precisa passar o token CSRF para o +formulário, que também está disponível em toda view como `$csrf` graças às +view injections listadas em `config/common/params.php`: + +```php +'yiisoft/yii-view-renderer' => [ + 'injections' => [ + Reference::to(CsrfViewInjection::class), + ], +], +``` + +O template renderiza o valor do token CSRF como um input oculto para +garantir que a requisição vem da página do formulário e não de outro +site. Ele é enviado junto com os dados POST do formulário. Sem ele, o +resultado seria o [código de resposta HTTP +422](https://tools.ietf.org/html/rfc4918#section-11.2). + +Você usa `Field::text()` para exibir o campo "message", então ele cuida de +preencher o valor, escapá-lo e renderizar o label do campo e os erros de +validação. + +Agora, se você enviar uma mensagem vazia, vai receber um erro de validação: +"The message to be echoed must contain at least 2 characters." + +## Testando + +Para ver como funciona, acesse a seguinte URL no navegador: + +``` +http://localhost:8080/say +``` + +Você vai ver uma página com um campo de formulário e um label indicando qual +dado informar. O formulário também tem um botão "submit" com o texto +"Say". Se você clicar no botão "submit" sem digitar nada, vai ver que o +campo é obrigatório. Se digitar um único caractere, o formulário mostra uma +mensagem de erro ao lado do campo com problema. + +![Formulário com erro de validação](/images/guide/start/form-error.png) + +Depois de digitar uma mensagem válida e clicar no botão "submit", a página +mostra de volta os dados que você digitou. + +![Formulário com mensagem de sucesso](/images/guide/start/form-success.png) + +## Resumo + +Nesta seção do guia, você aprendeu a criar uma classe de form model para +representar os dados do usuário e validar esses dados. + +Você também aprendeu a receber dados dos usuários e a exibi-los de volta no +navegador. Essa é uma tarefa que pode tomar muito tempo no desenvolvimento +de uma aplicação, mas o Yii oferece widgets poderosos que a tornam fácil. + +Na próxima seção, você vai aprender a trabalhar com bancos de dados, que são +necessários em quase toda aplicação. diff --git a/src/pt-BR/guide/start/gii.md b/src/pt-BR/guide/start/gii.md new file mode 100644 index 00000000..f07d8fbd --- /dev/null +++ b/src/pt-BR/guide/start/gii.md @@ -0,0 +1,4 @@ +# Gerando código com o Gii + +> [!NOTE] +> O Gii está em desenvolvimento e vai ficar disponível mais tarde. diff --git a/src/pt-BR/guide/start/hello.md b/src/pt-BR/guide/start/hello.md new file mode 100644 index 00000000..9d13038d --- /dev/null +++ b/src/pt-BR/guide/start/hello.md @@ -0,0 +1,192 @@ +# Dizendo olá + +Esta seção descreve como criar uma nova página "Hello" na sua aplicação. É +uma página simples que devolve o que você passar para ela ou, se nada for +passado, apenas diz "Hello!". + +Para isso, você vai definir uma rota e criar [um +handler](../structure/action.md) que faz o trabalho e monta a resposta. +Depois, vai melhorá-lo para usar uma [view](../views/view.md) na construção +da resposta. + +Neste tutorial, você vai aprender três coisas: + +1. Como criar um handler para responder a uma requisição. +2. Como mapear uma URL para o handler. +3. Como usar uma [view](../views/view.md) para compor o conteúdo da + resposta. + +## Criando um handler + +Para a tarefa "Hello", você vai criar uma classe handler que lê o parâmetro +`message` da requisição e mostra essa mensagem de volta para o usuário. Se a +requisição não trouxer o parâmetro `message`, a action mostra a mensagem +padrão "Hello". + +Crie `src/Web/Echo/Action.php`: + +```php +responseFactory->createResponse(); + $response->getBody()->write('The message is: ' . Html::encode($message)); + return $response; + } +} +``` + +No exemplo, o método `__invoke` recebe o parâmetro `$message`, que, com a +ajuda do atributo `RouteArgument`, pega a mensagem da URL. O valor padrão é +`"Hello!"`. Se a requisição for feita para `/say/Goodbye`, a action atribui +o valor "Goodbye" à variável `$message`. + +A aplicação passa a resposta pela [pilha de +middlewares](../structure/middleware.md) até o emitter, que envia a resposta +ao usuário final. + +## Configurando o router + +Agora, para mapear o handler para uma URL, você precisa adicionar uma rota +em `config/common/routes.php`: + +```php +routes( + Route::get('/') + ->action(Web\HomePage\Action::class) + ->name('home'), + Route::get('/say[/{message}]') + ->action(Web\Echo\Action::class) + ->name('echo/say'), + ), +]; +``` + +Acima, você mapeia o padrão `/say[/{message}]` para `\App\Web\Echo\Action`. +A cada requisição, o router cria uma instância e chama o método +`__invoke()`. A parte `{message}` do padrão grava o que for informado nessa +posição no argumento de rota `message`. `[]` marca essa parte do padrão +como opcional. + +Você também dá o nome `echo/say` a essa rota para poder gerar URLs que +apontem para ela. + +## Testando + +Depois de criar a action e a view, abra `http://localhost/say/Hello+World` +no navegador. + +Essa URL mostra uma página com "The message is: Hello World". + +Se você omitir o parâmetro `message` na URL, a página mostra "The message +is: Hello!". + +## Criando um template de view + +Normalmente, a tarefa é mais complicada do que imprimir "hello world" e +envolve renderizar algum HTML complexo. Para isso, é prático usar templates +de view. Eles são scripts que você escreve para gerar o corpo de uma +resposta. + +Para a tarefa "Hello", crie um template `src/Web/Echo/template.php` que +imprime o parâmetro `message` recebido do método da action: + +```php + + +

The message is:

+``` + +No código acima, o parâmetro `message` passa por codificação HTML antes de +ser impresso. Isso é necessário porque o parâmetro vem do usuário final e +está sujeito a [ataques de cross-site scripting +(XSS)](https://pt.wikipedia.org/wiki/Cross-site_scripting) com JavaScript +malicioso embutido no parâmetro. + +Naturalmente, você pode colocar mais conteúdo na view `say`. O conteúdo pode +ter tags HTML, texto puro e até instruções PHP. Na verdade, o serviço de +view executa a view `say` como um script PHP. + +Para usar a view, você precisa alterar `src/Web/Echo/Action.php`: + +```php +viewRenderer->render(__DIR__ . '/template', [ + 'message' => $message, + ]); + } +} +``` + +Agora abra o navegador e confira de novo. Você deve ver um texto parecido, +mas com um layout aplicado. + +Além disso, você separou a parte de como funciona da parte de como é +apresentado. Em aplicações maiores, isso ajuda muito a lidar com a +complexidade. + +## Resumo + +Nesta seção, você passou pelas partes de handler e de template de uma +aplicação web típica. Você criou um handler como parte de uma classe para +tratar uma requisição específica. Também criou uma view para compor o +conteúdo da resposta. Neste exemplo simples, nenhuma fonte de dados foi +usada, já que o único dado era o parâmetro `message`. + +Você também aprendeu sobre o roteamento no Yii, que funciona como a ponte +entre as requisições do usuário e os handlers. + +Na próxima seção, você vai aprender a buscar dados e adicionar uma nova +página com um formulário HTML. diff --git a/src/pt-BR/guide/start/looking-ahead.md b/src/pt-BR/guide/start/looking-ahead.md new file mode 100644 index 00000000..277bd115 --- /dev/null +++ b/src/pt-BR/guide/start/looking-ahead.md @@ -0,0 +1,9 @@ +# Seguindo em frente + +Se você leu todo o capítulo "Primeiros passos", já criou uma aplicação Yii +completa. No caminho, aprendeu a implementar alguns recursos comuns, como +receber dados dos usuários por um formulário HTML, buscar dados em um banco +de dados e exibir dados de forma paginada. Também aprendeu a usar o +[Gii](gii.md) para gerar código automaticamente. Usar o Gii para gerar +código transforma boa parte do desenvolvimento web em algo tão simples +quanto preencher alguns formulários. diff --git a/src/pt-BR/guide/start/prerequisites.md b/src/pt-BR/guide/start/prerequisites.md new file mode 100644 index 00000000..58d2d408 --- /dev/null +++ b/src/pt-BR/guide/start/prerequisites.md @@ -0,0 +1,45 @@ +# O que você precisa saber? + +A curva de aprendizado do Yii não é tão íngreme quanto a de outros +frameworks PHP, mas ainda assim há algumas coisas que você deve aprender +antes de começar com o Yii. + +## PHP + +O Yii é um framework PHP, então [leia e entenda a referência da +linguagem](https://www.php.net/manual/pt_BR/langref.php). + +## Programação orientada a objetos + +Você precisa de uma noção básica de programação orientada a objetos. Se +ainda não conhece, veja um dos muitos tutoriais disponíveis, como [o do +tuts+](https://code.tutsplus.com/tutorials/object-oriented-php-for-beginners--net-12762). + +Ao desenvolver com o Yii, você escreve código orientado a objetos, então +conheça bem o [suporte do PHP a +POO](https://www.php.net/manual/pt_BR/language.oop5.php). + +Quanto mais complexa for a sua aplicação, mais conceitos avançados de POO +você vai precisar aprender para lidar bem com essa complexidade. + +## Linha de comando e Composer + +O Yii usa amplamente o gerenciador de pacotes que é o padrão de fato no PHP, +o [Composer](https://getcomposer.org), então leia e entenda o [guia +dele](https://getcomposer.org/doc/01-basic-usage.md). Se você não tem +costume de usar a linha de comando, é hora de começar. Depois de aprender o +básico, você não vai querer trabalhar sem ela. + +## HTTP + +Como o Yii é um framework web e a web usa principalmente HTTP, é uma boa +ideia [aprender mais sobre +ele](https://developer.mozilla.org/pt-BR/docs/Web/HTTP). + +## Docker + +O template de aplicação padrão usa Docker, então recomendamos que você [leia +e entenda os conceitos](https://docs.docker.com/get-started/). + +Também vale a pena conhecer os princípios do [twelve-factor +app](https://12factor.net/pt_br/). diff --git a/src/pt-BR/guide/start/workflow.md b/src/pt-BR/guide/start/workflow.md new file mode 100644 index 00000000..e9c42b98 --- /dev/null +++ b/src/pt-BR/guide/start/workflow.md @@ -0,0 +1,149 @@ +# Fluxo da aplicação + +Depois de instalar o Yii, você tem uma aplicação Yii funcionando. Esta +seção apresenta as funcionalidades que vêm com a aplicação, como o código +está organizado e como a aplicação trata as requisições de forma geral. + +Diferente do próprio framework, depois que você instala um template de +projeto, ele é todo seu. Você pode adicionar ou remover código e mudar o +que precisar. + +## Funcionalidades + +A aplicação instalada tem apenas uma página, acessível em +`http://localhost/`. Ela usa um layout comum que você pode reaproveitar nas +próximas páginas. + + + +Além da aplicação web, você pode acessar um script de console via `./yii` +ou, no caso do Docker, `make yii`. Use esse script para rodar tarefas em +segundo plano e de manutenção da aplicação, descritas na [seção de +aplicações de console](../tutorial/console-applications.md). + +## Debugger experimental + +O Yii tem um debugger que coleta dados de debug das requisições web e os +expõe pelo [Yii Dev Panel](https://yiisoft.github.io/yii-dev-panel/). O +debugger ainda está em desenvolvimento. Ele não foi lançado como pacote +estável, e a API, as rotas e a configuração podem mudar ou ser +descontinuadas. + +Para testar a versão de desenvolvimento atual, instale o pacote da API de +debug: + +```shell +composer require yiisoft/yii-debug-api:^3.0@dev +``` + +Ative o modo debug no `.env`: + +```dotenv +APP_DEBUG=true +``` + +O pacote registra as rotas automaticamente. Inicie a aplicação e abra +`/debug` para conferir se a API de debug está disponível. Depois abra o [Yii +Dev Panel](https://yiisoft.github.io/yii-dev-panel/) e informe a URL da sua +aplicação. + +> [!CAUTION] +> Use o modo debug no desenvolvimento local. Em produção, mantenha `APP_DEBUG=false` e não exponha as rotas de debug publicamente. + +## Estrutura da aplicação + +Os diretórios e arquivos mais importantes da sua aplicação são (considerando +que o diretório raiz da aplicação é `app`): + +``` +assets/ Arquivos-fonte dos asset bundles. +config/ Arquivos de configuração. + common/ Configuração comum e definições de DI. + console/ Configuração específica do console. + environments/ Configuração por ambiente (dev/test/prod). + web/ Configuração específica da web. +docker/ Arquivos específicos do Docker. +public/ Arquivos acessíveis publicamente pela internet. + assets/ Assets publicados/compilados. + index.php Script de entrada. +runtime/ Arquivos gerados em tempo de execução. +src/ Código-fonte da aplicação. + Console/ Comandos de console. + Shared/ Código compartilhado entre as aplicações web e console. + Web/ Código específico da web (actions, handlers, layout). + Shared/ Componentes web compartilhados. + Layout/ Componentes e templates de layout. + Environment.php Classe de configuração do ambiente. +tests/ Conjunto de testes Codeception da aplicação. + Console/ Testes dos comandos de console. + Functional/ Testes funcionais. + Unit/ Testes unitários. + Web/ Testes das actions web. +vendor/ Pacotes do Composer instalados. +Makefile Configuração do comando make. +yii Ponto de entrada da aplicação de console. +``` + +De forma geral, os arquivos da aplicação se dividem em dois grupos: os que +ficam em `app/public` e os que ficam nos outros diretórios. Os primeiros +podem ser acessados diretamente via HTTP (ou seja, no navegador), enquanto +os demais não devem ser expostos. + +Toda aplicação tem um script de entrada `public/index.php`, o único script +PHP acessível pela web na aplicação. O script de entrada usa um +[application runner](https://github.com/yiisoft/yii-runner) para criar uma +instância da requisição recebida com a ajuda de um dos pacotes PSR-7 e a +passa para uma instância da [aplicação](../structure/application.md). A +aplicação executa um conjunto de middlewares em sequência para processar a +requisição. Depois, passa o resultado para o emitter, que envia a resposta +ao navegador. + +Dependendo dos middlewares que você usa, a aplicação pode se comportar de +forma diferente. Por padrão, um router usa a URL requisitada e a +configuração para escolher um handler e executá-lo para produzir a resposta. + +Você pode saber mais sobre o template de aplicação na [documentação do +pacote yiisoft/app](https://github.com/yiisoft/app/blob/master/README.md). + +## Ciclo de vida da requisição + +O diagrama a seguir mostra como uma aplicação trata uma requisição. + +```mermaid +flowchart LR + user[User's client] --> index + index[index.php] --> DI[Initialize Dependency Container] + config[configs] -.-> DI + DI --> RequestFactory[RequestFactory] + RequestFactory -->|Request| app[Application] + app -->|Request| middleware[Middleware] + middleware -->|Request| router[Router] + router -->|Request| action[Action Handler] + action -->|Response| emitter[SapiEmitter] + router -->|Response| emitter + middleware -->|Response| emitter + app -->|Response| emitter + emitter --> user +``` + +1. Um usuário faz uma requisição para o [script de + entrada](../structure/entry-script.md) `public/index.php`. +2. O script de entrada, com a ajuda do application runner, carrega a + [configuração](../concept/configuration.md) do container e cria uma + instância da [aplicação](../structure/application.md) e os serviços + necessários para tratar a requisição. +3. A request factory cria um objeto de requisição a partir da requisição + bruta que veio do usuário. +4. A aplicação passa o objeto de requisição pelo array de middlewares + configurado. Um deles normalmente é o router. +5. O router descobre qual handler executar com base na requisição e na + configuração. +6. O handler pode carregar alguns dados, possivelmente de um banco de dados. +7. O handler monta uma resposta usando esses dados, diretamente ou com a + ajuda do pacote de view. +8. O emitter recebe a resposta e cuida de enviá-la para o navegador do + usuário. diff --git a/src/pt-BR/guide/structure/action.md b/src/pt-BR/guide/structure/action.md new file mode 100644 index 00000000..a94bb4d0 --- /dev/null +++ b/src/pt-BR/guide/structure/action.md @@ -0,0 +1,130 @@ +# Actions + +Em uma aplicação web, a URL da requisição determina o que é executado. A +correspondência é feita por um router configurado com várias rotas. Cada +rota pode ser associada a um middleware que, dada a requisição, produz uma +resposta. Como os middlewares podem ser encadeados e podem passar o +tratamento efetivo para o próximo middleware, chamamos de action o +middleware que realmente faz o trabalho. + +Há várias formas de descrever uma action. A mais simples é usando uma +closure: + +```php +use \Psr\Http\Message\ServerRequestInterface; +use \Psr\Http\Message\ResponseInterface; +use Yiisoft\Router\Route; + +Route::get('/')->action(function (ServerRequestInterface $request) use ($responseFactory): ResponseInterface { + $response = $responseFactory->createResponse(); + $response->getBody()->write('You are at homepage.'); + return $response; +}); +``` + +Isso funciona bem para um tratamento simples, já que qualquer coisa mais +complicada exigiria obter dependências; então, uma boa ideia é mover o +tratamento para um método de classe. Um middleware de callback pode ser +usado para isso: + +```php +use Yiisoft\Router\Route; + +Route::get('/')->action(FrontPageAction::class), +``` + +A classe em si seria assim: + +```php +use \Psr\Http\Message\ServerRequestInterface; +use \Psr\Http\Message\ResponseInterface; + +final readonly class FrontPageAction +{ + public function __invoke(ServerRequestInterface $request): ResponseInterface + { + // monta a resposta para a página inicial + } +} +``` + +Em muitos casos, faz sentido agrupar o tratamento de várias rotas em uma +única classe: + + +```php +use Yiisoft\Router\Route; + +Route::get('/post/index')->action([PostController::class, 'actionIndex']), +Route::get('/post/view/{id:\d+}')->action([PostController::class, 'actionView']), +``` + +A classe em si ficaria assim: + +```php +use \Psr\Http\Message\ServerRequestInterface; +use \Psr\Http\Message\ResponseInterface; +use Yiisoft\Router\HydratorAttribute\RouteArgument; + +final readonly class PostController +{ + public function actionIndex(ServerRequestInterface $request): ResponseInterface + { + // renderiza a lista de posts + } + + + public function actionView( + ServerRequestInterface $request, + #[RouteArgument('id')] + int $id, + ): ResponseInterface + { + // renderiza um único post pelo $id + } +} +``` + +Normalmente chamamos uma classe assim de "controller". + +A parte `{id}` da rota `/post/view/{id:\d+}` é um parâmetro de rota +nomeado. Os parâmetros de rota estão disponíveis em +`Yiisoft\Router\CurrentRoute`. Para recebê-lo como argumento da action, +adicione o atributo `RouteArgument` ao parâmetro correspondente. O nome no +atributo deve corresponder ao nome do parâmetro de rota. + +## Autowiring + +Tanto os construtores das classes de action quanto os métodos de action recebem automaticamente serviços do + container de injeção de dependência: + +```php +use \Psr\Http\Message\ServerRequestInterface; +use \Psr\Http\Message\ResponseInterface; +use Psr\Log\LoggerInterface; + +final readonly class PostController +{ + public function __construct( + private PostRepository $postRepository + ) + { + } + + public function actionIndex(ServerRequestInterface $request, LoggerInterface $logger): ResponseInterface + { + $logger->debug('Rendering posts list'); + // renderiza a lista de posts + } + + + public function actionView(ServerRequestInterface $request): ResponseInterface + { + // renderiza um único post + } +} +``` + +No exemplo acima, `PostRepository` é injetado automaticamente pelo +construtor. Isso significa que ele fica disponível em todas as actions. O +logger é injetado apenas na action `index`. diff --git a/src/pt-BR/guide/structure/application.md b/src/pt-BR/guide/structure/application.md new file mode 100644 index 00000000..b8122cff --- /dev/null +++ b/src/pt-BR/guide/structure/application.md @@ -0,0 +1,19 @@ +# Aplicação + +O principal propósito da aplicação web e do seu runner no Yii3 é processar +requisições para obter respostas. + +Normalmente, o ciclo de execução consiste em: + +1. Inicialização. Obter a configuração, criar uma instância do container e + fazer a inicialização adicional do ambiente, como registrar o error + handler para que ele possa tratar os erros que ocorrerem. Disparar o + evento `ApplicationStartup`. +2. Tratar requisições passando os objetos de requisição para o dispatcher de + middlewares, que executa a [pilha de middlewares](middleware.md) e obtém + um objeto de resposta. Em aplicações PHP comuns, isso é feito uma vez. Em + [ambientes como o RoadRunner](../tutorial/using-with-event-loop.md), pode + ser feito várias vezes com a mesma instância da aplicação. O objeto de + resposta é convertido em uma resposta HTTP real usando o emitter. + Disparar o evento `AfterEmit`. +3. Encerramento. Disparar o evento `ApplicationShutdown`. diff --git a/src/pt-BR/guide/structure/designing-packages.md b/src/pt-BR/guide/structure/designing-packages.md new file mode 100644 index 00000000..7ca99335 --- /dev/null +++ b/src/pt-BR/guide/structure/designing-packages.md @@ -0,0 +1,543 @@ +# Projetando pacotes para aplicações Yii + +Esta página descreve como projetar um pacote Composer que acrescenta +comportamento a uma aplicação Yii por meio de configuração. Use-a quando o +seu pacote precisar registrar serviços, rotas, eventos, comandos, assets, +migrations, traduções ou um tema. + +Para instalar e atualizar pacotes em uma aplicação, veja [Usando +pacotes](package.md). + +## Metadados do Composer + +Todo pacote precisa ter um arquivo `composer.json` na pasta raiz. No mínimo, +defina o nome do pacote, as dependências, o autoload e os metadados de +configuração do Yii quando o pacote se integra a uma aplicação Yii. + +Use um nome de pacote no formato `vendor-name/project-name`: + +```json +{ + "name": "vendor/blog", + "type": "library", + "description": "Blog integration for Yii applications", + "require": { + "php": ">=8.2", + "yiisoft/router": "^4.0" + }, + "autoload": { + "psr-4": { + "Vendor\\Blog\\": "src/" + } + } +} +``` + +Use restrições de dependência estáveis em releases estáveis. Evite usar +`yiisoft` como nome de vendor, porque ele é reservado para os pacotes do +Yii. + +Se o seu pacote exige uma aplicação Yii, prefixar o nome do projeto com +`yii-` pode deixar isso claro no Packagist. + +## Estrutura do pacote + +Um pacote compatível com o Yii é um pacote Composer comum, com classes PHP, +arquivos de recursos opcionais e arquivos de configuração opcionais. +Mantenha a configuração em uma pasta previsível e deixe a API pública +explícita: + +``` +composer.json +config/ + params.php + di.php + di-providers.php + routes.php + events.php + params-web.php + params-console.php + di-console.php +src/ + ... +assets/ + ... +migrations/ + ... +messages/ + ... +views/ + ... +``` + +Use apenas os arquivos de que o seu pacote precisa. Por exemplo, um pacote +com comandos de console, mas sem rotas web, não precisa de `routes.php`. + +## Metadados do plugin de configuração + +Aplicações Yii usam o [yiisoft/config](https://github.com/yiisoft/config) +para descobrir a configuração dos pacotes. Declare os arquivos de +configuração do pacote na seção `extra.config-plugin` do `composer.json`: + +```json +{ + "name": "vendor/blog", + "type": "library", + "autoload": { + "psr-4": { + "Vendor\\Blog\\": "src/" + } + }, + "extra": { + "config-plugin": { + "params": "config/params.php", + "di": "config/di.php", + "di-providers": "config/di-providers.php", + "routes": "config/routes.php", + "events": "config/events.php", + "params-web": "config/params-web.php", + "params-console": "config/params-console.php", + "di-console": "config/di-console.php" + } + } +} +``` + +Cada chave de `config-plugin` é o nome de um grupo de configuração, e cada +valor é um caminho relativo à raiz do pacote. + +Use os grupos comuns, web e de console de forma consistente: + +- `params`, `di`, `di-providers`, `di-delegates`, `events` e `bootstrap` + valem para os pontos de entrada web e de console. +- `params-web`, `di-web`, `di-providers-web`, `events-web`, `bootstrap-web` + e `routes` valem para os pontos de entrada web. +- `params-console`, `di-console`, `di-providers-console`, `events-console` e + `bootstrap-console` valem para os pontos de entrada de console. + +Se o seu pacote define um novo grupo de configuração, documente como a +aplicação deve carregar esse grupo. Prefira os grupos padrão ao se integrar +com serviços do Yii, porque os templates de aplicação e os pacotes do Yii já +usam esses nomes. + +Depois que os usuários instalam, atualizam, removem ou fazem dump dos +arquivos de autoload do Composer, o plugin de configuração reconstrói o +merge plan que o Yii lê em tempo de execução. Se os usuários editarem +manualmente a configuração do pacote raiz, peça que executem: + +```sh +composer yii-config-rebuild +``` + +## Parâmetros + +Coloque as opções padrão em `config/params.php`. Agrupe os parâmetros do +pacote sob o nome do pacote no Composer para evitar colisões: + +```php + [ + 'postsPerPage' => 20, + 'cacheTtl' => 3600, + ], +]; +``` + +Os desenvolvedores da aplicação podem sobrescrever esses valores nos +próprios `config/common/params.php`, `config/web/params.php`, +`config/console/params.php` ou nos arquivos de parâmetros específicos de +cada ambiente. + +Não leia variáveis de ambiente nem estado global no código do pacote quando +um parâmetro puder expressar a escolha. Use parâmetros para configurar +serviços por meio de definições de DI ou service providers. + +## Definições de DI + +Use `config/di.php`, `config/di-web.php` ou `config/di-console.php` para +definições diretas do container: + +```php + [ + 'class' => PostRepository::class, + '__construct()' => [ + 'cacheTtl' => $params['vendor/blog']['cacheTtl'], + ], + ], +]; +``` + +Prefira definições de DI diretas quando a configuração descreve um serviço +de forma clara. + +## Service providers de DI + +Use um provider de DI quando o registro forma uma unidade reutilizável: +vários serviços relacionados, aliases, definições de factory ou extensões. + +Registre os providers em `config/di-providers.php`: + +```php + BlogProvider::class, +]; +``` + +Declare o grupo no `composer.json`: + +```json +"extra": { + "config-plugin": { + "di-providers": "config/di-providers.php" + } +} +``` + +Um provider pode retornar várias definições de serviços e extensões. Coloque +a classe do provider em `src/Provider/BlogProvider.php`: + +```php + PostRepository::class, + PostRepositoryInterface::class => static fn ( + ContainerInterface $container + ): CachedPostRepository => new CachedPostRepository( + $container->get(PostRepository::class), + $container->get(LoggerInterface::class), + ), + ]; + } + + public function getExtensions(): array + { + return []; + } +} +``` + +## Rotas + +Pacotes web podem adicionar rotas por meio de `config/routes.php`, declarado +como o grupo `routes`: + +```php +routes( + Route::get('') + ->action(IndexAction::class) + ->name('vendor/blog/index'), + ), +]; +``` + +Os nomes das rotas devem ter o prefixo do pacote. Isso evita colisões com as +rotas da aplicação e com as rotas de outros pacotes. + +Mantenha as rotas do pacote pequenas e fáceis de sobrescrever. Se uma +aplicação precisar de controle total sobre as URLs, documente as actions e +deixe a aplicação definir as próprias rotas. + +## Eventos + +Use `config/events.php`, `config/events-web.php` ou +`config/events-console.php` para associar handlers do pacote a eventos: + +```php + [ + ClearPostListCache::class, + ], +]; +``` + +Os handlers podem ser closures, callables, objetos invocáveis, nomes de +classes invocáveis ou aliases de DI suportados pela configuração do event +dispatcher. Prefira nomes de classes para os handlers do pacote, porque as +aplicações podem sobrescrever as dependências deles pelo container. + +## Assets + +Se o seu pacote traz CSS, JavaScript, imagens ou fontes, defina asset +bundles como classes PHP. Por exemplo, coloque esta classe em +`src/Asset/BlogAsset.php`: + +```php +register(BlogAsset::class); +``` + +Use `$sourcePath` para os arquivos que vêm dentro do pacote. Use `$basePath` +e `$baseUrl` como o destino público onde o asset manager os publica. + +## Migrations + +Pacotes que precisam de mudanças no esquema do banco de dados devem trazer +migrations e adicionar o namespace ou o caminho delas aos parâmetros do +`yiisoft/db-migration`. + +Para migrations com namespace: + +```php + [ + 'sourceNamespaces' => [ + 'Vendor\\Blog\\Migration', + ], + ], +]; +``` + +Para migrations baseadas em caminho: + +```php + [ + 'sourcePaths' => [ + __DIR__ . '/../migrations', + ], + ], +]; +``` + +Coloque isso em `config/params-console.php` e declare-o como +`params-console` no `composer.json`. + +Isso apenas informa os locais das migrations do pacote. A aplicação ainda +precisa ter o `yiisoft/db-migration` instalado e uma conexão com o banco de +dados configurada antes que os comandos de migration possam rodar. + +As migrations do pacote devem ficar estáveis depois do release. Não edite +uma migration que os usuários talvez já tenham aplicado. Em vez disso, +adicione uma nova migration. + +## Traduções + +Se o pacote tem mensagens exibidas ao usuário, dê a ele uma categoria de +tradução própria e registre uma category source em `config/di.php`: + +```php + [ + 'definition' => static function (): CategorySource { + $messageSource = new MessageSource(__DIR__ . '/../messages'); + + return new CategorySource( + 'vendor-blog', + $messageSource, + new IntlMessageFormatter(), + $messageSource, + ); + }, + 'tags' => ['translation.categorySource'], + ], +]; +``` + +Guarde as mensagens por locale e categoria: + +``` +messages/ + en-US/ + vendor-blog.php + de/ + vendor-blog.php +``` + +Use a categoria explícita ao traduzir: + +```php +$translator->translate('post.created', category: 'vendor-blog'); +``` + +## Temas + +Um pacote pode trazer arquivos de view e assets para um tema. Não o ative +pela configuração do pacote em vendor. Em vez disso, documente a +configuração da aplicação raiz necessária para habilitá-lo. No template de +aplicação, isso fica em `config/web/params.php`: + +```php + [ + 'theme' => [ + 'pathMap' => [ + '@views' => '@vendor/vendor/blog/views', + ], + 'basePath' => '@vendor/vendor/blog/assets', + 'baseUrl' => '@assetsUrl/vendor-blog', + ], + ], +]; +``` + +Os temas substituem caminhos de views de acordo com um mapa de +caminhos. Documente quais caminhos de views da aplicação o seu tema +substitui e qual URL de assets a aplicação precisa publicar ou expor. + +Não defina `yiisoft/view.theme` diretamente na configuração do pacote em +vendor. O `yiisoft/view` já define essa chave, e chaves duplicadas na mesma +camada de configuração não são permitidas. + +Se o seu pacote fornece apenas arquivos de tema opcionais, não deixe o tema +ativo por padrão. Forneça os arquivos de view, o asset bundle e um trecho de +parâmetros documentado, para que a aplicação possa optar por usá-lo. + +## Comandos de console + +Pacotes de console podem adicionar comandos do Symfony Console por meio de +`config/params-console.php`: + +```php + [ + 'commands' => [ + 'blog/reindex' => ReindexCommand::class, + ], + ], +]; +``` + +Os nomes dos comandos devem ter o prefixo do pacote. Mantenha as +dependências dos comandos injetadas pelo construtor e registradas via DI. + +## Sobrescritas pela aplicação + +A configuração do pacote é a camada padrão. A aplicação pode sobrescrevê-la +na configuração do pacote raiz. Projete pensando nisso: + +- Use chaves de parâmetros, nomes de rotas, IDs de handlers de eventos e + aliases de DI com o prefixo do pacote. +- Mantenha a configuração padrão pequena e documentada. +- Evite fazer trabalho irreversível durante o registro de serviços. +- Coloque integrações opcionais em arquivos de configuração ou providers + separados quando elas exigirem pacotes Composer opcionais. +- Teste o pacote dentro de uma aplicação Yii mínima, para que o plugin de + configuração, o container de DI, as rotas, os comandos de console, as + migrations, as traduções e os assets sejam exercitados juntos. + +Quando um usuário precisa personalizar a configuração do pacote, normalmente +não precisa copiar o arquivo de configuração do pacote. Ele pode redefinir +parcialmente as chaves necessárias na configuração da aplicação. + +Depois de alterar os mapeamentos de grupos de configuração, ele deve +reconstruir o merge plan com: + +```sh +composer yii-config-rebuild +``` + +## Publicando pacotes + +Antes de criar a tag de um release, teste o pacote isoladamente e dentro de +uma aplicação Yii mínima. Inclua `README.md`, `CHANGELOG.md` e `UPGRADE.md` +quando mudanças de comportamento ou de configuração precisarem de +explicação. + +Use [versionamento semântico](https://semver.org) nos releases +públicos. Depois do primeiro release, não edite migrations que os usuários +talvez já tenham aplicado; adicione novas migrations. diff --git a/src/pt-BR/guide/structure/entry-script.md b/src/pt-BR/guide/structure/entry-script.md new file mode 100644 index 00000000..12743c60 --- /dev/null +++ b/src/pt-BR/guide/structure/entry-script.md @@ -0,0 +1,117 @@ +# Scripts de entrada + +Os scripts de entrada são o primeiro passo no processo de inicialização da +aplicação. Uma aplicação (seja web ou de console) tem um único script de +entrada. Os usuários finais fazem requisições aos scripts de entrada, que +instanciam a aplicação e encaminham as requisições para ela. + +Os scripts de entrada de aplicações web devem ficar em pastas acessíveis +pela web, para que os usuários finais possam acessá-los. Eles costumam se +chamar `index.php`, mas podem ter qualquer outro nome, desde que os +servidores web consigam localizá-los. + +O script de entrada da aplicação de console é `./yii`. + +Os scripts de entrada fazem principalmente o seguinte, com a ajuda do +`ApplicationRunner`: + +* Registram o [autoloader do + Composer](https://getcomposer.org/doc/01-basic-usage.md#autoloading); +* Obtêm a configuração; +* Usam a configuração para inicializar um container de injeção de + dependência; +* Obtêm uma instância da requisição. +* Passam-na para a `Application` tratar e obtêm dela uma resposta. +* Com a ajuda de um emitter, transformam o objeto de resposta em uma + resposta HTTP real, que é enviada ao navegador do cliente. + +## Aplicações web + +Este é o código do script de entrada do template de aplicação: + +```php +debug(); +// Executa a aplicação: +$runner->run(); +``` + + +## Aplicações de console + +Da mesma forma, este é o código do script de entrada de uma aplicação de +console: + +```php +#!/usr/bin/env php +withDefinitions($config->get('console')) + ->withProviders($config->get('providers-console')); +$container = new Container($containerConfig); + +/** @var ContainerInterface $container */ +$container = $container->get(ContainerInterface::class); + +$application = $container->get(Application::class); +$exitCode = 1; + +try { + $application->start(); + $exitCode = $application->run(null, new ConsoleBufferedOutput()); +} catch (\Error $error) { + $application->renderThrowable($error, new ConsoleBufferedOutput()); +} finally { + $application->shutdown($exitCode); + exit($exitCode); +} +``` + +## Runtimes alternativos + +Para runtimes alternativos como FrankenPHP, Rapira, RoadRunner ou Swoole, +devem ser usados scripts de entrada especiais. Veja: + +- [Usando o Yii com FrankenPHP](../tutorial/using-yii-with-frankenphp.md) +- [Usando o Yii com Rapira](../tutorial/using-yii-with-rapira.md) +- [Usando o Yii com RoadRunner](../tutorial/using-yii-with-roadrunner.md) +- [Usando o Yii com Swoole](../tutorial/using-yii-with-swoole.md) diff --git a/src/pt-BR/guide/structure/middleware.md b/src/pt-BR/guide/structure/middleware.md new file mode 100644 index 00000000..1ea6d5d8 --- /dev/null +++ b/src/pt-BR/guide/structure/middleware.md @@ -0,0 +1,200 @@ +# Middleware + +O Yii trabalha com HTTP usando a camada de abstração construída em torno das +[interfaces de mensagens HTTP da PSR-7](https://www.php-fig.org/psr/psr-7/) +e das [interfaces de request handler/middleware da +PSR-15](https://www.php-fig.org/psr/psr-15/). + +A aplicação é composta por um ou vários middlewares. O middleware roda entre +a requisição e a resposta. Quando a URL é requisitada, o objeto de +requisição é passado para o dispatcher de middlewares, que começa a executar +os middlewares um após o outro. Cada middleware, dada a requisição, pode: + +- Passar a requisição para o próximo middleware, fazendo algum trabalho + antes / depois dele. +- Montar a resposta e devolvê-la. + +Dependendo dos middlewares usados, o comportamento da aplicação pode variar +bastante. + +![Middleware](/images/guide/middleware.svg) + +Acima, cada middleware seguinte envolve o anterior. Também é possível +representar assim: + +![Middleware](/images/guide/middleware_alternative.svg) + +## Usando middlewares + +Qualquer middleware compatível com a +[PSR-15](https://www.php-fig.org/psr/psr-15/) pode ser usado com o Yii, e +existem muitos. Digamos que você precise adicionar autenticação básica a +uma das URLs da aplicação. Middlewares que dependem da URL são configurados +pelo router, então você precisa alterar a router factory. + +O middleware de autenticação é implementado pelo pacote +`middlewares/http-authentication`, então execute `composer require +middlewares/http-authentication` na pasta raiz da aplicação. + +Agora registre o middleware na configuração do container de DI, +`config/web.php`: + +```php + [ + 'class' => \Middlewares\BasicAuthentication::class, + '__construct()' => [ + 'users' => [ + 'foo' => 'bar', + ], + ], + 'realm()' => ['Access to the staging site via basic auth'], + 'attribute()' => ['username'], +], +``` + +No `config/routes.php`, adicione uma nova rota: + +```php +action([SiteController::class, 'auth']) + ->name('site/auth') + ->prependMiddleware(BasicAuthentication::class) +]; +``` + +Ao configurar o roteamento, você está associando a URL `/basic-auth` a uma +cadeia de middlewares formada pela autenticação básica e pela própria +action. Uma cadeia é um middleware especial que executa todos os middlewares +com que foi configurada. + +A action em si poderia ser a seguinte: + +```php +public function auth(ServerRequestInterface $request): ResponseInterface +{ + $response = $this->responseFactory->createResponse(); + $response->getBody()->write('Hi ' . $request->getAttribute('username')); + return $response; +} +``` + +O middleware de autenticação básica gravou o atributo `username` na +requisição, então você pode acessar esse dado se precisar. + +Para aplicar um middleware à aplicação como um todo, independentemente da +URL, ajuste o `config/application.php`: + +```php +return [ + Yiisoft\Yii\Http\Application::class => [ + '__construct()' => [ + 'dispatcher' => DynamicReference::to(static function (Injector $injector) { + return ($injector->make(MiddlewareDispatcher::class)) + ->withMiddlewares( + [ + ErrorCatcher::class, + BasicAuthentication::class, + SessionMiddleware::class, + CsrfTokenMiddleware::class, + Router::class, + ] + ); + }), + 'fallbackHandler' => Reference::to(NotFoundHandler::class), + ], + ], +]; +``` + +## Criando o seu próprio middleware + +Para criar um middleware, você precisa implementar um único método, +`process`, da `Psr\Http\Server\MiddlewareInterface`: + +```php +public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface; +``` + +Há várias formas de tratar uma requisição, e a escolha depende do que o +middleware deve fazer. + +### Montando uma resposta diretamente + +Para responder diretamente, é preciso uma response factory passada pelo +construtor: + +```php +responseFactory->createResponse(); + $response->getBody()->write('Hello!'); + return $response; + } +} +``` + +### Delegando o tratamento para o próximo middleware + +Se o middleware não tem a intenção de montar uma resposta nem de alterar a requisição, ou se não pode fazer nada desta vez, +o tratamento pode ficar para o próximo middleware da pilha: + +```php +public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface +{ + return $handler->handle($request); +} +``` + +Se você precisar passar dados para o próximo middleware, pode usar atributos +da requisição: + +```php +$request = $request->withAttribute('answer', 42); +return $handler->handle($request); +``` + +Para obtê-los no próximo middleware: + +```php +$answer = $request->getAttribute('answer'); +``` + +### Capturando a resposta para manipulá-la + +Você pode querer capturar a resposta para manipulá-la. Isso pode ser útil +para adicionar headers CORS, compactar o conteúdo com gzip etc. + +```php +$response = $handler->handle($request); +// tratamento extra +return $response; +``` diff --git a/src/pt-BR/guide/structure/module.md b/src/pt-BR/guide/structure/module.md new file mode 100644 index 00000000..5e487a81 --- /dev/null +++ b/src/pt-BR/guide/structure/module.md @@ -0,0 +1,291 @@ +# Módulos + +Um módulo é uma parte da aplicação agrupada em torno de um contexto de +negócio ou de um recurso reutilizável. No Yii, isso é uma fronteira de +design, não uma classe base obrigatória. Um módulo pode ser: + +- código da aplicação no namespace `App\`; +- um [pacote Composer](package.md) instalado em `vendor/`; +- código que começa na aplicação e depois é extraído para um pacote. + +Use um módulo quando um grupo de actions, serviços de domínio, repositórios, +handlers de eventos, views, assets, comandos e a configuração relacionada +mudam juntos e têm um nome que faz sentido para o negócio. + +Por exemplo, um módulo de blog pode ficar na aplicação assim: + +``` +src/ + Blog/ + Post/ + Post.php + PostRepositoryInterface.php + InMemoryPostRepository.php + Web/ + IndexAction.php + index.php +``` + +A mesma estrutura pode virar um pacote Composer mais tarde, mudando o +namespace e adicionando os metadados e os arquivos de configuração do +pacote. Veja [Projetando pacotes](designing-packages.md) para os detalhes +específicos de pacotes. + +## Fronteiras de módulos + +Mantenha o código do módulo agrupado primeiro por contexto e depois por tipo +técnico. Isso se aproxima da abordagem de [vertical +slices](../../cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md), +mas numa fronteira maior da estrutura da aplicação. Prefira +`App\Blog\Post\PostRepositoryInterface` a um +`App\Repository\PostRepositoryInterface` global quando o repositório +pertence apenas aos posts do blog. + +Trate as classes de um módulo como API pública apenas quando se espera que +outro módulo as use. Boas classes de API pública normalmente são: + +- comandos ou queries que expressam um caso de uso; +- DTOs ou value objects trocados entre módulos; +- interfaces de serviços que outro módulo pode chamar; +- eventos emitidos pelo módulo. + +Mantenha as classes de implementação privadas ao namespace do módulo. Outros +módulos não devem depender diretamente de +`App\Blog\Post\InMemoryPostRepository` ou de uma action de controller. Eles +devem depender de uma interface, de uma classe de caso de uso ou de um +evento. + +## Interfaces entre módulos + +Coloque a interface onde o contrato pertence: + +- Se a interface descreve uma capacidade fornecida por um módulo, coloque-a + nesse módulo. Por exemplo, `App\Blog\Post\PostRepositoryInterface` + pertence ao módulo de blog porque descreve como os posts do blog são + lidos. +- Se a interface descreve o que um módulo precisa do mundo externo, + coloque-a no módulo consumidor. Por exemplo, + `App\Order\Customer\CustomerVerifierInterface` pertence ao módulo de + pedidos se os pedidos só precisam de uma verificação de cliente do tipo + sim ou não. O módulo de clientes, um adaptador da aplicação ou um pacote + pode fornecer a implementação. + +Isso mantém as dependências explícitas. Um módulo pode depender do contrato +público de outro módulo, mas não deve acessar as classes de implementação +internas de outro módulo. + +Primeiro, defina a interface no módulo: + +```php + + */ + public function findLatest(): array; +} +``` + +Coloque a implementação no mesmo módulo e associe a interface a ela: + +```php + InMemoryPostRepository::class, +]; +``` + +No template de aplicação padrão, coloque esse arquivo em +`config/common/di/`, por exemplo `config/common/di/blog.php`. O template +carrega `config/common/di/*.php` no grupo de configuração compartilhado +`di`, então a associação fica disponível para os pontos de entrada web e de +console. + +## Actions web + +As actions pertencem ao módulo quando são o ponto de entrada web do +comportamento do módulo: + +```php +viewRenderer->render(__DIR__ . '/index', [ + 'posts' => $this->posts->findLatest(), + ]); + } +} +``` + +Mantenha a leitura da requisição e a criação da resposta na action. Mantenha +as decisões de negócio nas classes de domínio do módulo ou em serviços de +caso de uso. + +## Rotas + +Em uma aplicação pequena, adicione as rotas do módulo diretamente em +`config/common/routes.php`: + +```php +routes( + Route::get('/') + ->action(Web\HomePage\Action::class) + ->name('home'), + ), + + Group::create('/blog') + ->routes( + Route::get('') + ->action(IndexAction::class) + ->name('blog/index'), + ), +]; +``` + +Use nomes de rota com o prefixo do módulo, como `blog/index`, para evitar +colisões. + +Se a aplicação tem muitos módulos, você pode dar a cada módulo o seu próprio +arquivo de configuração de rotas. Altere o grupo `routes` em +`config/configuration.php`: + +```php +'routes' => [ + 'common/routes.php', + 'common/routes/*.php', +], +``` + +Depois crie `config/common/routes/blog.php`: + +```php +routes( + Route::get('') + ->action(IndexAction::class) + ->name('blog/index'), + ), +]; +``` + +Depois de alterar `config/configuration.php` ou de adicionar arquivos que +casam com um curinga da configuração, reconstrua o merge plan: + +```sh +composer yii-config-rebuild +``` + +## Configuração de módulos + +Os módulos da aplicação usam os mesmos grupos de configuração que os +pacotes. A diferença é onde a configuração fica: + +- a configuração de um módulo da aplicação fica na aplicação raiz, em + `config/`; +- a configuração de um módulo em pacote fica no pacote e é declarada em + `extra.config-plugin`. + +Locais comuns para a configuração de módulos da aplicação são: + +``` +config/ + common/ + di/ + blog.php + routes/ + blog.php + params.php + console/ + params.php + web/ + params.php +``` + +Coloque as definições de serviços compartilhadas em `common/di/`. Coloque as +definições exclusivas da web em `web/di/`. Coloque os parâmetros ou +registros de comandos exclusivos do console em `console/params.php`. + +Quando um módulo cresce a ponto de se tornar reutilizável, mova as classes +PHP para um pacote Composer, mova os arquivos de configuração para a pasta +`config/` do pacote e declare-os no `composer.json` do pacote: + +```json +{ + "extra": { + "config-plugin": { + "di": "config/di.php", + "routes": "config/routes.php" + } + } +} +``` + +A aplicação pode, então, sobrescrever os padrões do pacote nos próprios +arquivos de configuração. + +## Comunicação entre módulos + +Escolha o menor acoplamento que atenda ao comportamento: + +- Use injeção pelo construtor com uma interface para uma chamada síncrona + direta. +- Use um evento quando quem produz não deve saber quem reage a algo que + aconteceu. +- Use um serviço de aplicação ou uma classe de caso de uso quando a + orquestração pertence a um lugar fora dos dois módulos. +- Use um pacote quando o módulo precisa ser reutilizado por mais de uma + aplicação. + +Evite chamadas a service locator e estado global dentro das classes do +módulo. Deixe que actions, comandos e serviços recebam as suas dependências +pelos construtores, para que as fronteiras dos módulos fiquem visíveis no +código e possam ser testadas isoladamente. diff --git a/src/pt-BR/guide/structure/overview.md b/src/pt-BR/guide/structure/overview.md new file mode 100644 index 00000000..a746d45f --- /dev/null +++ b/src/pt-BR/guide/structure/overview.md @@ -0,0 +1,67 @@ +# Visão geral + +O código de aplicações Yii normalmente é agrupado em módulos por +contexto. Dentro de cada módulo, pode haver um agrupamento por tipo. + +Por exemplo, se a aplicação for uma loja online, os contextos poderiam ser: + +- Cliente + - Perfil + - Lista de produtos + - Checkout +- Logística +- Entrega + - Endereços +- Helpdesk + - Suporte + - Reclamações + - Devoluções +- Contabilidade + - Devoluções + - Transações + - Impostos + +Para um contexto "Customer", localizado no namespace `App\Customer`, a +estrutura seria: + +``` +App/ + Customer/ <-- namespace do módulo + Entity/ + Customer.php <-- entidade compartilhada por "Profile" e "Checkout" + Profile/ + Widget/ + Gravatar.php + ProfileRepository.php <-- o repositório geralmente é específico do contexto + ProfileController.php <-- ponto de entrada de "Customer\Profile" + ProductList/ <-- namespace do módulo + Entity/ <-- entidades específicas de "Customer\ProductList" + Category.php + Product.php + ProductsListController.php <-- ponto de entrada de "Customer\ProductList" + Checkout/ <-- namespace do módulo + CheckoutController.php +``` + +Um contexto pode incluir subcontextos. Se uma classe é compartilhada por +vários contextos, ela é movida para o ancestral comum desses contextos. + +Um contexto pode ter [um ponto de entrada conhecido como "action" ou +"controller"](action.md). A função dele é receber [uma instância de +requisição](../runtime/request.md), passá-la para a [camada de +domínio](../../cookbook/organizing-code/domain.md) em um formato adequado e +criar [uma resposta](../runtime/response.md) com base no retorno da camada +de domínio. + +Além disso, aplicações Yii também têm o seguinte: + +* [scripts de entrada](entry-script.md): são scripts PHP acessíveis + diretamente pelos usuários finais. Eles são responsáveis por iniciar um + ciclo de tratamento de requisição. Normalmente, um único script de entrada + atende a aplicação inteira. +* [serviços](../../cookbook/organizing-code/service.md): normalmente são + objetos sem estado registrados no container de dependências que fornecem + diversos métodos de ação. +* [middleware](middleware.md): representam código que precisa ser executado + antes e depois do tratamento efetivo de cada requisição pelos handlers de + action. diff --git a/src/pt-BR/guide/structure/package.md b/src/pt-BR/guide/structure/package.md new file mode 100644 index 00000000..a230873d --- /dev/null +++ b/src/pt-BR/guide/structure/package.md @@ -0,0 +1,121 @@ +# Usando pacotes + +Código reutilizável é distribuído como [pacotes +Composer](https://getcomposer.org/doc/05-repositories.md#package). Um +pacote pode ser uma biblioteca de infraestrutura, uma integração com o Yii, +um recurso reutilizável ou um módulo que representa um contexto da +aplicação. + +Esta página explica como usar pacotes em uma aplicação. Para criar um pacote +compatível com o Yii, veja [Projetando pacotes para aplicações +Yii](designing-packages.md). + +## Instalando pacotes + +Por padrão, o Composer instala pacotes registrados no +[Packagist](https://packagist.org/), o principal repositório de pacotes PHP +de código aberto. + +Instale um pacote com: + +```sh +composer require vendor-name/package-name +``` + +O Composer atualiza dois arquivos: + +- `composer.json` armazena o nome do pacote e a restrição de versão. +- `composer.lock` armazena as versões exatas instaladas. + +Faça commit dos dois arquivos para que outros ambientes instalem as mesmas +versões das dependências. + +Os pacotes instalados ficam na pasta `vendor/` da aplicação. + +> [!WARNING] +> Nunca edite arquivos em `vendor/` diretamente. Em vez disso, altere a configuração da aplicação, estenda classes, decore serviços ou +> contribua com correções para o pacote. + +As classes dos pacotes ficam disponíveis pelo autoload do Composer após a +instalação. Veja [Autoload](../concept/autoloading.md) para mais detalhes. + +## Atualizando pacotes + +Atualize um pacote dentro da restrição de versão registrada no +`composer.json`: + +```sh +composer update vendor-name/package-name +``` + +Altere a restrição de versão aceita com `composer require`: + +```sh +composer require vendor-name/package-name:^2.0 +``` + +Depois de atualizar um pacote compatível com o Yii, o Composer reconstrói o +merge plan de configuração do Yii. Se você alterou manualmente os +mapeamentos de grupos de configuração, reconstrua-o explicitamente: + +```sh +composer yii-config-rebuild +``` + +## Removendo pacotes + +Remova um pacote com: + +```sh +composer remove vendor-name/package-name +``` + +Em seguida, remova o código e a configuração da aplicação que referenciavam +classes, serviços, rotas, comandos, assets, migrations ou traduções desse +pacote. + +## Pacotes privados + +Para código privado, configure repositórios do Composer no `composer.json` +da aplicação. As opções mais comuns são: + +- `vcs` para um repositório Git. +- `path` para um pacote local durante o desenvolvimento. +- `composer` para um repositório Composer privado. + +Por exemplo, para trabalhar com um pacote localizado ao lado da aplicação: + +```json +{ + "repositories": [ + { + "type": "path", + "url": "../packages/blog" + } + ] +} +``` + +Depois, instale-o normalmente: + +```sh +composer require vendor/blog +``` + +Leia mais na [documentação de repositórios do +Composer](https://getcomposer.org/doc/05-repositories.md). + +## Configuração de pacotes + +Alguns pacotes Yii fornecem configuração padrão por meio do +[yiisoft/config](https://github.com/yiisoft/config). Após a instalação, a +configuração do pacote passa a fazer parte da camada vendor, e a aplicação +pode sobrescrevê-la na configuração do pacote raiz. + +Prefira sobrescritas parciais nos arquivos de configuração da aplicação em +vez de copiar arquivos de configuração inteiros do pacote. Por exemplo, +sobrescreva apenas o parâmetro ou a definição de serviço de que você +precisa. + +Para mais detalhes, veja [Configuração](../concept/configuration.md) e +[Projetando pacotes para aplicações Yii](designing-packages.md). diff --git a/src/pt-BR/guide/testing/end-to-end.md b/src/pt-BR/guide/testing/end-to-end.md new file mode 100644 index 00000000..4b35ac94 --- /dev/null +++ b/src/pt-BR/guide/testing/end-to-end.md @@ -0,0 +1,132 @@ +# Testes end-to-end + +O template de aplicação Yii usa a suíte `Web` do Codeception para testes que +passam por um servidor HTTP. Esses testes ficam em `tests/Web` e usam +`App\Tests\Support\WebTester`. + +Use testes web para o comportamento HTTP visível ao usuário: páginas, links, +formulários, redirecionamentos, cookies e páginas de erro. + +## Suíte Web + +O template configura `tests/Web.suite.yml` assim: + +```yaml +actor: WebTester +extensions: + enabled: + - Codeception\Extension\RunProcess: + 0: composer serve + sleep: 3 +modules: + enabled: + - PhpBrowser: + url: http://127.0.0.1:8080 +``` + +`RunProcess` inicia a aplicação com o script `serve` do +Composer. `PhpBrowser` envia requisições HTTP ao servidor. + +## Testar uma página + +O template inclui `tests/Web/HomePageCest.php`: + +```php +wantTo('home page works.'); + $I->amOnPage('/'); + $I->expectTo('see page home.'); + $I->see('Hello!'); + } +} +``` + +Execute a suíte web localmente: + +```shell +APP_ENV=test vendor/bin/codecept run Web +``` + +Execute apenas este teste: + +```shell +APP_ENV=test vendor/bin/codecept run Web HomePageCest +``` + +Com Docker: + +```shell +make test Web +``` + +## Testar links e páginas de erro + +Use os mesmos métodos do actor para navegação e asserções sobre a resposta: + +```php +wantTo('see 404 page.'); + $I->amOnPage('/non-existent-page'); + $I->canSeeResponseCodeIs(404); + $I->see('404'); + $I->see('The page /non-existent-page not found.'); + } +} +``` + +## Smoke test com curl + +Para um smoke test de deploy, inicie a aplicação e verifique uma URL: + +```shell +APP_ENV=test ./yii serve --port=8080 +``` + +Em outro terminal: + +```shell +curl -fsS http://127.0.0.1:8080/ > /tmp/home.html +grep -q "Hello!" /tmp/home.html +``` + +## Redefinir o estado + +Testes web usam infraestrutura real, então redefina o estado antes de cada +cenário: + +- Carregue apenas os registros exigidos pelo cenário. +- Limpe o armazenamento de sessão e de cookies. +- Limpe arquivos gerados e mensagens de saída. +- Pare os workers em segundo plano ou torne seus efeitos determinísticos. + +Se o cenário altera um banco de dados, redefina-o no hook `_before()` do +Cest ou em um helper específico do projeto: + +```php +public function _before(WebTester $I): void +{ + // Redefina tabelas do banco de dados, arquivos, filas e mensagens de saída. +} +``` diff --git a/src/pt-BR/guide/testing/environment-setup.md b/src/pt-BR/guide/testing/environment-setup.md new file mode 100644 index 00000000..b510a747 --- /dev/null +++ b/src/pt-BR/guide/testing/environment-setup.md @@ -0,0 +1,200 @@ +# Configuração do ambiente de testes + +O template de aplicação Yii já vem com o ambiente de testes configurado. Use +esta página ao criar um novo projeto a partir do template, restaurar +arquivos de teste removidos ou adicionar uma nova suíte. + +## Configuração do Composer + +O template exige o Codeception, o PHPUnit e os módulos usados pelas suítes: + +```json +{ + "require-dev": { + "codeception/codeception": "^5.3", + "codeception/module-asserts": "^3.2", + "codeception/module-cli": "^2.0", + "codeception/module-phpbrowser": "^3.0", + "phpunit/phpunit": "^11.5" + }, + "autoload-dev": { + "psr-4": { + "App\\Tests\\": "tests" + } + }, + "scripts": { + "test": "codecept run" + } +} +``` + +Se essas entradas já estiverem no seu projeto, mantenha as versões +instaladas do `composer.lock`. + +## Arquivo principal do Codeception + +O `codeception.yml` na raiz define o namespace dos testes, os caminhos, o +arquivo de bootstrap e a origem da cobertura: + +```yaml +namespace: App\Tests +support_namespace: Support +bootstrap: bootstrap.php + +settings: + shuffle: true + colors: true + +paths: + tests: tests + output: tests/_output + data: tests/Support/Data + support: tests/Support + +coverage: + enabled: true + show_uncovered: true + show_only_summary: true + include: + - src/* + - public/index.php + - yii + +extensions: + enabled: + - Codeception\Extension\RunFailed +``` + +`tests/bootstrap.php` prepara o ambiente da aplicação para todas as suítes: + +```php +runAndGetResponse($request); + $body = $response->getBody(); + if ($body->isSeekable()) { + $body->rewind(); + } + + return $response; + } +} +``` + +## Testar uma página + +O template inclui `tests/Functional/HomePageCest.php`: + +```php +sendRequest( + new ServerRequest(uri: '/'), + ); + + assertSame(200, $response->getStatusCode()); + assertStringContainsString( + 'Don\'t forget to check the guide', + $response->getBody()->getContents(), + ); + } +} +``` + +Execute-o: + +```shell +APP_ENV=test vendor/bin/codecept run Functional +APP_ENV=test vendor/bin/codecept run Functional HomePageCest +``` + +## Enviar dados na requisição + +Use os métodos PSR-7 para modelar a requisição: + +```php +$request = (new ServerRequest(uri: '/contact', method: 'POST')) + ->withHeader('Content-Type', 'application/x-www-form-urlencoded') + ->withParsedBody([ + 'ContactForm' => [ + 'name' => 'Sam', + 'email' => 'sam@example.test', + 'body' => 'Hello.', + ], + ]); + +$response = $tester->sendRequest($request); + +assertSame(302, $response->getStatusCode()); +assertSame('/contact/sent', $response->getHeaderLine('Location')); +``` + +Para APIs JSON, escreva o corpo JSON em um stream PSR-7 e defina +`Content-Type: application/json`. + +## Redefinir o estado + +Testes funcionais costumam mexer em arquivos de runtime, sessões, cache e +banco de dados. Redefina o estado alterado no hook `_before()` do Cest ou em +um helper do projeto: + +```php +public function _before(FunctionalTester $tester): void +{ + // Redefina tabelas do banco de dados, pools de cache, filas e mensagens de saída. +} +``` + +Mantenha as regras de domínio puras nos testes unitários. Coloque o +comportamento de requisição e resposta nos testes funcionais. diff --git a/src/pt-BR/guide/testing/overview.md b/src/pt-BR/guide/testing/overview.md new file mode 100644 index 00000000..d4f71f66 --- /dev/null +++ b/src/pt-BR/guide/testing/overview.md @@ -0,0 +1,105 @@ +# Testes + +O template de aplicação Yii inclui uma configuração de testes pronta. Ele +usa o Codeception com asserções do PHPUnit e tem quatro suítes: + +- `Unit` para classes PHP isoladas. +- `Functional` para código da aplicação chamado no mesmo processo PHP. +- `Web` para requisições enviadas por um servidor HTTP. +- `Console` para comandos de console. + +Os arquivos principais são: + +- `codeception.yml`. +- `tests/bootstrap.php`. +- `tests/Unit.suite.yml`. +- `tests/Functional.suite.yml`. +- `tests/Web.suite.yml`. +- `tests/Console.suite.yml`. +- `tests/Support/*Tester.php`. + +## Executar testes localmente + +Gere as classes de actor depois de instalar as dependências ou alterar uma +suíte: + +```shell +vendor/bin/codecept build +``` + +Execute todos os testes: + +```shell +APP_ENV=test vendor/bin/codecept run +``` + +O template também define um script do Composer: + +```shell +APP_ENV=test composer test +``` + +Execute uma suíte: + +```shell +APP_ENV=test vendor/bin/codecept run Unit +APP_ENV=test vendor/bin/codecept run Functional +APP_ENV=test vendor/bin/codecept run Web +APP_ENV=test vendor/bin/codecept run Console +``` + +Execute uma classe ou um método de teste: + +```shell +APP_ENV=test vendor/bin/codecept run Functional HomePageCest +APP_ENV=test vendor/bin/codecept run Functional HomePageCest:base +``` + +`APP_ENV=test` é obrigatório nos comandos locais porque +`tests/bootstrap.php` prepara o ambiente da aplicação antes da execução dos +testes. + +## Executar testes no Docker + +Gere as classes de actor: + +```shell +make codecept build +``` + +Execute todos os testes: + +```shell +make test +``` + +Execute uma suíte: + +```shell +make test Unit +make test Functional +make test Web +make test Console +``` + +O ambiente de testes do Docker lê `docker/test/.env`, onde `APP_ENV=test` já +está definido. + +## Escolher uma suíte + +Comece com testes unitários para código que não tem fronteira com o +framework: value objects, validadores, serviços de domínio e +transformadores. + +Use testes funcionais quando o código precisa da configuração do Yii, +injeção de dependência, roteamento, middlewares, tratamento de requisições +ou renderização de templates. + +Use testes web para comportamentos que precisam passar por um servidor HTTP: +códigos de status, links, redirecionamentos, cookies e páginas renderizadas +como o cliente as vê. + +Use testes de console para os comandos em `src/Console`. + +Execute a análise estática no CI e antes de alterar contratos +compartilhados. diff --git a/src/pt-BR/guide/testing/quality-tools.md b/src/pt-BR/guide/testing/quality-tools.md new file mode 100644 index 00000000..f110a7a7 --- /dev/null +++ b/src/pt-BR/guide/testing/quality-tools.md @@ -0,0 +1,113 @@ +# Análise estática e qualidade de código + +O template de aplicação Yii inclui ferramentas de análise estática e de +qualidade de código junto com a suíte de testes. + +## Psalm + +Execute o Psalm localmente: + +```shell +vendor/bin/psalm +``` + +Execute o Psalm no Docker: + +```shell +make psalm +``` + +O template guarda a configuração do Psalm em `psalm.xml`. O workflow do +GitHub Actions executa o Psalm nas versões de PHP suportadas. + +Quando o Psalm reportar um problema, corrija o código ou adicione uma +anotação de tipo precisa. Mantenha as supressões restritas e locais à linha +ou ao método que precisa delas. + +## Composer Dependency Analyser + +O Composer Dependency Analyser verifica se o `composer.json` corresponde às +classes usadas pela aplicação. + +Execute-o localmente: + +```shell +vendor/bin/composer-dependency-analyser --config=composer-dependency-analyser.php +``` + +Execute-o no Docker: + +```shell +make composer-dependency-analyser +``` + +Use essa verificação depois de adicionar ou remover o uso de pacotes em +`src`, `config` ou `tests`. + +## PHP CS Fixer + +O PHP CS Fixer aplica o estilo de código do projeto definido em +`.php-cs-fixer.php`. + +Execute-o localmente: + +```shell +vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.php --diff +``` + +Execute-o no Docker: + +```shell +make cs-fix +``` + +Faça o commit das mudanças de formatação junto com o código que as exige. + +## Rector + +O Rector aplica as atualizações e refatorações de código configuradas em +`rector.php`. + +Visualize as mudanças localmente: + +```shell +vendor/bin/rector --dry-run +``` + +Aplique as mudanças localmente: + +```shell +vendor/bin/rector +``` + +Execute-o no Docker: + +```shell +make rector +``` + +Revise as mudanças do Rector antes de fazer o commit. A refatoração +automatizada pode alterar o comportamento quando regras personalizadas ou +caminhos amplos estão configurados. + +## Verificações de pull request + +Uma verificação local prática antes de abrir um pull request é: + +```shell +APP_ENV=test vendor/bin/codecept build +APP_ENV=test vendor/bin/codecept run +vendor/bin/psalm +vendor/bin/composer-dependency-analyser --config=composer-dependency-analyser.php +vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.php --diff +``` + +Com Docker: + +```shell +make codecept build +make test +make psalm +make composer-dependency-analyser +make cs-fix +``` diff --git a/src/pt-BR/guide/testing/unit.md b/src/pt-BR/guide/testing/unit.md new file mode 100644 index 00000000..18c9705e --- /dev/null +++ b/src/pt-BR/guide/testing/unit.md @@ -0,0 +1,213 @@ +# Testes unitários + +Testes unitários verificam diretamente um pequeno trecho de código PHP. No +template de aplicação Yii eles ficam em `tests/Unit` e são executados pela +suíte `Unit` do Codeception. + +O template inclui `tests/Unit/EnvironmentTest.php`: + +```php +generate('Hello, Yii3!'); + + assertSame('hello-yii3', $slug); + } +} +``` + +Execute-o: + +```shell +APP_ENV=test vendor/bin/codecept run Unit SlugGeneratorTest +``` + +## Testar serviços com dependências + +Passe as dependências pelo construtor e use test doubles para I/O. + +Crie `src/Clock/ClockInterface.php`: + +```php +clock->now()); + } +} +``` + +Crie `tests/Unit/PublishPostTest.php`: + +```php +publish('Testing Yii'); + + assertSame('Testing Yii', $post->title); + assertSame('2026-05-07 10:00:00', $post->publishedAt->format('Y-m-d H:i:s')); + } +} +``` + +Execute-o: + +```shell +APP_ENV=test vendor/bin/codecept run Unit PublishPostTest +``` + +Mantenha os testes unitários focados em uma classe ou em uma pequena +colaboração. Use testes funcionais quando o comportamento depende da +configuração do Yii, injeção de dependência, roteamento ou middlewares. diff --git a/src/pt-BR/guide/tutorial/console-applications.md b/src/pt-BR/guide/tutorial/console-applications.md new file mode 100644 index 00000000..f3eedce7 --- /dev/null +++ b/src/pt-BR/guide/tutorial/console-applications.md @@ -0,0 +1,92 @@ +# Aplicações de console + +Aplicações de console são usadas principalmente para criar utilitários, +processamento em segundo plano e tarefas de manutenção. + +## Primeiros passos + +Se você usa [yiisoft/app](https://github.com/yiisoft/app) ou +[yiisoft/app-api](https://github.com/yiisoft/app-api), o suporte a console +já vem incluído. Você pode acessar o ponto de entrada assim: + +``` +./yii +``` + +Se você quer uma aplicação somente de console, use o template de projeto +[yiisoft/app-console](https://github.com/yiisoft/app-console): + +```sh +composer create-project yiisoft/app-console your-project +``` + +Para adicionar suporte a console a um projeto existente do zero, consulte a +[documentação do pacote +yiisoft/yii-console](https://github.com/yiisoft/yii-console). + +De início, apenas o comando `serve` está disponível. Ele inicia o servidor +web embutido do PHP para servir a aplicação localmente. + +Os comandos são executados com `symfony/console`. Para criar seu próprio +comando de console, você precisa definir um comando: + +```php +setHelp('This command serves for demo purpose') + ->addArgument('name', InputArgument::OPTIONAL, 'Name to greet', 'anonymous'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + + $name = $input->getArgument('name'); + $io->success("Hello, $name!"); + return ExitCode::OK; + } +} +``` + +Agora registre o comando em `config/params.php`: + +```php +return [ + 'yiisoft/yii-console' => [ + 'commands' => [ + 'demo:hello' => App\Demo\HelloCommand::class, + ], + ], +]; +``` + +Feito isso, o comando pode ser executado assim + +``` +./yii demo:hello Alice +``` + + +## Referências + +- [Guia do componente Symfony + Console](https://symfony.com/doc/current/components/console.html) diff --git a/src/pt-BR/guide/tutorial/docker.md b/src/pt-BR/guide/tutorial/docker.md new file mode 100644 index 00000000..3e32ed19 --- /dev/null +++ b/src/pt-BR/guide/tutorial/docker.md @@ -0,0 +1,461 @@ +# Docker nos templates de aplicação + +Tanto o [yiisoft/app](https://github.com/yiisoft/app) quanto o +[yiisoft/app-api](https://github.com/yiisoft/app-api) vêm com uma +configuração Docker pronta para uso, baseada em +[FrankenPHP](https://frankenphp.dev/) com Caddy como servidor web embutido. +A configuração cobre desenvolvimento local, testes e deploy em produção por +meio de um conjunto de arquivos de ambiente, configurações do Docker +Compose, um Dockerfile multi-stage e um `Makefile` que encapsula as +operações mais comuns. + +## Visão geral do diretório docker + +Todos os arquivos relacionados ao Docker ficam no diretório `docker/`: + +``` +docker/ +├── .env # Variáveis do Compose (nome da stack, portas, nomes de imagens) +├── Dockerfile # Definição de imagem multi-stage +├── compose.yml # Arquivo Compose base (âncora compartilhada por todos os ambientes) +├── dev/ +│ ├── .env # Variáveis de ambiente da aplicação para desenvolvimento +│ ├── .gitignore # Exclui override.env do controle de versão +│ ├── compose.yml # Overrides do Compose específicos de desenvolvimento +│ └── override.env.example # Template opcional de overrides locais do desenvolvedor +├── test/ +│ ├── .env # Variáveis de ambiente da aplicação para testes +│ ├── .gitignore # Exclui override.env do controle de versão +│ └── compose.yml # Overrides do Compose específicos de testes +└── prod/ + ├── .env # Variáveis de ambiente da aplicação para produção + ├── .gitignore # Exclui override.env do controle de versão + └── compose.yml # Overrides do Compose específicos de produção (Docker Swarm) +``` + +Cada subdiretório (`dev/`, `test/`, `prod/`) corresponde a um estágio de +ambiente e contém seu próprio arquivo `.env` com a configuração da aplicação +e um `compose.yml` que estende o `docker/compose.yml` base. + +## Arquivos de ambiente + +Os templates usam dois sistemas de ambiente separados, com propósitos e +runtimes diferentes. + +### .env.example (raiz do projeto) + +A raiz do projeto contém um arquivo `.env.example` que serve de template +para desenvolvimento local **sem Docker**: + +```ini +# Configuração do ambiente local. +# Copie este arquivo para .env e ajuste conforme necessário. +# Em produção, defina as variáveis de ambiente pela configuração do servidor ou do container. +APP_ENV=dev +APP_DEBUG=true +``` + +Copie-o para criar seu arquivo de configuração local: + +```sh +cp .env.example .env +``` + +O arquivo `.env` é carregado automaticamente por `src/bootstrap.php` usando +o [phpdotenv](https://github.com/vlucas/phpdotenv) somente quando `APP_ENV` +ainda não está presente no ambiente do processo. Isso significa que **as +variáveis de ambiente fornecidas pelo Docker sempre têm precedência** sobre +o arquivo `.env` da raiz — os dois fluxos de trabalho podem coexistir com +segurança no mesmo diretório do projeto. + +> [!NOTE] +> `phpdotenv` é uma dependência de desenvolvimento e não é instalado em produção +> (`composer install --no-dev`), então o arquivo `.env` da raiz não tem efeito nos containers de produção. + +### docker/.env + +Este arquivo contém variáveis usadas pelos próprios arquivos Compose — elas +**não** são repassadas ao container da aplicação em execução: + +```ini +# Variáveis para os arquivos compose.yml. Não disponíveis na aplicação. + +STACK_NAME=app + +# Desenvolvimento + +DEV_PORT=80 + +# Produção + +PROD_HOST=app.example.com +PROD_SSH="ssh://docker-web" + +IMAGE=app +IMAGE_TAG=latest +``` + +| Variável | Finalidade | +|--------------|-------------------------------------------------------------------------| +| `STACK_NAME` | Nome do projeto Docker Compose e nome da stack do Docker Swarm. | +| `DEV_PORT` | Porta do host onde a aplicação é exposta em desenvolvimento (`make up`). | +| `PROD_HOST` | Hostname usado pelos labels do Caddy para HTTPS automático em produção. | +| `PROD_SSH` | Host Docker remoto para deploy em um nó Swarm via SSH. | +| `IMAGE` | Nome da imagem Docker usada no build e no push. | +| `IMAGE_TAG` | Tag da imagem Docker (`latest` por padrão; use uma versão no CI/CD). | + +### docker/dev/.env + +Contém as variáveis de ambiente da aplicação injetadas no container de +desenvolvimento em tempo de execução: + +```ini +# Ambiente dev da aplicação. +# Note que as variáveis ficam disponíveis apenas na aplicação, não no compose.yml. + +APP_ENV=dev +APP_DEBUG=true +SERVER_NAME=:80 +XDEBUG_MODE=develop +COMPOSER_CACHE_DIR=/app/runtime/cache/composer +``` + +| Variável | Finalidade | +|-----------------------|--------------------------------------------------------------------------------------| +| `APP_ENV` | Ambiente da aplicação. `dev` ativa um comportamento amigável para o desenvolvedor. | +| `APP_DEBUG` | Ativa saída de erros detalhada e painéis de debug. | +| `SERVER_NAME` | Endereço do servidor Caddy — `:80` significa escutar em todas as interfaces na porta 80. | +| `XDEBUG_MODE` | Modo do Xdebug. Use `develop` para helpers e `debug` para ativar a depuração passo a passo. | +| `COMPOSER_CACHE_DIR` | Move o cache do Composer para o volume montado, para que persista entre execuções. | + +### docker/test/.env + +Contém as variáveis de ambiente da aplicação para o container de testes: + +```ini +# Ambiente test da aplicação. +# Note que as variáveis ficam disponíveis apenas na aplicação, não no compose.yml. + +APP_ENV=test +APP_DEBUG=false +APP_C3=true +SERVER_NAME=:80 +XDEBUG_MODE=coverage +COMPOSER_CACHE_DIR=/app/runtime/cache/composer +``` + +| Variável | Finalidade | +|----------------------|-----------------------------------------------------------------------------------------------| +| `APP_ENV` | Define o ambiente como `test` para que a aplicação carregue a configuração específica de testes. | +| `APP_DEBUG` | Desativado nos testes para corresponder a um contexto de execução realista. | +| `APP_C3` | Ativa a coleta remota de cobertura de código com [c3](https://github.com/Codeception/c3). | +| `SERVER_NAME` | Endereço do servidor Caddy. | +| `XDEBUG_MODE` | `coverage` ativa o driver de cobertura de código do Xdebug, necessário para os relatórios de cobertura. | +| `COMPOSER_CACHE_DIR` | Cache persistente do Composer dentro do volume. | + +### docker/prod/.env + +Contém as variáveis de ambiente da aplicação para o container de produção: + +```ini +# Ambiente prod da aplicação. +# Note que as variáveis ficam disponíveis apenas na aplicação, não no compose.yml. + +APP_ENV=prod +APP_DEBUG=false +SERVER_NAME=:80 +``` + +O ambiente de produção usa intencionalmente uma configuração +mínima. Segredos e overrides específicos de host devem ser gerenciados pelas +ferramentas de deploy e nunca commitados no controle de versão. + +### Arquivos env de override + +Cada diretório de ambiente contém um `.gitignore` que exclui um arquivo +`override.env`. Esse arquivo é opcional e, quando presente, é mesclado por +cima do `.env` principal daquele ambiente: + +``` +# docker/dev/override.env.example +APP_HOST_PATH=/projects/yiisoft/app +``` + +Copie o arquivo de exemplo para criar seus overrides locais: + +```sh +cp docker/dev/override.env.example docker/dev/override.env +``` + +Use arquivos de override para configurações específicas do desenvolvedor, +como chaves de IDE do Xdebug ou caminhos locais de bind, que não devem ser +compartilhados com o time. + +## Arquivos Compose + +A configuração do Compose é dividida em vários arquivos que o Docker Compose +mescla em tempo de execução. Essa abordagem evita duplicar configurações +compartilhadas e mantém o arquivo de cada ambiente pequeno e focado. + +### docker/compose.yml (base) + +O arquivo base define configurações compartilhadas herdadas por todos os +ambientes: + +```yaml +services: + app: &appconfig + extra_hosts: + - "host.docker.internal:host-gateway" + +volumes: + caddy_data: + caddy_config: +``` + +A âncora YAML `&appconfig` permite que os arquivos de ambiente referenciem e +estendam essa definição de serviço. A entrada `host.docker.internal` aponta +para o host Docker, para que os containers alcancem serviços rodando na +máquina host (por exemplo, um banco de dados local). + +Os dois volumes nomeados (`caddy_data` e `caddy_config`) persistem o +armazenamento de certificados e a configuração do Caddy entre +reinicializações do container. + +### docker/dev/compose.yml + +Estende o arquivo base para desenvolvimento local: + +```yaml +services: + app: + build: + dockerfile: docker/Dockerfile + context: .. + target: dev + args: + USER_ID: ${UID} + GROUP_ID: ${GID} + env_file: + - path: ./dev/.env + - path: ./dev/override.env + required: false + ports: + - "${DEV_PORT:-80}:80" + volumes: + - ../:/app + - ../runtime:/app/runtime + - caddy_data:/data + - caddy_config:/config + tty: true +``` + +Pontos principais: + +- **`target: dev`** — Seleciona o estágio `dev` do Dockerfile multi-stage. +- **`USER_ID` / `GROUP_ID`** — Passados como argumentos de build para que o + usuário do container corresponda ao usuário do host, evitando problemas de + permissão de arquivos no Linux. +- **`env_file`** — Carrega `docker/dev/.env` e, opcionalmente, o + `override.env` local do desenvolvedor. +- **`ports`** — Expõe a porta 80 (ou `DEV_PORT` de `docker/.env`) no host. +- **`volumes`** — Monta o projeto inteiro em `/app` para que mudanças no + código sejam refletidas imediatamente, sem rebuild da imagem. + +### docker/test/compose.yml + +Tem a mesma estrutura do arquivo dev, mas carrega `docker/test/.env` e não +expõe portas para o host, já que os testes rodam inteiramente dentro da rede +de containers. + +### docker/prod/compose.yml + +Voltado a deploys em produção usando Docker Swarm: + +```yaml +services: + app: + image: ${IMAGE}:${IMAGE_TAG} + networks: + - caddy_public + volumes: + - runtime:/app/runtime + - caddy_data:/data + - caddy_config:/config + env_file: + - path: ./prod/.env + - path: ./prod/override.env + required: false + deploy: + replicas: 2 + update_config: + delay: 10s + parallelism: 1 + order: start-first + failure_action: rollback + monitor: 10s + rollback_config: + parallelism: 0 + order: stop-first + restart_policy: + condition: on-failure + delay: 5s + max_attempts: 3 + window: 120s + labels: + caddy: ${PROD_HOST:-app.example.com} + caddy.reverse_proxy: "{{upstreams 80}}" + +volumes: + runtime: + +networks: + caddy_public: + external: true +``` + +Em vez de fazer build de uma imagem, o arquivo de produção referencia uma +imagem pré-construída (`${IMAGE}:${IMAGE_TAG}`). O bloco `deploy` configura +o comportamento do Docker Swarm: duas réplicas com estratégia de atualização +gradual `start-first` e rollback automático em caso de falha. Os labels +`caddy` são lidos por um [Caddy Docker +Proxy](https://github.com/lucaslorentz/caddy-docker-proxy) rodando no mesmo +Swarm para configurar o roteamento HTTPS automático. + +> [!NOTE] +> A rede `caddy_public` precisa existir no Swarm antes do deploy. +> Veja o [guia de deploy com Docker Swarm](../../cookbook/deployment/docker-swarm.md) para instruções completas de configuração. + +## Dockerfile multi-stage + +O `docker/Dockerfile` usa [builds +multi-stage](https://docs.docker.com/build/building/multi-stage/) para +produzir imagens enxutas para cada finalidade a partir de um único arquivo, +evitando duplicar a configuração base: + +```dockerfile +FROM composer/composer:2-bin AS composer + +FROM dunglas/frankenphp:1-php8.2-bookworm AS base + +RUN apt update && apt -y install \ + unzip + +RUN install-php-extensions \ + opcache mbstring intl dom ctype curl phar openssl xml xmlwriter simplexml pdo + +ENV LC_ALL=C.UTF-8 + +# +# Development +# + +FROM base AS dev +ARG USER_ID=10001 +ARG GROUP_ID=10001 +ARG USER_NAME=appuser +ARG GROUP_NAME=appuser + +RUN install-php-extensions xdebug + +COPY --from=composer /composer /usr/bin/composer + +RUN \ + groupadd --gid ${GROUP_ID} ${GROUP_NAME}; \ + useradd --gid ${GROUP_ID} --uid ${USER_ID} ${GROUP_NAME}; \ + setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/frankenphp; \ + chown -R ${USER_NAME}:${GROUP_NAME} /data/caddy && \ + chown -R ${USER_NAME}:${GROUP_NAME} /config/caddy +USER ${USER_NAME} + +# +# Production +# + +FROM base AS prod-builder +COPY --from=composer /composer /usr/bin/composer +COPY .. /app +RUN --mount=type=cache,target=/tmp/cache \ + composer install --no-dev --no-progress --no-interaction --classmap-authoritative && \ + rm composer.lock composer.json + +FROM base AS prod +ENV APP_ENV=prod +COPY --from=prod-builder --chown=www-data:www-data /app /app +USER www-data +``` + +O Dockerfile define quatro estágios: + +| Estágio | Finalidade | +|----------------|--------------------------------------------------------------------------------------------------| +| `composer` | Copia o binário do Composer da imagem oficial para evitar instalá-lo nos outros estágios. | +| `base` | Instala o FrankenPHP, extensões PHP comuns e pacotes de sistema compartilhados por todos os ambientes. | +| `dev` | Estende `base` com Xdebug e Composer. Cria um usuário não root com o mesmo UID/GID do usuário do host para evitar problemas de permissão com volumes montados. | +| `prod-builder` | Estende `base`, copia o código-fonte da aplicação e executa `composer install --no-dev` usando um cache de build. Remove `composer.lock` e `composer.json` em seguida para manter a imagem final limpa. | +| `prod` | Copia apenas a aplicação construída de `prod-builder` para uma imagem `base` limpa. Isso gera uma imagem final pequena, porque o binário do Composer e os arquivos intermediários não são incluídos. | + +> [!TIP] +> Ao construir a imagem de produção, você seleciona um estágio específico com `--target prod`. O estágio `prod-builder` +> é um passo intermediário e nunca é enviado para um registry. + +O alvo `dev` é selecionado ao executar `make up` ou `make build`, enquanto +`make prod-build` usa o alvo `prod`. + +## Comandos make + +O `Makefile` oferece uma interface prática para todas as operações Docker +comuns. Execute `make` ou `make help` para listar os alvos disponíveis com +suas descrições. + +### Desenvolvimento + +| Comando | Descrição | +|---------------|----------------------------------------------------------------| +| `make build` | Faz o build (ou rebuild) da imagem Docker de desenvolvimento. | +| `make up` | Inicia o ambiente de desenvolvimento em modo detached. | +| `make down` | Para e remove containers, redes e serviços órfãos. | +| `make stop` | Para os containers em execução sem removê-los. | +| `make clear` | Remove todos os containers, redes e volumes de desenvolvimento. | +| `make shell` | Abre um shell Bash interativo dentro do container `app` em execução. | + +### Executando ferramentas + +Os comandos deste grupo rodam dentro do container de desenvolvimento usando +`docker compose run --rm`, então funcionam mesmo quando o container não está +em execução: + +| Comando | Descrição | +|--------------------------------------|-------------------------------------------------| +| `make yii ` | Executa um comando de console `./yii`. | +| `make composer ` | Executa o Composer. | +| `make rector` | Executa o [Rector](https://getrector.com/) para refatoração automatizada de PHP e melhorias de qualidade de código. | +| `make cs-fix` | Executa o [PHP CS Fixer](https://cs.symfony.com/). | +| `make psalm` | Executa a análise estática do [Psalm](https://psalm.dev/). | +| `make composer-dependency-analyser` | Executa o [Composer Dependency Analyser](https://github.com/shipmonk-rnd/composer-dependency-analyser). | + +### Testes + +| Comando | Descrição | +|------------------------|-----------------------------------------------------------| +| `make test` | Executa a suíte de testes completa com Codeception. | +| `make test-coverage` | Executa os testes e gera um relatório de cobertura em HTML. | +| `make codecept ` | Executa qualquer comando do Codeception com argumentos personalizados. | + +### Produção + +| Comando | Descrição | +|----------------------|-------------------------------------------------------------------------------------| +| `make prod-build` | Faz o build local da imagem Docker de produção (`--target prod`). | +| `make prod-push` | Envia a imagem construída para o registry definido por `IMAGE` e `IMAGE_TAG`. | +| `make prod-deploy` | Faz o deploy da stack em um nó Docker Swarm remoto definido por `PROD_SSH`. | + +> [!TIP] +> A maioria dos comandos aceita argumentos adicionais. Por exemplo, para instalar um pacote específico: +> ```sh +> make composer require yiisoft/yii-db-mysql +> ``` +> Para executar uma única suíte de testes: +> ```sh +> make test -- Unit +> ``` diff --git a/src/pt-BR/guide/tutorial/i18n.md b/src/pt-BR/guide/tutorial/i18n.md new file mode 100644 index 00000000..3b5cc401 --- /dev/null +++ b/src/pt-BR/guide/tutorial/i18n.md @@ -0,0 +1,455 @@ +# Internacionalização + +A internacionalização prepara uma aplicação para mais de um locale. A +localização é a parte específica de cada locale: textos traduzidos, formas +de plural, formatos de data e número e templates de view para um locale como +`en-US` ou `de`. + +Numa aplicação Yii, as partes habituais são: + +- a escolha do idioma da requisição atual; +- as mensagens traduzidas da aplicação; +- a formatação de plurais e parâmetros; +- templates de view localizados para páginas que precisam de marcação + diferente. + +Este tutorial parte de um projeto novo do +[yiisoft/app](https://github.com/yiisoft/app). + +## Instalando os pacotes + +O `yiisoft/app` já inclui `yiisoft/i18n` e `yiisoft/translator`. Instale o +armazenamento de mensagens em arquivos PHP: + +```sh +composer require yiisoft/translator-message-php +``` + +Instale o extrator como dependência de desenvolvimento: + +```sh +composer require --dev yiisoft/translator-extractor +``` + +Os exemplos usam a formatação de mensagens ICU para as formas de +plural. Confira se a extensão `intl` do PHP está habilitada. Se você só +precisa de placeholders simples, use +`Yiisoft\Translator\SimpleMessageFormatter` na configuração abaixo. + +## Configurando o idioma da aplicação + +O template da aplicação guarda as configurações básicas em +`config/common/application.php`. Defina ali o idioma de origem: + +```php + 'UTF-8', + 'locale' => 'en-US', + 'name' => 'My Project', +]; +``` + +O layout padrão usa esse valor no atributo `` por meio de `ApplicationParams`. +Quando a aplicação escolhe o idioma por requisição, defina o idioma escolhido na view, como mostrado em +[Escolhendo o idioma por requisição](#escolhendo-o-idioma-por-requisicao). + +Configure os padrões do tradutor em `config/common/params.php`: + +```php +'yiisoft/translator' => [ + 'locale' => 'en-US', + 'fallbackLocale' => 'en-US', + 'defaultCategory' => 'app', +], +``` + +`locale` é o idioma padrão das traduções. `fallbackLocale` é usado quando +falta uma tradução para o idioma atual. `defaultCategory` é a categoria +usada quando uma chamada a `translate()` não especifica nenhuma. + +## Configurando o armazenamento de mensagens + +Crie `config/common/di/translator.php`: + +```php + [ + 'definition' => static function (Aliases $aliases) use ($params): CategorySource { + $messageSource = new MessageSource($aliases->get('@root/messages')); + + return new CategorySource( + $params['yiisoft/translator']['defaultCategory'], + $messageSource, + new IntlMessageFormatter(), + $messageSource, + ); + }, + 'tags' => ['translation.categorySource'], + ], +]; +``` + +Isso registra a categoria `app`. O `MessageSource` lê arrays PHP do +diretório `messages/` e grava as mensagens extraídas de volta no mesmo +diretório. + +Crie os arquivos de mensagens de origem e de destino: + +``` +messages/ +├── de/ +│ └── app.php +└── en-US/ + └── app.php +``` + +`messages/en-US/app.php`: + +```php + 'Home', + 'home.welcome' => 'Welcome to Yii3', + 'cart.items' => '{count, plural, =0{No items} one{# item} other{# items}}', +]; +``` + +`messages/de/app.php`: + +```php + 'Home', + 'home.welcome' => 'Willkommen bei Yii3', + 'cart.items' => '{count, plural, =0{Keine Artikel} one{# Artikel} other{# Artikel}}', +]; +``` + +## Traduzindo mensagens + +Injete `Yiisoft\Translator\TranslatorInterface` onde você prepara os dados +de uma resposta. Para a action padrão da página inicial, altere +`src/Web/HomePage/Action.php`: + +```php +viewRenderer->render(__DIR__ . '/template', [ + 'itemCount' => 3, + 'translator' => $this->translator, + ]); + } +} +``` + +Use o tradutor em `src/Web/HomePage/template.php`: + +```php +setTitle($translator->translate('home.title')); +?> + +
+

translate('home.welcome')) ?>

+ +

translate('cart.items', ['count' => $itemCount])) ?>

+
+``` + +Escape o texto traduzido antes de exibi-lo. Guarde HTML confiável +separadamente ou renderize-o a partir de um template de view. + +## Escolhendo o idioma por requisição + +Numa aplicação web, escolha o idioma cedo na pilha de middlewares e +aplique-o tanto ao tradutor quanto à view. O exemplo abaixo usa o parâmetro +`lang` da query string e uma lista fixa de idiomas permitidos: + +```php +getLocale($request); + + $this->translator->setLocale($locale); + $this->view->setLocale($locale); + + return $handler->handle($request); + } + + private function getLocale(ServerRequestInterface $request): string + { + $locale = $request->getQueryParams()['lang'] ?? null; + + return is_string($locale) && in_array($locale, self::SUPPORTED_LOCALES, true) + ? $locale + : self::DEFAULT_LOCALE; + } +} +``` + +Registre o middleware em `config/common/routes.php` ou no grupo de rotas que +precisa de saída localizada. Adicione o middleware antes da action da rota: + +```php +use App\Web\Middleware\LocaleMiddleware; +use Yiisoft\Router\Route; + +return [ + Route::get('/') + ->middleware(LocaleMiddleware::class) + ->action(App\Web\HomePage\Action::class) + ->name('home'), +]; +``` + +Altere `src/Web/Shared/Layout/Main/layout.php` para ler o idioma do estado +atual da view: + +```php + +``` + +Use a mesma abordagem quando o idioma estiver guardado na sessão, num +cookie, no perfil do usuário ou num parâmetro de rota. + +O `yiisoft/i18n` oferece `Yiisoft\I18n\Locale` para trabalhar com códigos de +locale BCP 47: + +```php +use Yiisoft\I18n\Locale; + +$locale = new Locale('de-DE'); + +echo $locale->language(); // de +echo $locale->region(); // DE +echo $locale->fallbackLocale()->asString(); // de +``` + +Isso é útil quando você precisa derivar um idioma de reserva ou inspecionar +as partes do locale antes de escolher um idioma suportado. + +## Arquivos de view localizados + +Use tradução de mensagens para rótulos, títulos, botões, mensagens de +validação e parágrafos curtos. Use arquivos de view localizados quando uma +página precisa de marcação diferente ou de uma quantidade diferente de texto +para cada idioma. + +O `yiisoft/view` procura arquivos localizados num subdiretório com o nome do +locale, ao lado do arquivo de view original. Por exemplo, quando +`src/Web/HomePage/template.php` é renderizado com o locale `de-DE`, o Yii +verifica: + +1. `src/Web/HomePage/de-DE/template.php` +2. `src/Web/HomePage/de/template.php` +3. `src/Web/HomePage/template.php` + +O fallback para o código de idioma de duas letras é automático. + +Você pode definir o idioma para uma única chamada de renderização: + +```php +return $this->viewRenderer + ->withLocale('de-DE') + ->render(__DIR__ . '/template'); +``` + +Quando o idioma é definido no `WebView` dentro de um middleware, o mesmo +idioma é aplicado às views renderizadas pelo `WebViewRenderer`. + +## Extraindo mensagens + +Configure o extrator para que ele consiga ler as mensagens existentes e +gravar novos IDs no mesmo armazenamento de mensagens. + +Crie `config/common/di/translator-extractor.php`: + +```php + [ + '__construct()' => [ + [ + DynamicReference::to([ + 'class' => ExtractorCategorySource::class, + '__construct()' => [ + $params['yiisoft/translator']['defaultCategory'], + DynamicReference::to( + static fn (Aliases $aliases): MessageSource => new MessageSource($aliases->get('@root/messages')), + ), + DynamicReference::to( + static fn (Aliases $aliases): MessageSource => new MessageSource($aliases->get('@root/messages')), + ), + ], + ]), + ], + ], + ], +]; +``` + +Reconstrua a configuração depois de adicionar o arquivo de configuração do +extrator: + +```sh +composer yii-config-rebuild +``` + +Extraia as mensagens dos arquivos-fonte da aplicação: + +```sh +./yii translator/extract src --languages=en-US,de +``` + +O comando procura chamadas como: + +```php +$translator->translate('home.welcome'); +$translator->translate('cart.items', ['count' => $itemCount]); +``` + +Ele grava os IDs que faltam em: + +``` +messages/en-US/app.php +messages/de/app.php +``` + +Depois da extração, edite os arquivos dos idiomas de destino e troque os IDs +de origem pelo texto traduzido. + +Use `--category` quando uma chamada pertence a outra categoria: + +```sh +./yii translator/extract src --languages=en-US,de --category=shop +``` + +O extrator exclui `vendor/` por padrão. Use `--only` ou `--except` quando +precisar de uma varredura mais restrita: + +```sh +./yii translator/extract src --languages=en-US,de --only=**/*.php --except=**/runtime/** +``` + +## Trabalhando com categorias + +A categoria padrão `app` basta para a maioria das mensagens da +aplicação. Adicione categorias quando um pacote ou um recurso grande tem +seus próprios arquivos de mensagens. + +Para uma categoria `shop`, crie outro category source com a tag: + +```php +'translation.shop' => [ + 'definition' => static function (Aliases $aliases): CategorySource { + $messageSource = new MessageSource($aliases->get('@root/messages')); + + return new CategorySource( + 'shop', + $messageSource, + new IntlMessageFormatter(), + $messageSource, + ); + }, + 'tags' => ['translation.categorySource'], +], +``` + +Traduza informando o nome da categoria: + +```php +$translator->translate('checkout.submit', category: 'shop'); +``` + +Os arquivos de mensagens ficam assim: + +``` +messages/de/shop.php +messages/en-US/shop.php +``` + +Mantenha os IDs de mensagens estáveis. Mudar um ID cria uma nova tarefa de +tradução para cada idioma. diff --git a/src/pt-BR/guide/tutorial/mailing.md b/src/pt-BR/guide/tutorial/mailing.md new file mode 100644 index 00000000..1e80556f --- /dev/null +++ b/src/pt-BR/guide/tutorial/mailing.md @@ -0,0 +1,332 @@ +# Envio de e-mails + +O Yii simplifica a composição e o envio de e-mails com o pacote +[yiisoft/mailer](https://github.com/yiisoft/mailer). Esse pacote oferece a +composição do conteúdo e uma interface básica para enviar e-mails. Por +padrão, o pacote inclui um mailer de arquivo, que grava o conteúdo dos +e-mails num arquivo em vez de enviá-los. Isso é especialmente útil nas fases +iniciais do desenvolvimento da aplicação. + +Para enviar e-mails de verdade, você pode usar a implementação com [Symfony +Mailer](https://github.com/yiisoft/mailer-symfony), que é a usada nos +exemplos abaixo. + +## Configurando o mailer + +O serviço de mailer permite criar uma instância de mensagem, preenchê-la com +dados e enviá-la. Normalmente, você obtém uma instância do container de DI +como `Yiisoft\Mailer\MailerInterface`. + +Você também pode criar uma instância manualmente: + +```php + +use Yiisoft\Mailer\Symfony\Mailer; + +/** + * @var \Symfony\Component\Mailer\Transport\TransportInterface $transport + */ + +$mailer = new \Yiisoft\Mailer\Symfony\Mailer( + $transport, +); +``` + +A `Yiisoft\Mailer\MailerInterface` oferece dois métodos principais: + +- `send()` - Envia a mensagem de e-mail informada. +- `sendMultiple()` - Envia várias mensagens de uma vez. + +## Criando uma mensagem + +### Mensagem de texto simples + +Para criar uma mensagem simples com corpo em texto, use +`Yiisoft\Mailer\Message`: + +```php +$message = new \Yiisoft\Mailer\Message( + from: 'from@domain.com', + to: 'to@domain.com', + subject: 'Message subject', + textBody: 'Plain text content' +); +``` + +### Mensagem HTML simples + +```php +$message = new \Yiisoft\Mailer\Message( + from: 'from@domain.com', + to: 'to@domain.com', + subject: 'Message subject', + htmlBody: 'HTML content' +); +``` + +### Mensagem HTML a partir de um template + +Neste exemplo, vamos usar o pacote de renderização +[view](https://github.com/yiisoft/view). + +```php +/** + * @var \Yiisoft\View\View $view + */ + +$content = $view->render('path/to/view.php', [ + 'name' => 'name', + 'code' => 'code', +]); + +$message = new \Yiisoft\Mailer\Message( + from: 'from@domain.com', + to: 'to@domain.com', + subject: 'Subject', + htmlBody: $content +); +``` + +### Usando layouts + +Você também pode passar parâmetros para os layouts a partir do template da +mensagem: + +```php +/** + * @var \Yiisoft\View\View $view + * @var array $layoutParameters + */ + +$messageBody = $view->render('path/to/view.php', [ + 'name' => 'name', + 'code' => 'code', +]); + +$layoutParameters['content'] = $messageBody; + +$content = $view->render('path/to/layout.php', $layoutParameters); + +$message = new \Yiisoft\Mailer\Message( + from: 'from@domain.com', + to: 'to@domain.com', + subject: 'Subject', + htmlBody: $content +); +``` + +### Exemplo de layout + +Você pode envolver o resultado da renderização da view num layout, do mesmo +jeito que os layouts funcionam em aplicações web. Isso é útil para definir +conteúdo compartilhado, como estilos CSS: + +```php + + + + + + + + + + +
+--
+Mailed by Yii +
+ + + +``` + +## Adicionando mais dados + +A `Yiisoft\Mailer\MessageInterface` oferece vários métodos para personalizar +a mensagem: + +- `withCharset()` - Retorna uma nova instância com o charset informado. +- `withFrom()` - Retorna uma nova instância com o endereço de e-mail do + remetente informado. +- `withTo()` - Retorna uma nova instância com o(s) endereço(s) de e-mail + do(s) destinatário(s) informado(s). +- `withReplyTo()` - Retorna uma nova instância com o endereço de resposta + (reply-to) informado. +- `withCc()` - Retorna uma nova instância com os endereços em Cc + (destinatários de cópia) informados. +- `withBcc()` - Retorna uma nova instância com os endereços em Bcc + (destinatários de cópia oculta) informados. +- `withSubject()` - Retorna uma nova instância com o assunto da mensagem + informado. +- `withDate()` - Retorna uma nova instância com a data de envio da mensagem + informada. +- `withPriority()` - Retorna uma nova instância com a prioridade da mensagem + informada. +- `withReturnPath()` - Retorna uma nova instância com o return-path + (endereço de bounce) da mensagem informado. +- `withSender()` - Retorna uma nova instância com o endereço de e-mail do + remetente real informado. +- `withHtmlBody()` - Retorna uma nova instância com o conteúdo HTML da + mensagem informado. +- `withTextBody()` - Retorna uma nova instância com o conteúdo em texto puro + da mensagem informado. +- `withAddedHeader()` - Retorna uma nova instância com o valor de header + personalizado adicionado. +- `withHeader()` - Retorna uma nova instância com o valor de header + personalizado informado. +- `withHeaders()` - Retorna uma nova instância com os valores de headers + personalizados informados. + +Esses métodos são imutáveis, ou seja, retornam uma nova instância da +mensagem com os dados atualizados. + +Repare no prefixo `with`. Ele indica que o método é imutável e retorna uma +nova instância da classe com os dados alterados. + +### Getters + +Os getters a seguir estão disponíveis para obter os dados da mensagem: + +- `getCharset()` - Retorna o charset da mensagem. +- `getFrom()` - Retorna o endereço de e-mail do remetente da mensagem. +- `getTo()` - Retorna o(s) endereço(s) de e-mail do(s) destinatário(s) da + mensagem. +- `getReplyTo()` - Retorna o endereço de resposta (reply-to) da mensagem. +- `getCc()` - Retorna os endereços em Cc (destinatários de cópia) da + mensagem. +- `getBcc()` - Retorna os endereços em Bcc (destinatários de cópia oculta) + da mensagem. +- `getSubject()` - Retorna o assunto da mensagem. +- `getDate()` - Retorna a data de envio da mensagem, ou null se ela não foi + definida. +- `getPriority()` - Retorna a prioridade da mensagem. +- `getReturnPath()` - Retorna o return-path (endereço de bounce) da + mensagem. +- `getSender()` - Retorna o endereço de e-mail do remetente real da + mensagem. +- `getHtmlBody()` - Retorna o corpo HTML da mensagem. +- `getTextBody()` - Retorna o corpo em texto da mensagem. +- `getHeader()` - Retorna todos os valores do header informado. +- `__toString()` - Retorna a representação em string da mensagem. + +## Anexando arquivos + +Você pode anexar arquivos à mensagem com o método `withAttached()`: + +```php +use Yiisoft\Mailer\File; + +// Anexa um arquivo do sistema de arquivos local +$message = $message->withAttached( + File::fromPath('/path/to/source/file.pdf'), +); + +// Cria um anexo na hora +$message = $message->withAttached( + File::fromContent('Attachment content', 'attach.txt', 'text/plain'), +); +``` + +## Incorporando imagens + +Você pode incorporar imagens ao conteúdo da mensagem com o método +`withEmbedded()`. Isso é especialmente útil ao compor mensagens com views: + +```php +$logo = 'path/to/logo'; +$htmlBody = $this->view->render( + __DIR__ . 'template.php', + [ + 'content' => $content, + 'logoCid' => $logo->cid(), + ], +); +return new \Yiisoft\Mailer\Message( + from: 'from@domain.com', + to: 'to@domain.com', + subject: 'Message subject', + htmlBody: $htmlBody, + embeddings: $logo + ); +``` + +No template da view ou do layout, você pode referenciar a imagem incorporada +pelo seu CID: + +```php + +``` + +## Enviando uma mensagem + +Para enviar uma mensagem de e-mail: + +```php +/** + * @var \Yiisoft\View\View $view + */ + +$content = $view->render('path/to/view.php', [ + 'name' => 'name', + 'code' => 'code', +]); + +$message = new \Yiisoft\Mailer\Message( + from: 'from@domain.com', + to: 'to@domain.com', + subject: 'Subject', + htmlBody: $content +); + +$mailer->send($message); +``` + +## Enviando várias mensagens + +Você pode enviar várias mensagens de uma vez: + +```php +$messages = []; + +foreach ($users as $user) { + $messages[] = (new \Yiisoft\Mailer\Message()) + // ... + ->withTo($user->email); +} + +$result = $mailer->sendMultiple($messages); +``` + +O método `sendMultiple()` retorna um objeto `Yiisoft\Mailer\SendResults` com +arrays das mensagens enviadas com sucesso e das que falharam. + +## Implementando seu próprio driver de e-mail + +Para criar uma solução de e-mail personalizada, implemente as interfaces +`Yiisoft\Mailer\MailerInterface` e `Yiisoft\Mailer\MessageInterface`. + +## Para desenvolvimento + +Em desenvolvimento local ou em testes, você pode usar implementações +simplificadas do mailer que não enviam e-mails. O pacote oferece estas +implementações: + +- `Yiisoft\Mailer\StubMailer` - Um mailer simples que guarda as mensagens + num array local. +- `Yiisoft\Mailer\FileMailer` - Um mailer de mentira que grava as mensagens + de e-mail em arquivos em vez de enviá-las. +- `Yiisoft\Mailer\NullMailer` - Um mailer que descarta as mensagens sem + enviá-las nem guardá-las. + +Para usar um desses mailers, configure-o no arquivo de ambiente de +desenvolvimento. Exemplo: `environments/local/di.php` + +```php +return [ + Yiisoft\Mailer\MailerInterface::class => Yiisoft\Mailer\StubMailer::class, //ou qualquer outro +]; + +``` diff --git a/src/pt-BR/guide/tutorial/performance-tuning.md b/src/pt-BR/guide/tutorial/performance-tuning.md new file mode 100644 index 00000000..77620c4b --- /dev/null +++ b/src/pt-BR/guide/tutorial/performance-tuning.md @@ -0,0 +1,220 @@ +# Ajuste de desempenho + +Muitos fatores afetam o desempenho da sua aplicação. Alguns são do ambiente, +outros estão ligados ao seu código, e outros ao próprio Yii. Nesta seção, +listamos a maioria desses fatores e explicamos como você pode melhorar o +desempenho da aplicação ajustando cada um deles. + + +## Otimizando o ambiente PHP + +Um ambiente PHP bem configurado é importante. Para obter o máximo de +desempenho: + +- Use a versão estável mais recente do PHP. Versões principais do PHP podem + trazer ganhos de desempenho significativos. +- Ative o cache de bytecode com o + [Opcache](https://secure.php.net/opcache). O cache de bytecode evita o + tempo gasto para analisar e incluir os scripts PHP a cada requisição. +- [Ajuste o cache do + `realpath()`](https://github.com/samdark/realpath_cache_tuner). +- Garanta que o [XDebug](https://xdebug.org/) não esteja instalado no + ambiente de produção. +- Experimente o [preload do PHP 7](https://wiki.php.net/rfc/preload). + +## Otimizando o seu código + +Além da configuração do ambiente, há otimizações no nível do código que +podem melhorar o desempenho da aplicação: + +- Fique atento à [complexidade dos + algoritmos](https://en.wikipedia.org/wiki/Time_complexity). Preste + atenção especial a loops `foreach` dentro de `foreach`, mas também ao uso + de [funções PHP + pesadas](https://stackoverflow.com/questions/2473989/list-of-big-o-for-php-functions) + dentro de loops. +- [Acelerando o + array_merge()](https://www.exakat.io/speeding-up-array_merge/) +- [Mova aquele foreach() para dentro do + método](https://www.exakat.io/move-that-foreach-inside-the-method/) +- [Uso de memória de arrays, classes e classes + anônimas](https://www.exakat.io/array-classes-and-anonymous-memory-usage/) +- Use nomes de funções totalmente qualificados, com barra invertida no + início, para otimizar o desempenho do opcache. Ao chamar [certas funções + globais](https://github.com/php/php-src/blob/944b6b6bbd6f05ad905f5f4ad07445792bee4027/Zend/zend_compile.c#L4291-L4353) + de dentro de um namespace, o PHP primeiro procura no namespace atual antes + de recorrer ao namespace global. Adicionar a barra invertida no início + (por exemplo, `\count()` em vez de `count()`) diz ao PHP para usar + diretamente a função global, evitando a busca no namespace e melhorando a + eficiência do opcache. O melhor é aplicar essa otimização automaticamente + com ferramentas como o + [PHP-CS-Fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer), usando a + regra `native_function_invocation`. + +As otimizações acima só trazem um ganho de desempenho significativo se o +código em questão for executado com frequência. Normalmente é o caso de +loops grandes ou de processamento em lote. + +## Usando técnicas de cache + +Você pode usar várias técnicas de cache para melhorar bastante o desempenho +da aplicação. Por exemplo, se a sua aplicação permite que os usuários +digitem texto em Markdown, considere guardar em cache o conteúdo Markdown já +processado, para não processar o mesmo texto repetidamente a cada +requisição. Consulte a seção de [Cache](../caching/overview.md) para +conhecer o suporte a cache oferecido pelo Yii. + + +## Otimizando o armazenamento de sessões + +Por padrão, os dados de sessão são guardados em arquivos. A implementação trava o arquivo desde a abertura da sessão até o momento em que ela é +fechada, seja por `$session->close()` ou no fim da requisição. +Enquanto o arquivo de sessão está travado, todas as outras requisições que tentam usar a mesma sessão ficam bloqueadas, esperando a +requisição inicial liberar o arquivo de sessão. Isso serve para desenvolvimento e, provavelmente, para projetos pequenos. Mas quando se trata +de lidar com muitas requisições concorrentes, é melhor usar um armazenamento mais sofisticado, como o Redis. + +Isso pode ser feito [configurando o PHP via +php.ini](https://www.digitalocean.com/community/tutorials/how-to-set-up-a-redis-server-as-a-session-handler-for-php-on-ubuntu-14-04) +ou [implementando a +SessionHandlerInterface](https://www.sitepoint.com/saving-php-sessions-in-redis/) +e configurando o serviço de sessão assim: + +```php +\Yiisoft\Session\SessionInterface::class => [ + 'class' => \Yiisoft\Session\Session::class, + '__construct()' => [[], $myCustomSessionHandler], +], +``` + +## Otimizando bancos de dados + +Executar consultas e buscar dados no banco de dados costuma ser o principal +gargalo de desempenho de uma aplicação web. Embora técnicas de [cache de +dados](../caching/data.md) possam amenizar o impacto, elas não resolvem +totalmente o problema. Quando o banco de dados tem uma quantidade enorme de +dados e os dados em cache ficam inválidos, buscar os dados mais recentes +pode ficar caro demais sem um bom projeto de banco de dados e de consultas. + +Uma técnica geral para melhorar o desempenho das consultas é criar índices +nas colunas das tabelas usadas em filtros. Por exemplo, se você precisa +buscar o registro de um usuário pelo `username`, crie um índice em +`username`. Note que, embora a indexação possa deixar as consultas SELECT +muito mais rápidas, ela deixa as consultas INSERT, UPDATE e DELETE mais +lentas. + +Para consultas complexas, é recomendável criar views no banco de dados para +economizar o tempo de análise e preparação da consulta. + +Por último, mas não menos importante, use `LIMIT` nas suas consultas +`SELECT`. Isso evita buscar uma quantidade excessiva de dados no banco e +esgotar a memória alocada para o PHP. + + +## Otimizando o autoloader do Composer + +Como o autoloader do Composer é usado para incluir a maioria dos arquivos de +classes de terceiros, considere otimizá-lo executando o seguinte comando: + +``` +composer dumpautoload -o +``` + +Além disso, você pode considerar o uso de [class maps +autoritativos](https://getcomposer.org/doc/articles/autoloader-optimization.md#optimization-level-2-a-authoritative-class-maps) +e do [cache +APCu](https://getcomposer.org/doc/articles/autoloader-optimization.md#optimization-level-2-b-apcu-cache). +Note que essas duas otimizações podem ou não ser adequadas ao seu caso. + + +## Processando dados offline + +Quando uma requisição envolve operações que consomem muitos recursos, pense +em formas de executá-las em modo offline, sem fazer os usuários esperarem +que terminem. + +Há dois métodos para processar dados offline: pull e push. + +No método pull, sempre que uma requisição envolve alguma operação complexa, +você cria uma tarefa e a salva num armazenamento persistente, como um banco +de dados. Depois, usa um processo separado (como um cron job) para buscar as +tarefas e processá-las. Esse método é simples de implementar, mas tem +algumas desvantagens. Por exemplo, o processo de tarefas precisa consultar +periodicamente o armazenamento de tarefas. Se a frequência for baixa demais, +as tarefas podem ser processadas com muito atraso; se for alta demais, gera +muito overhead. + +No método push, você usa uma fila de mensagens (por exemplo, RabbitMQ, +ActiveMQ, Amazon SQS etc.) para gerenciar as tarefas. Sempre que uma nova +tarefa entra na fila, ela inicia ou notifica o processo responsável, que +dispara o processamento da tarefa. + +## Usando preload + +A partir do PHP 7.4.0, o PHP pode ser configurado para pré-carregar scripts +no opcache quando o engine inicia. Saiba mais na +[documentação](https://www.php.net/manual/en/opcache.preloading.php) e na +[RFC](https://wiki.php.net/rfc/preload) correspondente. + +Note que o equilíbrio ideal entre desempenho e memória pode variar conforme +a aplicação. "Pré-carregar tudo" pode ser a estratégia mais fácil, mas não +necessariamente a melhor. + +Por exemplo, fizemos um benchmark simples do template de aplicação +[yiisoft/app](https://github.com/yiisoft/app): sem preload e com preload de +todo o class map do Composer. + +### Benchmarks de preload + +O benchmark do template de aplicação inclui a configuração das classes para +as dependências injetadas no script de bootstrap. + +Nas duas variantes, foi usado o +[ApacheBench](https://httpd.apache.org/docs/2.4/programs/ab.html) com os +seguintes parâmetros de execução: + +```shell +ab -n 1000 -c 10 -t 10 +``` + +Além disso, o modo debug estava desativado. Também foi usado um autoloader +otimizado do [Composer](https://getcomposer.org), sem as dependências de +desenvolvimento: + +```shell +composer install --optimize-autoloader --no-dev +``` + +Com o preload ativado, foi usado todo o class map do Composer (825 +arquivos): + +```php +$files = require 'vendor/composer/autoload_classmap.php'; + +foreach (array_unique($files) as $file) { + opcache_compile_file($file); +} +``` + +#### Resultados dos testes + +| Benchmark | Arquivos pré-carregados | Memória do Opcache usada | Memória usada por requisição | Tempo por requisição | Requisições por segundo | +|--------------------|-------------------------|--------------------------|------------------------------|----------------------|-------------------------| +| Sem preload | 0 | 12.32 mb | 1.71 mb | 27.63 ms | 36.55 rq/s | +| Com preload | 825 | 17.86 mb | 1.82 mb | 26.21 ms | 38.42 rq/s | + +Como você pode ver, os resultados não são muito diferentes, já que este é +apenas um template de aplicação limpo, com poucas classes. Mais discussões +sobre preload, incluindo benchmarks, estão na [issue do +Composer](https://github.com/composer/composer/issues/7777). + +## Profiling de desempenho + +Faça o profiling do seu código para encontrar os gargalos de desempenho e +tomar as medidas adequadas. As seguintes ferramentas de profiling podem ser +úteis: + + + +- [Blackfire](https://blackfire.io/) +- [XHProf](https://secure.php.net/manual/en/book.xhprof.php) +- [Profiler do XDebug](https://xdebug.org/docs/profiler) diff --git a/src/pt-BR/guide/tutorial/using-with-event-loop.md b/src/pt-BR/guide/tutorial/using-with-event-loop.md new file mode 100644 index 00000000..f9fccd26 --- /dev/null +++ b/src/pt-BR/guide/tutorial/using-with-event-loop.md @@ -0,0 +1,70 @@ +# Usando o Yii com event loop + +O ciclo normal de execução de uma requisição web em PHP consiste em preparar o ambiente, receber a requisição, processá-la para gerar uma resposta +e enviar o resultado. Depois que a resposta é enviada, a execução termina e o contexto se perde. Então, na requisição + seguinte, toda a sequência se repete. Essa abordagem tem uma grande vantagem na facilidade de desenvolvimento, já que o desenvolvedor não +precisa se preocupar muito com vazamentos de memória nem com limpar o contexto corretamente. Por outro lado, inicializar tudo a +cada requisição leva tempo e, no total, consome até 50% dos recursos de processamento. + +Existe outra forma de rodar uma aplicação: o event loop. A ideia é +inicializar tudo o que for possível uma única vez e depois processar várias +requisições usando esse contexto. Essa abordagem costuma ser chamada de +event loop. + +Há várias ferramentas que permitem fazer isso. As principais são +[FrankenPHP](https://frankenphp.dev/), [Rapira](https://rapira.rs/), +[RoadRunner](https://roadrunner.dev/) e [Swoole](https://www.swoole.com/). + +## Implicações do event loop + +Um worker de event loop basicamente tem esta cara: + +```php +initializeContext(); +while ($request = getRequest()) { + $response = process($request); + emit($response); +} +``` + +Normalmente, há vários workers processando requisições ao mesmo tempo, como +no php-fpm tradicional. + +Isso significa que há mais coisas a considerar ao desenvolver aplicações. + +### O processamento é bloqueante + +O worker processa as requisições uma a uma, ou seja, o processamento atual +bloqueia o processamento da próxima requisição. Isso significa que processos +demorados, assim como em aplicações PHP comuns, devem ir para segundo plano +usando uma fila. + +### Serviços e estado + +Como o contexto no event loop é compartilhado entre todas as requisições e +respostas processadas por um mesmo worker, qualquer mudança no estado de um +serviço feita pela requisição anterior pode afetar a requisição atual. Além +disso, isso pode ser um problema de segurança se os dados de um usuário +ficarem disponíveis para outro. + +Há duas formas de lidar com isso. A primeira é evitar estado, tornando os +serviços stateless. A palavra-chave `readonly` do PHP pode ajudar nisso. A +segunda é redefinir o estado dos serviços ao fim do processamento da +requisição. Nesse caso, um state resetter vai ajudar você: + +```php +initializeContext(); +$resetter = $container->get(\Yiisoft\Di\StateResetter::class); +while ($request = getRequest()) { + $response = process($request); + emit($response); + $resetter->reset(); // Precisamos redefinir o estado desses serviços a cada requisição. +} +``` + +## Integrações + +- [FrankenPHP](using-yii-with-frankenphp.md) +- [Rapira](using-yii-with-rapira.md) +- [RoadRunner](using-yii-with-roadrunner.md) +- [Swoole](using-yii-with-swoole.md) diff --git a/src/pt-BR/guide/tutorial/using-yii-with-frankenphp.md b/src/pt-BR/guide/tutorial/using-yii-with-frankenphp.md new file mode 100644 index 00000000..9b04fe92 --- /dev/null +++ b/src/pt-BR/guide/tutorial/using-yii-with-frankenphp.md @@ -0,0 +1,264 @@ +# Usando o Yii com FrankenPHP + +O [FrankenPHP](https://frankenphp.dev/) é um servidor de aplicação PHP com o Caddy embutido. Ele pode rodar o Yii em +[modo worker](using-with-event-loop.md), o que faz o bootstrap do framework acontecer uma vez por worker em vez de +uma vez por requisição. + +## Instalação + +O [runner para FrankenPHP](https://github.com/yiisoft/yii-runner-frankenphp) +exige PHP 8.1–8.5. Instale o FrankenPHP seguindo as [instruções de +instalação](https://frankenphp.dev/docs/) dele, ou use a configuração Docker +dos templates de aplicação do Yii, descrita abaixo. + +Instale o pacote do runner com o Composer: + +```shell +composer require yiisoft/yii-runner-frankenphp +``` + +O FrankenPHP funciona especialmente bem em deploys com containers e é o +runtime usado pela configuração Docker dos templates de aplicação do Yii, +descrita em [Docker nos templates de aplicação](docker.md). + +> [!NOTE] +> Este runner é para o modo worker. Para usar o FrankenPHP no modo clássico, mantenha o `public/index.php` e o +> [yiisoft/yii-runner-http](https://github.com/yiisoft/yii-runner-http), o runner HTTP padrão dos templates. + +## Configuração + +Primeiro, configure o script de entrada do worker. + +### Script de entrada do worker + +Crie `/worker.php` na raiz do projeto: + +```php +setLevels([ + LogLevel::EMERGENCY, + LogLevel::ERROR, + LogLevel::WARNING, + ]), + ], + ), + new PlainTextRenderer(), + ), +); +$runner->run(); +``` + +O runner faz o bootstrap da aplicação uma vez e depois continua processando +requisições em modo worker. Diferente do `public/index.php` clássico, este +script não é executado a cada requisição. + +### Configuração do servidor + +O FrankenPHP é configurado por um `Caddyfile`. Em produção, ele pode ficar +assim: + +```caddyfile +{ + skip_install_trust + + frankenphp { + + } +} + +{$SERVER_NAME::80} { + encode zstd br gzip + php_server { + root /app/public + worker { + match * + file /app/worker.php + } + } +} +``` + +Essa configuração diz ao FrankenPHP para servir o diretório `public` e +atender todas as requisições com o `worker.php`. Os assets estáticos +continuam sendo servidos de `public`, enquanto as requisições PHP são +processadas pelo worker de longa duração. + +Em desenvolvimento, adicione `watch` para que o FrankenPHP recarregue os +workers quando arquivos PHP mudarem: + +```caddyfile +{ + skip_install_trust + + frankenphp { + + } +} + +{$SERVER_NAME::80} { + encode zstd br gzip + php_server { + root /app/public + worker { + match * + file /app/worker.php + watch /app/**/*.php + } + } +} +``` + +### Configuração Docker nos templates de aplicação do Yii + +Os templates de aplicação do Yii já vêm com uma configuração Docker baseada +no FrankenPHP. Para passar a aplicação para o modo worker, altere os +arquivos da estrutura Docker em vez de depender do `public/index.php`. + +Crie `/worker.php` na raiz do projeto como mostrado acima e depois altere a +configuração do Caddy usada pelo container. Em desenvolvimento, edite +`docker/dev/Caddyfile`: + +```caddyfile +{ + skip_install_trust + + frankenphp { + + } +} + +{$SERVER_NAME::80} { + encode zstd br gzip + php_server { + root /app/public + worker { + match * + file /app/worker.php + watch /app/**/*.php + } + } +} +``` + +Em produção, use a mesma configuração sem `watch` em `docker/Caddyfile`: + +```caddyfile +{ + skip_install_trust + + frankenphp { + + } +} + +{$SERVER_NAME::80} { + encode zstd br gzip + php_server { + root /app/public + worker { + match * + file /app/worker.php + } + } +} +``` + +Os templates usam `dunglas/frankenphp` como imagem base em +`docker/Dockerfile`, montam o projeto em `/app` no desenvolvimento e passam +a configuração de runtime por arquivos de ambiente como `docker/dev/.env` e +`docker/prod/.env`. O valor padrão de `SERVER_NAME` nesses arquivos é `:80`, +que corresponde aos exemplos acima. + +Depois de alterar o `worker.php` e o `Caddyfile` correspondente, reconstrua +a imagem e reinicie o ambiente: + +```shell +make build +make up +``` + +Em produção, reconstrua a imagem de produção e faça o deploy usando o fluxo +Docker de produção do projeto. + +Se você passar totalmente para o modo worker, o `public/index.php` e o +`yiisoft/yii-runner-http` deixam de ser necessários. + +## Iniciando o servidor + +O comando exato para iniciar depende de como você roda o FrankenPHP: + +- Nos templates de aplicação do Yii, execute `make build` e `make up` depois + de alterar o `worker.php` e o `Caddyfile` correspondente. +- Com o binário standalone, execute o seguinte comando no diretório que + contém o seu `Caddyfile`: + +```shell +frankenphp run --config Caddyfile +``` + +A configuração de exemplo usa `/app` como raiz da aplicação. Ajuste +`/app/public`, `/app/worker.php` e o caminho do watch conforme a sua +instalação. Veja a [referência de configuração do +FrankenPHP](https://frankenphp.dev/docs/config/) para outras opções de +deploy. + +## Sobre o escopo do worker + +- A memória de cada worker é isolada da dos outros workers. +- Um único worker atende várias requisições, então os serviços criados + dentro dele podem manter estado entre requisições. +- A cada iteração do event loop, todo serviço com estado deve ser + redefinido. + +Para as implicações gerais de workers de longa duração, veja [Usando o Yii +com event loop](using-with-event-loop.md). + +## Notas sobre o modo worker + +- Use a variável de ambiente `MAX_REQUESTS` para limitar quantas requisições + um worker atende antes de ser reiniciado. +- O runner chama `Yiisoft\Di\StateResetter::reset()` depois de cada + requisição. Registre resetters para os seus serviços com estado, como + descrito na [documentação do Yii + DI](https://github.com/yiisoft/di#resetting-services-state). + +## Configuração adicional + +O `FrankenPHPApplicationRunner` vem configurado por padrão para os templates +de aplicação do Yii e segue o conceito de [configuração do container de +dependências](../concept/configuration.md#configuracao-do-container). + +O construtor permite sobrescrever a configuração padrão de bootstrap, +eventos, DI, params e tratamento de erros. Você também pode fornecer uma +instância de configuração personalizada com `withConfig()` e um container +personalizado com `withContainer()`. diff --git a/src/pt-BR/guide/tutorial/using-yii-with-rapira.md b/src/pt-BR/guide/tutorial/using-yii-with-rapira.md new file mode 100644 index 00000000..07d024bf --- /dev/null +++ b/src/pt-BR/guide/tutorial/using-yii-with-rapira.md @@ -0,0 +1,144 @@ +# Usando o Yii com Rapira + +O [Rapira](https://rapira.rs/) é um servidor de aplicação PHP escrito em Rust que embute o interpretador PHP. +O [runner do Yii para Rapira](https://github.com/yiisoft/yii-runner-rapira) suporta os modos classic, worker e dispatcher. +Os modos worker e dispatcher inicializam a aplicação uma vez por worker e a reaproveitam nas requisições seguintes. +Veja [Usando o Yii com event loop](using-with-event-loop.md) para as implicações de manter a aplicação na memória. + +## Instalação + +O runner exige PHP 8.4–8.5. Instale o binário do Rapira seguindo as +[instruções de instalação do +Rapira](https://rapira.rs/docs/intro/installation), com uma versão do PHP +suportada pelo runner. Os pacotes do Composer fornecem a integração com o +Yii; o binário do servidor precisa ser instalado à parte. + +Instale o runner e o pacote de contratos dele na sua aplicação Yii: + +```shell +composer require yiisoft/yii-runner-rapira:@dev rapira/contract:@dev +``` + +Essas flags de estabilidade permitem as versões de desenvolvimento usadas +nas instruções de instalação do runner. + +## Configuração + +O exemplo a seguir supõe uma aplicação baseada em `yiisoft/app` ou +`yiisoft/app-api`, com `App\Environment` e `src/bootstrap.php` fornecidos +pelo template. + +### Script de entrada do worker + +Crie `worker.php` na raiz da aplicação: + +```php +setLevels([ + LogLevel::EMERGENCY, + LogLevel::ERROR, + LogLevel::WARNING, + ]), + ], + ), + new PlainTextRenderer(), + ), +); +$runner->run(); +``` + +O runner cria o container, inicia a aplicação, converte as requisições +recebidas em requisições PSR-7 e emite as respostas. Ele detecta o modo de +execução do Rapira, então o mesmo script de entrada serve para os três +modos. + +### Configuração do servidor + +Crie `rapira.toml` ao lado de `worker.php`: + +```toml +[http] +listen = "127.0.0.1:8000" + +[http.pool] +entrypoint = "worker.php" +mode = "worker" +max_requests = 1000 +``` + +Essa configuração escuta na interface de loopback e recicla cada worker +depois de 1.000 requisições. Para servir arquivos de `public`, siga a +[configuração de arquivos estáticos](https://rapira.rs/docs/static-files) do +Rapira. Veja a [referência de +configuração](https://rapira.rs/docs/configuration) para as outras opções do +servidor e do pool. + +## Iniciando o servidor + +Execute o seguinte comando na raiz da aplicação: + +```shell +rapira serve rapira.toml +``` + +Abra `http://127.0.0.1:8000` para acessar a aplicação. Reinicie o servidor +depois de alterar o código ou a configuração da aplicação. + +## Modos de execução + +Defina `mode` na seção `[http.pool]` do `rapira.toml` para escolher como as +requisições são processadas: + +- `classic` inicializa a aplicação a cada requisição, como no PHP-FPM. +- `worker` mantém a aplicação na memória e recebe as requisições pelas + superglobais da SAPI do PHP. +- `dispatcher` mantém a aplicação na memória e recebe objetos de requisição + pela API de dispatcher do Rapira. O runner do Yii processa essas + requisições sequencialmente dentro de cada worker. + +Veja [os modos de execução do +Rapira](https://rapira.rs/docs/execution-modes) para mais detalhes. + +## Sobre o escopo do worker + +Nos modos worker e dispatcher, os serviços podem manter estado entre +requisições. O runner chama `Yiisoft\Di\StateResetter::reset()` depois de +cada requisição, mas você precisa configurar resetters para os seus próprios +serviços com estado. Veja a [documentação do Yii +DI](https://github.com/yiisoft/di#resetting-services-state). + +A opção `max_requests` limita quanto tempo um worker vive; ela não substitui +a redefinição do estado específico de cada requisição. + +## Configuração adicional + +O `RapiraApplicationRunner` usa por padrão os grupos de configuração web dos +templates de aplicação. O construtor aceita grupos alternativos, diretórios +de configuração e um error handler temporário. Use `withConfig()` para +fornecer uma instância de configuração personalizada ou `withContainer()` +para fornecer um container PSR-11. Veja a [documentação do +runner](https://github.com/yiisoft/yii-runner-rapira#configuration) para +exemplos. diff --git a/src/pt-BR/guide/tutorial/using-yii-with-roadrunner.md b/src/pt-BR/guide/tutorial/using-yii-with-roadrunner.md new file mode 100644 index 00000000..baf6d31e --- /dev/null +++ b/src/pt-BR/guide/tutorial/using-yii-with-roadrunner.md @@ -0,0 +1,182 @@ +# Usando o Yii com RoadRunner + +O [RoadRunner](https://roadrunner.dev/) é um servidor de aplicação escrito em Go que se integra bem ao PHP. Ele roda +o PHP como workers, e cada worker pode atender várias requisições. Esse modo de operação costuma ser chamado de +[event loop](using-with-event-loop.md) e evita reinicializar o framework a cada requisição, o que melhora +bastante o desempenho. + +## Instalação + +O RoadRunner funciona no Linux, macOS e Windows. A melhor forma de +instalá-lo é pelo Composer: + +``` +composer require yiisoft/yii-runner-roadrunner +``` + +Terminada a instalação, execute + +``` +./vendor/bin/rr get +``` + +Isso baixa o binário `rr` do servidor RoadRunner, pronto para uso. + +## Configuração + +Primeiro, precisamos configurar o próprio servidor. Crie `/.rr.yaml` e +adicione a seguinte configuração: + +```yaml +version: '3' + +server: + command: "php worker.php" + +rpc: + listen: tcp://127.0.0.1:6001 + +http: + address: :8080 + pool: + debug: false # defina como true apenas no desenvolvimento local + supervisor: + max_worker_memory: 192 + middleware: [static, gzip, headers, sendfile] + static: + dir: "public" + forbid: [".php", ".htaccess"] + headers: + response: + "Cache-Control": "no-cache" + +logs: + mode: production + level: warn +``` + +> [!INFO] +> Saiba mais sobre configuração de TLS, HTTP/2, HTTP/3 e outros middlewares [na documentação do RoadRunner](https://docs.roadrunner.dev/docs/http/http). + +Estamos definindo que o script de entrada é o `worker.php`, que o servidor +escuta na porta 8080 e que os arquivos do diretório `public` são servidos +estaticamente, exceto `.php` e `.htaccess`. O `max_worker_memory` é um +limite flexível: se um worker passar de 192 MB, ele reinicia depois de +terminar a requisição atual. Também estamos enviando um header adicional. + +## Cache KV + +O RoadRunner tem um [plugin +KV](https://docs.roadrunner.dev/docs/key-value/overview-kv) que pode ser +usado como armazenamento de cache PSR-16. Ele é útil quando a aplicação já +roda no RoadRunner e precisa de um cache compartilhado entre os workers. + +Instale a ponte PHP e o pacote de cache do Yii: + +``` +composer require spiral/roadrunner-kv yiisoft/cache +``` + +Adicione um armazenamento KV ao `.rr.yaml`: + +```yaml +kv: + cache: + driver: memory + config: + interval: 60 +``` + +O driver `memory` guarda os valores dentro do processo do RoadRunner, então +os dados se perdem quando o RoadRunner para. Para um armazenamento de cache +persistente, use outro driver KV da documentação do RoadRunner. + +Crie `config/common/di/roadrunner-kv.php`: + +```php + static function (): StorageInterface { + $factory = new Factory(RPC::create('tcp://127.0.0.1:6001')); + + return $factory->select('cache'); + }, + + SimpleCacheInterface::class => StorageInterface::class, + YiiCacheInterface::class => Cache::class, +]; +``` + +Agora os serviços podem usar `Yiisoft\Cache\CacheInterface` do mesmo jeito +que com outros backends de cache: + +```php +use Yiisoft\Cache\CacheInterface; + +final readonly class FeedService +{ + public function __construct( + private CacheInterface $cache, + ) { + } + + public function latest(): array + { + return $this->cache->getOrSet('feed-latest', fn (): array => $this->loadLatest(), 60); + } + + private function loadLatest(): array + { + return []; + } +} +``` + +Crie `/worker.php`: + +```php +run(); +``` + +## Iniciando o servidor + +Para iniciar o servidor, execute o seguinte comando: + +``` +./rr serve +``` + +## Sobre o escopo do worker + +- O escopo de cada worker é isolado dos outros workers. A memória não é + compartilhada. +- Um único worker atende várias requisições, e nelas o escopo é + compartilhado. +- A cada iteração do event loop, todo serviço que depende de estado deve ser + redefinido. diff --git a/src/pt-BR/guide/tutorial/using-yii-with-swoole.md b/src/pt-BR/guide/tutorial/using-yii-with-swoole.md new file mode 100644 index 00000000..067ef988 --- /dev/null +++ b/src/pt-BR/guide/tutorial/using-yii-with-swoole.md @@ -0,0 +1,174 @@ +# Usando o Yii com Swoole + +O [Swoole](https://www.swoole.com/) é uma extensão PHP para aplicações de rede orientadas a eventos e baseadas em corrotinas. Ela +inclui um servidor HTTP, APIs de corrotinas e hooks de runtime para as funções de I/O bloqueantes mais comuns. + +O Swoole permite que os handlers de requisição do Yii rodem como +workers. Cada worker pode atender várias requisições. Esse modo de operação +costuma ser chamado de [event loop](using-with-event-loop.md) e evita +reinicializar o framework a cada requisição, o que melhora bastante o +desempenho. + +## Instalação + +O Swoole suporta Linux, macOS, Cygwin e WSL. Instale a extensão pelo PECL: + +```bash +pecl install swoole +``` + +Se o PECL não habilitar a extensão automaticamente, adicione-a ao seu +`php.ini`: + +```ini +extension=swoole.so +``` + +Confira se o PHP carrega a extensão: + +```bash +php --ri swoole +``` + +O projeto Swoole também oferece uma [imagem +Docker](https://github.com/swoole/docker-swoole) e documenta builds a partir +do código-fonte com recursos opcionais, como hooks para OpenSSL, sockets, +MySQL, PostgreSQL e curl. + +## Subindo um servidor + +O Swoole passa objetos `Swoole\Http\Request` e `Swoole\Http\Response` para +os callbacks de requisição. O Yii trabalha com requisições e respostas +PSR-7, então adicione um pacote conversor: + +```shell +composer require ilexn/swoole-convert-psr7 +``` + +Crie um script de entrada, `server.php`: + +```php +setLevels([ + LogLevel::EMERGENCY, + LogLevel::ERROR, + LogLevel::WARNING, + ]), + ], + ), + new HtmlRenderer(), + ), +); + +$container = $runner->getContainer(); +$application = $container->get(Application::class); +$errorCatcher = $container->get(ErrorCatcher::class); + +$serverRequestFactory = new SwooleServerRequestConverter( + $container->get(ServerRequestFactoryInterface::class), + $container->get(UriFactoryInterface::class), + $container->get(UploadedFileFactoryInterface::class), + $container->get(StreamFactoryInterface::class) +); + +$server = new Server('0.0.0.0', 9501); + +$server->on('start', static function (Server $server) use ($application) { + $application->start(); + echo "Swoole http server is started at http://127.0.0.1:9501\n"; +}); + +$server->on('request', static function ( + Request $request, + Response $response +) use ($serverRequestFactory, $application, $errorCatcher, $container) { + try { + $psr7Request = $serverRequestFactory->createFromSwoole($request); + $psr7Response = $application->handle($psr7Request); + (new SwooleResponseConverter($response))->send($psr7Response); + } catch (Throwable $throwable) { + $handler = new ThrowableHandler($throwable); + $psr7Response = $errorCatcher->process($request, $handler); + (new SwooleResponseConverter($response))->send($psr7Response); + } + $application->afterEmit($psr7Response); + $container->get(StateResetter::class)->reset(); +}); + +$server->on('shutdown', static function (Server $server) use ($application) { + $application->shutdown(); +}); + +$server->start(); +``` + +## Iniciando o servidor + +Para iniciar o servidor, execute o seguinte comando: + +``` +php server.php +``` + +## Sobre o escopo + +O escopo é compartilhado, então a cada iteração do event loop todo serviço +que depende de estado deve ser redefinido. + +## Sessões + +Evite as sessões nativas do PHP, incluindo `Yiisoft\Session\Session`, quando +corrotinas do Swoole atendem requisições simultâneas dentro de um mesmo +worker: elas compartilham o estado da sessão e podem expor os dados de um +usuário a outra requisição. + +Para requisições atendidas uma por vez, feche a sessão e redefina os +serviços entre as requisições. O `yiisoft/session` impede o reuso de IDs de +sessão antigos, mas não isola corrotinas simultâneas. + +Para autenticação, considere tokens como [JWT](https://jwt.io/introduction) +em vez de sessões nativas, principalmente em APIs. Se você precisa de +recursos de sessão, use uma implementação que isole os dados de sessão de +cada corrotina; trocar o handler de armazenamento nativo para Redis não +basta. + +Veja as [orientações do +Swoole](https://github.com/swoole/swoole-src/issues/4478#issuecomment-962840796) +e a [discussão sobre sessões no +Yii](https://github.com/yiisoft/session/issues/25). diff --git a/src/pt-BR/guide/views/asset.md b/src/pt-BR/guide/views/asset.md new file mode 100644 index 00000000..e75533a0 --- /dev/null +++ b/src/pt-BR/guide/views/asset.md @@ -0,0 +1,672 @@ +# Assets + +O gerenciamento de assets é essencial em aplicações web modernas. Assets +incluem folhas de estilo CSS, arquivos JavaScript, imagens, fontes e outros +recursos estáticos. O Yii3 oferece um sistema completo de gerenciamento de +assets por meio do pacote `yiisoft/assets`, que cuida das dependências, da +otimização e da publicação desses recursos. + +## Instalação + +A funcionalidade de gerenciamento de assets vem do pacote `yiisoft/assets`: + +```bash +composer require yiisoft/assets +``` + +Esse pacote já vem incluído por padrão no template de aplicação +`yiisoft/app`. + +## Conceitos básicos + +### Asset bundles + +Um asset bundle é um conjunto de arquivos de asset relacionados (CSS, +JavaScript, imagens) agrupados logicamente. Asset bundles podem depender de +outros bundles, o que permite gerenciar as dependências corretamente. + +### Asset Manager + +O Asset Manager é responsável por: - Resolver as dependências dos asset +bundles - Publicar assets de diretórios protegidos em locais acessíveis pela +web - Combinar e minificar assets (quando configurado) - Gerar as URLs +corretas dos assets + +## Criando asset bundles + +### Asset bundle básico + +Esta é uma definição simples de asset bundle: + +```php + 'print'], + ['css/admin/mobile.css', 'media' => 'screen and (max-width: 768px)'], + ]; + + // Arquivos JavaScript com atributos + public array $js = [ + 'js/admin/core.js', + ['js/admin/charts.js', 'defer' => true], + ['js/admin/analytics.js', 'async' => true], + ]; + + // Opções globais para todos os arquivos JS deste bundle + public array $jsOptions = [ + 'data-admin' => 'true', + ]; + + // Opções globais para todos os arquivos CSS deste bundle + public array $cssOptions = [ + 'data-bundle' => 'admin', + ]; + + public array $depends = [ + MainAsset::class, + ChartJsAsset::class, + ]; +} +``` + +## Usando asset bundles + +### Em controllers + +Registre os asset bundles nos seus controllers ou views: + +```php +assetManager->register(MainAsset::class); + + return $this->viewRenderer->render('index', [ + 'title' => 'Home Page', + ]); + } + + public function admin(): ResponseInterface + { + // Registra vários asset bundles + $this->assetManager->registerMany([ + MainAsset::class, + AdminAsset::class, + ]); + + return $this->viewRenderer->render('admin/dashboard'); + } +} +``` + +### Em views + +Você também pode registrar assets diretamente nas views: + +```php +register(ProductAsset::class); +?> + +
+

+ +
+``` + +### Com integração à WebView + +A abordagem recomendada é integrar com a WebView para que os assets sejam +renderizados automaticamente: + +```php +register(MainAsset::class); + +// Adiciona todos os assets registrados à view +$this->addCssFiles($assetManager->getCssFiles()); +$this->addCssStrings($assetManager->getCssStrings()); +$this->addJsFiles($assetManager->getJsFiles()); +$this->addJsStrings($assetManager->getJsStrings()); +$this->addJsVars($assetManager->getJsVars()); +?> + +
+ +
+``` + +## Publicação de assets + +### Publicação a partir do source path + +Quando os assets ficam em diretórios não acessíveis pela web (como pacotes +do vendor), eles precisam ser publicados: + +```php +publish('@vendor/company/package/assets'); + +// Obtém a URL publicada +$publishedUrl = $assetManager->getPublishedUrl('@vendor/company/package/assets'); +``` + +## Assets de bibliotecas de terceiros + +### Asset bundle do jQuery + +```php + 'sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3', + 'crossorigin' => 'anonymous', + ]; + + public array $js = [ + 'https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js', + ]; + + public array $jsOptions = [ + 'integrity' => 'sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p', + 'crossorigin' => 'anonymous', + ]; +} +``` + +## Configuração de assets + +### Configuração da aplicação + +Configure o gerenciamento de assets na configuração da sua aplicação: + +**config/web/params.php** +```php +return [ + 'yiisoft/assets' => [ + // Caminho base dos assets publicados + 'basePath' => '@webroot/assets', + + // URL base dos assets + 'baseUrl' => '@web/assets', + + // Configuração do conversor de assets + 'converter' => [ + 'commands' => [ + 'scss' => ['sass', '{from}', '{to}', '--style=compressed'], + 'ts' => ['tsc', '{from}', '--outFile', '{to}'], + ], + ], + ], +]; +``` + +### Assets por ambiente + +Configure assets diferentes para cada ambiente: + +```php +css = ['css/main.css', 'css/debug.css']; + $this->js = ['js/main.js', 'js/debug.js']; + } else { + // Assets de produção (minificados) + $this->css = ['css/main.min.css']; + $this->js = ['js/main.min.js']; + } + } +} +``` + +## Otimização de assets + +### Combinação de assets + +Combine vários arquivos CSS ou JavaScript em arquivos únicos: + +```php +/** + * @var \Yiisoft\Assets\AssetManager $assetManager + */ + +// Habilita a combinação de assets +$assetManager->setCombine(true); + +// Define as opções de combinação +$assetManager->setCombineOptions([ + 'css' => true, // Combina os arquivos CSS + 'js' => true, // Combina os arquivos JavaScript +]); +``` + +### Compressão de assets + +Configure a compressão de assets para produção: + +```php +// Na configuração do seu asset manager +'converter' => [ + 'commands' => [ + 'css' => ['cleancss', '{from}', '-o', '{to}'], + 'js' => ['uglifyjs', '{from}', '-o', '{to}', '--compress', '--mangle'], + ], +], +``` + +## Trabalhando com o conversor de assets + +### Compilação de SCSS/SASS + +```php + 'screen and (max-width: 768px)'], + ]; + + public array $depends = [ + AppAsset::class, + ]; +} +``` + +## Boas práticas + +1. **Organize por funcionalidade**: agrupe assets relacionados em bundles + lógicos +2. **Gerencie as dependências**: declare corretamente as dependências entre + bundles +3. **Use nomes significativos**: dê nomes claros aos seus asset bundles +4. **Otimize por ambiente**: use assets minificados em produção +5. **Considere uma CDN**: use CDN para bibliotecas populares quando fizer + sentido +6. **Versione seus assets**: inclua números de versão nos nomes dos arquivos + para invalidar o cache +7. **Reduza as requisições HTTP**: combine assets relacionados quando + possível +8. **Otimize o tamanho dos arquivos**: comprima e minifique os assets para + produção + +## Solução de problemas + +### Problemas comuns + +**Asset não encontrado:** +- Verifique se o arquivo de asset existe no caminho especificado +- Confira se `$basePath` e `$baseUrl` estão configurados corretamente +- Garanta que os assets foram publicados se você usa `$sourcePath` + +**Dependências não carregam:** +- Confira se os bundles de dependência estão registrados corretamente +- Verifique se há dependências circulares +- Garanta que os bundles de dependência estão configurados corretamente + +**Assets não aparecem no HTML:** +- Verifique se você chama `$this->addCssFiles()` e `$this->addJsFiles()` no seu layout +- Confira se `$this->head()`, `$this->beginBody()` e `$this->endBody()` são chamados no layout + +**Problemas de permissão:** +- Verifique se o servidor web tem permissão de escrita no diretório de assets +- Confira se o diretório de assets publicados é acessível pela web diff --git a/src/pt-BR/guide/views/script-style-meta.md b/src/pt-BR/guide/views/script-style-meta.md new file mode 100644 index 00000000..82120fc7 --- /dev/null +++ b/src/pt-BR/guide/views/script-style-meta.md @@ -0,0 +1,509 @@ +# Scripts, estilos e meta tags + +Aplicações web modernas exigem um gerenciamento cuidadoso de estilos CSS, +código JavaScript e meta tags HTML. O Yii3 oferece um sistema completo para +registrar e organizar esses recursos por meio da classe `WebView`, que faz +parte do pacote `yiisoft/view`. + +## Visão geral + +A classe `WebView` estende a classe básica `View` com funcionalidades +específicas para a web, permitindo que você: + +- Registre arquivos CSS e estilos inline +- Registre arquivos JavaScript e scripts inline +- Gerencie meta tags e link tags HTML +- Controle a posição em que os recursos são renderizados +- Lide com dependências entre recursos + +## Gerenciamento de CSS + +### Registrando arquivos CSS + +Você pode registrar arquivos CSS para incluí-los nas suas páginas HTML: + +```php +registerCssFile('/css/styles.css'); + +// Registra um arquivo CSS com atributos +$this->registerCssFile('/css/print.css', WebView::POSITION_HEAD, [ + 'media' => 'print', +]); + +// Registra um arquivo CSS com uma chave personalizada para evitar duplicatas +$this->registerCssFile('/css/theme.css', WebView::POSITION_HEAD, [], 'theme-css'); +``` + +### Registrando CSS inline + +Para estilos CSS inline, use o método `registerCss()`: + +```php +// Registra CSS inline +$this->registerCss(' + .highlight { + background-color: yellow; + font-weight: bold; + } + .error { + color: red; + border: 1px solid red; + } +', WebView::POSITION_HEAD); + +// Com atributos personalizados +$this->registerCss(' + @media print { + .no-print { display: none; } + } +', WebView::POSITION_HEAD, ['id' => 'print-styles']); +``` + +### CSS a partir de arquivos + +Você também pode registrar o conteúdo CSS de arquivos externos: + +```php +// Lê o CSS de um arquivo e o registra como CSS inline +$this->registerCssFromFile('/path/to/dynamic-styles.css', WebView::POSITION_HEAD, [ + 'id' => 'dynamic-styles', +]); +``` + +### Usando tags style + +Para ter mais controle, você pode usar tags style do HTML diretamente: + +```php +use Yiisoft\Html\Html; + +$styleTag = Html::style(' + .custom-button { + background: linear-gradient(45deg, #blue, #purple); + border: none; + color: white; + padding: 10px 20px; + } +', ['id' => 'custom-button-styles']); + +$this->registerStyleTag($styleTag, WebView::POSITION_HEAD); +``` + +## Gerenciamento de JavaScript + +### Registrando arquivos JavaScript + +Inclua arquivos JavaScript externos com `registerJsFile()`: + +```php +// Registra um arquivo JavaScript +$this->registerJsFile('/js/main.js'); + +// Registra com atributos (carregamento assíncrono) +$this->registerJsFile('/js/analytics.js', WebView::POSITION_END, [ + 'async' => true, +]); + +// Registra com o atributo defer +$this->registerJsFile('/js/interactive.js', WebView::POSITION_END, [ + 'defer' => true, +]); + +// Registra a partir de uma CDN +$this->registerJsFile('https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js', + WebView::POSITION_END, [], 'jquery'); +``` + +### Registrando JavaScript inline + +Adicione código JavaScript inline com `registerJs()`: + +```php +// Registra JavaScript inline +$this->registerJs(' + document.addEventListener("DOMContentLoaded", function() { + console.log("Page loaded!"); + initializeComponents(); + }); +', WebView::POSITION_END); + +// Registra JavaScript que deve rodar quando o DOM estiver pronto +$this->registerJs(' + function showAlert(message) { + alert(message); + } +', WebView::POSITION_READY); +``` + +### Variáveis JavaScript + +Passe dados do PHP para o JavaScript com `registerJsVar()`: + +```php +// Registra variáveis JavaScript +$this->registerJsVar('apiUrl', 'https://api.example.com'); +$this->registerJsVar('currentUser', [ + 'id' => $user->getId(), + 'name' => $user->getName(), + 'isAdmin' => $user->isAdmin(), +]); +$this->registerJsVar('config', [ + 'debug' => $this->isDebugMode(), + 'locale' => $this->getLocale(), +]); +``` + +Isso gera um código JavaScript como este: + +```html + +``` + +### Usando tags script + +Para ter mais controle sobre as tags script: + +```php +use Yiisoft\Html\Html; + +$scriptTag = Html::script(' + window.myApp = { + init: function() { + console.log("App initialized"); + } + }; +', ['type' => 'module']); + +$this->registerScriptTag($scriptTag, WebView::POSITION_END); +``` + +## Constantes de posição + +Os recursos podem ser posicionados em diferentes pontos do documento HTML: + +```php +use Yiisoft\View\WebView; + +// Na seção +WebView::POSITION_HEAD + +// No início do +WebView::POSITION_BEGIN + +// No fim do (antes de ) +WebView::POSITION_END + +// Quando o DOM estiver pronto (equivalente ao document.ready do jQuery) +WebView::POSITION_READY + +// Quando a página terminar de carregar (equivalente ao window.onload) +WebView::POSITION_LOAD +``` + +Exemplo de layout mostrando onde cada posição é renderizada: + +```php + +beginPage() ?> + + + + + head() ?> + + + + beginBody() ?> + +
+ +
+ + + endBody() ?> + + +endPage() ?> +``` + +## Meta tags + +### Meta tags básicas + +Registre meta tags para SEO e informações da página: + +```php +// Registra meta tags usando a sintaxe de array +$this->registerMeta(['name' => 'description', 'content' => 'Page description']); +$this->registerMeta(['name' => 'keywords', 'content' => 'yii, php, framework']); +$this->registerMeta(['name' => 'author', 'content' => 'John Doe']); +$this->registerMeta(['name' => 'robots', 'content' => 'index, follow']); + +// Viewport para design responsivo +$this->registerMeta(['name' => 'viewport', 'content' => 'width=device-width, initial-scale=1']); + +// Tags Open Graph para redes sociais +$this->registerMeta(['property' => 'og:title', 'content' => 'Page Title']); +$this->registerMeta(['property' => 'og:description', 'content' => 'Page description']); +$this->registerMeta(['property' => 'og:image', 'content' => 'https://example.com/image.jpg']); +``` + +### Usando objetos de meta tag + +Para ter mais controle, use o helper `Html::meta()`: + +```php +use Yiisoft\Html\Html; + +// Cria meta tags com o helper Html +$this->registerMetaTag( + Html::meta() + ->name('description') + ->content('This is a comprehensive guide to Yii3 views') +); + +$this->registerMetaTag( + Html::meta() + ->httpEquiv('refresh') + ->content('300') // Atualiza a cada 5 minutos +); +``` + +### Evitando meta tags duplicadas + +Use chaves para evitar meta tags duplicadas: + +```php +// Primeiro registro +$this->registerMeta([ + 'name' => 'description', + 'content' => 'Original description' +], 'description'); + +// Este sobrescreve o anterior +$this->registerMeta([ + 'name' => 'description', + 'content' => 'Updated description' +], 'description'); +``` + +## Link tags + +### Link tags básicas + +Registre vários tipos de link tags: + +```php +// Favicon +$this->registerLink([ + 'rel' => 'icon', + 'type' => 'image/png', + 'href' => '/favicon.png', +]); + +// Feed RSS +$this->registerLink([ + 'rel' => 'alternate', + 'type' => 'application/rss+xml', + 'title' => 'RSS Feed', + 'href' => '/feed.rss', +]); + +// URL canônica +$this->registerLink([ + 'rel' => 'canonical', + 'href' => 'https://example.com/canonical-url', +]); + +// Pré-carregamento de recursos +$this->registerLink([ + 'rel' => 'preload', + 'href' => '/fonts/main.woff2', + 'as' => 'font', + 'type' => 'font/woff2', + 'crossorigin' => 'anonymous', +]); +``` + +### Usando objetos de link tag + +```php +use Yiisoft\Html\Html; + +// Folha de estilo CSS +$this->registerLinkTag( + Html::link('/css/main.css', [ + 'rel' => 'stylesheet', + ]) +); + +// Prefetch de DNS +$this->registerLinkTag( + Html::link('https://fonts.googleapis.com', [ + 'rel' => 'dns-prefetch', + ]) +); +``` + +## Exemplos práticos + +### Configuração completa de uma página + +Veja como montar uma página completa com todos os tipos de recursos: + +```php +setTitle($title); + +// Meta tags +$this->registerMeta(['name' => 'description', 'content' => $description]); +$this->registerMeta(['name' => 'keywords', 'content' => 'ecommerce, products, online shop']); + +// Tags Open Graph +$this->registerMeta(['property' => 'og:title', 'content' => $title]); +$this->registerMeta(['property' => 'og:description', 'content' => $description]); +$this->registerMeta(['property' => 'og:image', 'content' => $product['image']]); + +// Arquivos CSS +$this->registerCssFile('/css/product.css'); +$this->registerCssFile('/css/responsive.css', WebView::POSITION_HEAD, [ + 'media' => 'screen and (max-width: 768px)', +]); + +// Arquivos JavaScript +$this->registerJsFile('/js/product-gallery.js', WebView::POSITION_END); +$this->registerJsFile('/js/shopping-cart.js', WebView::POSITION_END); + +// Variáveis JavaScript +$this->registerJsVar('productData', $product); +$this->registerJsVar('cartApiUrl', '/api/cart'); + +// JavaScript inline +$this->registerJs(' + document.addEventListener("DOMContentLoaded", function() { + initProductGallery(); + initShoppingCart(); + }); +', WebView::POSITION_END); + +// Estilos específicos da página +$this->registerCss(' + .product-special { + background: linear-gradient(45deg, #ff6b6b, #4ecdc4); + padding: 20px; + border-radius: 10px; + } +', WebView::POSITION_HEAD); +?> + +
+ +
+``` + +### Carregamento condicional de recursos + +Carregue recursos de acordo com condições: + +```php +registerCssFile('/css/dark-theme.css'); +} else { + $this->registerCssFile('/css/light-theme.css'); +} + +// Recursos específicos da área admin +if ($isAdmin) { + $this->registerCssFile('/css/admin-toolbar.css'); + $this->registerJsFile('/js/admin-functions.js'); +} + +// Configuração JavaScript baseada no papel do usuário +$this->registerJsVar('userPermissions', [ + 'canEdit' => in_array($userRole, ['admin', 'editor']), + 'canDelete' => $userRole === 'admin', + 'canPublish' => in_array($userRole, ['admin', 'publisher']), +]); +?> +``` + +## Boas práticas + +1. **Use as posições adequadas**: coloque o CSS em `POSITION_HEAD` e o + JavaScript em `POSITION_END` +2. **Reduza os recursos inline**: prefira arquivos externos, que aproveitam + melhor o cache +3. **Use chaves contra duplicatas**: evite recursos duplicados com chaves + significativas +4. **Otimize o carregamento**: use os atributos `async` e `defer` para + JavaScript não crítico +5. **Agrupe recursos relacionados**: mantenha juntos os arquivos CSS e JS + relacionados +6. **Use CDNs com critério**: equilibre desempenho e confiabilidade +7. **Valide as meta tags**: garanta que as meta tags de SEO estejam + definidas corretamente +8. **Pense na segurança**: tenha cuidado com scripts inline e políticas de + CSP + +## Trabalhando com asset bundles + +Para um gerenciamento de assets mais complexo, considere usar asset bundles: + +```php +// Registra um asset bundle (explicado em detalhes no guia de Assets) +$assetBundle = $this->assetManager->register(MainAsset::class); + +// Adiciona todos os arquivos CSS do bundle +$this->addCssFiles($this->assetManager->getCssFiles()); + +// Adiciona todos os arquivos JavaScript do bundle +$this->addJsFiles($this->assetManager->getJsFiles()); +``` diff --git a/src/pt-BR/guide/views/template-engines.md b/src/pt-BR/guide/views/template-engines.md new file mode 100644 index 00000000..ed4b9c17 --- /dev/null +++ b/src/pt-BR/guide/views/template-engines.md @@ -0,0 +1,212 @@ +# Template engines + +O Yii3 suporta várias template engines por meio de um sistema flexível de +renderers. Por padrão, o PHP é usado como template engine, mas você pode +adicionar suporte a outras engines como Twig e +[Blade](https://github.com/lee-to/yii-blade), ou criar seus próprios +renderers. + +Os templates PHP foram descritos na seção "[View](view.md)" do guia. + +## Template engine Twig + +O Twig é uma template engine moderna, com uma sintaxe mais amigável para +designers. Para usar o Twig na sua aplicação Yii3, instale a extensão do +Twig. + +```bash +composer require yiisoft/view-twig +``` + +Agora você pode usar templates `.twig`. Por exemplo, +`views/site/about.twig`: + +```twig +{# Dicas de tipo das variáveis para suporte na IDE #} +{# @var user \App\Entity\User #} +{# @var posts \App\Entity\Post[] #} + + +``` + +### Recursos do Twig + +**Escape automático**: o Twig escapa as variáveis automaticamente para o contexto HTML: + +```twig +{# Escapado automaticamente #} +

{{ title }}

+ +{# Saída bruta (use com cuidado) #} +
{{ content|raw }}
+``` + +**Filtros e funções**: o Twig oferece muitos filtros e funções nativos: + +```twig +{# Formatação de data #} + + +{# Manipulação de strings #} +

{{ description|truncate(100) }}

+ +{# Geração de URLs #} +Profile +``` + +**Herança de templates**: o Twig suporta herança de templates: + +**views/layout/main.twig** +```twig + + + + {% block title %}Default Title{% endblock %} + + +
+ {% block content %}{% endblock %} +
+ + +``` + +**views/site/about.twig** +```twig +{% extends "layout/main.twig" %} + +{% block title %}About Us{% endblock %} + +{% block content %} +

About Our Company

+

Welcome to our website!

+{% endblock %} +``` + +### Renderizando templates Twig + +Use templates Twig da mesma forma que templates PHP: + +```php +// No seu controller +public function about(): ResponseInterface +{ + return $this->viewRenderer->render('about.twig', [ + 'user' => $this->getCurrentUser(), + 'posts' => $this->getRecentPosts(), + ]); +} +``` + +## Template engines personalizadas + +Você pode criar template engines personalizadas implementando a +`TemplateRendererInterface`: + +```php + $value) { + $content = str_replace("{{$key}}", (string) $value, $content); + } + + return $this->parser->parse($content); + } +} +``` + +Registre o seu renderer personalizado: + +```php +use Yiisoft\Container\Reference; + +// Na configuração +'yiisoft/view' => [ + 'renderers' => [ + 'md' => Reference::to(App\View\MarkdownRenderer::class), + ], +], +``` + +Agora você pode usar arquivos de template `.md`: + +**views/content/help.md** +```markdown +# Help: {{title}} + +Welcome, {{username}}! + +This is a Markdown template with **bold** and *italic* text. + +- Feature 1 +- Feature 2 +- Feature 3 +``` + +## Escolhendo a template engine certa + +**Use templates PHP quando:** +- Você precisa do máximo de flexibilidade e desempenho +- Seu time está à vontade com PHP +- Você quer aproveitar o conhecimento de PHP que já tem +- Você precisa de lógica complexa nos templates (embora isso deva ser minimizado) + +**Use templates Twig quando:** +- Você quer uma separação mais rígida entre lógica e apresentação +- Você trabalha com designers que preferem uma sintaxe mais limpa +- Você precisa de escape automático e recursos de segurança +- Você quer herança de templates e recursos avançados + +**Use templates personalizados quando:** +- Você tem requisitos específicos que o PHP ou o Twig não atendem +- Você trabalha com formatos de conteúdo especializados +- Você precisa integrar com sistemas de template externos + +## Boas práticas + +1. **Mantenha os templates simples**: leve a lógica complexa para + controllers ou serviços +2. **Sempre escape a saída**: evite ataques XSS escapando as variáveis + corretamente +3. **Use nomes significativos**: dê nomes claros aos seus templates e + variáveis +4. **Organize os templates**: agrupe templates relacionados em subdiretórios +5. **Documente as variáveis**: sempre adicione dicas de tipo para um suporte + melhor da IDE +6. **Evite lógica de negócio**: mantenha a lógica de negócio em models e + serviços diff --git a/src/pt-BR/guide/views/view-injections.md b/src/pt-BR/guide/views/view-injections.md new file mode 100644 index 00000000..4d0429c0 --- /dev/null +++ b/src/pt-BR/guide/views/view-injections.md @@ -0,0 +1,116 @@ +# Injeções de view + +As injeções de view oferecem uma forma padronizada de passar parâmetros para +a camada comum das views de uma aplicação. Com elas, você gerencia os dados +que ficarão disponíveis em várias views, o que garante flexibilidade e +reaproveitamento de código. + +Você pode usar as injeções de view se a sua aplicação exige o pacote +`yiisoft/yii-view-renderer`: + + +```sh +composer require yiisoft/yii-view-renderer +``` + +## Configuração + +Na configuração `params.php`: + + +```php +... +'yiisoft/yii-view' => [ + 'injections' => [ + Reference::to(ContentViewInjection::class), + Reference::to(CsrfViewInjection::class), + Reference::to(LayoutViewInjection::class), + ], + ], +``` + +## Novas injeções + +Comece definindo uma classe que implemente +`Yiisoft\Yii\View\Renderer\CommonParametersInjectionInterface`. Essa classe +fornece os parâmetros que você quer injetar nos templates de view e nos +layouts. + +```php +class MyCustomParametersInjection implements Yiisoft\Yii\View\Renderer\CommonParametersInjectionInterface +{ + // As propriedades e os métodos da classe ficam aqui + + public function __construct(UserService $userService) + { + $this->userService = $userService; + } + + public function getCommonParameters(): array + { + return [ + 'siteName' => 'My Awesome Site', + 'currentYear' => date('Y'), + 'user' => $this->userService->getCurrentUser(), + ]; + } +} +``` + +Adicione a nova injeção ao `params.php`: + +```php +'yiisoft/yii-view' => [ + 'injections' => [ + ..., + Reference::to(MyCustomParametersInjection::class), + ], + ], +``` + +## Usando injeções separadas para layouts diferentes + +Se a sua aplicação tem vários layouts, você pode criar injeções de +parâmetros separadas para cada um. Assim, os parâmetros injetados em cada +layout atendem às necessidades específicas dele, o que deixa a aplicação +mais flexível e fácil de manter. + +Crie a sua ViewInjection personalizada para um layout específico: + +```php +readonly final class CartViewInjection implements CommonParametersInjectionInterface +{ + public function __construct(private Cart $cart) + { + } + + public function getCommonParameters(): array + { + return [ + 'cart' => $this->cart, + ]; + } +} +``` + +Adicione a nova injeção ao `params.php` sob o nome de um layout +específico. No exemplo a seguir, é `@layout/cart`: + +```php +'yiisoft/yii-view' => [ + 'injections' => [ + ..., + Reference::to(MyCustomParametersInjection::class), + DynamicReference::to(static function (ContainerInterface $container) { + $cart = $container + ->get(Cart::class); + + return new LayoutSpecificInjections( + '@layout/cart', // nome do layout para a injeção + + new CartViewInjection($cart) + ); + }), + ], + ], +``` diff --git a/src/pt-BR/guide/views/view.md b/src/pt-BR/guide/views/view.md new file mode 100644 index 00000000..abe00f96 --- /dev/null +++ b/src/pt-BR/guide/views/view.md @@ -0,0 +1,319 @@ +# Views + +A view é responsável por apresentar os dados ao usuário final. Você entrega +a ela um template com alguns placeholders e lógica de apresentação, além de +alguns dados. A view passa os dados para o template e executa a lógica do +template. O resultado final está pronto para ser entregue ao usuário final, +seja um navegador, um arquivo para download, um e-mail a ser enviado ou +outra coisa. + +```mermaid +flowchart LR + A[Dados] --> V[View] + B[Template] --> V + V --> C[HTML] + C --> D[Navegador] +``` + +No Yii3, as views normalmente são arquivos PHP com lógica de apresentação e +marcação HTML. O sistema de views oferece uma forma flexível de organizar a +camada de apresentação e suporta recursos como layouts e views parciais. Em +vez de templates PHP puros, você pode usar uma das template engines, como +[Twig](template-engines.md) ou +[Blade](https://github.com/lee-to/yii-blade). + +## Instalação + +Para a funcionalidade básica de views, você precisa do pacote +`yiisoft/view`: + +```sh +composer require yiisoft/view +``` + +Em aplicações web, instale também o pacote `yiisoft/yii-view-renderer`, que +oferece compatibilidade com [PSR-7](https://www.php-fig.org/psr/psr-7/) e +recursos específicos para a web: + +```sh +composer require yiisoft/yii-view-renderer +``` + +Esses pacotes já vêm incluídos por padrão no template de aplicação +`yiisoft/app`. + +## Conceitos básicos + +Um arquivo de template de view contém lógica de apresentação. No template +`yiisoft/app`, os arquivos de view normalmente ficam junto dos seus +controllers (por exemplo, `src/Web/Echo/Action.php`). Este é um exemplo +simples de arquivo de view, `src/Web/Echo/template.php`: + +```php + + +

The message is:

+``` + +Aqui, `$message` é um dado da view passado quando você renderiza um template +com o `WebViewRenderer`. Por exemplo, `src/Web/Echo/Action.php`: + +```php +viewRenderer->render(__DIR__ . '/template', [ + 'message' => $message, + ]); + } +} +``` + +O primeiro argumento do método `render()` é o caminho do arquivo de +template. No `yiisoft/app`, os arquivos de template normalmente ficam junto +das suas actions. O resultado já está pronto para ser enviado ao navegador, +então o devolvemos imediatamente. + +## Trabalhando com layouts + +A maioria das aplicações web usa um layout comum para todas as páginas. No +template `yiisoft/app`, os layouts ficam no diretório +`src/Web/Shared/Layout/Main/`. Você pode definir um layout padrão em +`config/common/params.php`: + +```php +return [ + 'yiisoft/yii-view-renderer' => [ + 'viewPath' => null, + 'layout' => '@src/Web/Shared/Layout/Main/layout.php', + ], +]; +``` + +Um arquivo de layout típico, como `src/Web/Shared/Layout/Main/layout.php`, +tem esta cara: + +```php +register(MainAsset::class); + +$this->addCssFiles($assetManager->getCssFiles()); +$this->addCssStrings($assetManager->getCssStrings()); +$this->addJsFiles($assetManager->getJsFiles()); +$this->addJsStrings($assetManager->getJsStrings()); +$this->addJsVars($assetManager->getJsVars()); + +$this->beginPage() +?> + + + + + + + <?= Html::encode($this->getTitle()) ?> + head() ?> + + +beginBody() ?> + + + +
+ +
+ + + +endBody() ?> + + +endPage() ?> +``` + +No template acima, `$applicationParams` é um array de parâmetros de +`config/common/application.php`. + +`$aliases` se refere ao [componente de aliases](../concept/aliases.md), +usado para obter a URL base da aplicação no servidor para montar URLs. + +`$this` é uma instância da view que usamos para obter o título da página e +gerar a saída dos assets, tanto os padrão quanto os personalizados. + +Com `$assetManager->register(MainAsset::class);` registramos um asset que define o `css` a ser incluído na página. Ele é +copiado automaticamente para `public/assets` no primeiro uso. Isso não ajuda muito com um único arquivo CSS, mas se torna útil +conforme o número de assets cresce. + +> [!IMPORTANT] +> Nenhuma saída em templates PHP puros é codificada, então não se esqueça de usar `Html::encode()` para evitar +vulnerabilidades de segurança do tipo XSS. + +Você encontra mais detalhes sobre o que está disponível no layout na +documentação do [yiisoft/view](https://github.com/yiisoft/view). + +### Renderizando sem layout + +Às vezes você precisa renderizar uma view sem layout (por exemplo, para +respostas AJAX): + +```php +public function ajaxContent(): ResponseInterface +{ + return $this->viewRenderer + ->withLayout(null) + ->render('ajax-content', ['data' => $data]); +} + +// Ou use o método renderPartial +public function ajaxContent(): ResponseInterface +{ + return $this->viewRenderer->renderPartial('ajax-content', ['data' => $data]); +} +``` + +## Views aninhadas e parciais + +### Renderizando sub-views + +Você pode renderizar outras views de dentro de uma view com o método `$this->render()`: + +```php + +
+ + render('_post_item', ['post' => $post]) ?> + +
+``` + +**src/Web/Post/_item.php** +```php + +
+

getTitle()) ?>

+

getExcerpt()) ?>

+ +
+``` + +### Usando blocos + +Os blocos permitem definir conteúdo em uma view e exibi-lo em outra, +normalmente nos layouts: + +```php +// Em um arquivo de view +setBlock('sidebar', $this->render('_sidebar', ['items' => $sidebarItems])) ?> + +// No arquivo de layout +hasBlock('sidebar')): ?> + + +``` + +## Renderizando como string + +Se você precisa do conteúdo renderizado como string em vez de uma resposta +PSR-7: + +```php +public function getEmailContent(): string +{ + return $this->viewRenderer->renderAsString('email/welcome', [ + 'user' => $user, + ]); +} +``` + +## Eventos de view + +O sistema de views dispara eventos durante a renderização, e você pode +escutá-los: + +```php +use Yiisoft\View\Event\WebView\BeforeRender; +use Yiisoft\View\Event\WebView\AfterRender; + +// Exemplo de listener de eventos +final class ViewEventListener +{ + public function onBeforeRender(BeforeRender $event): void + { + // Adiciona uma classe CSS global com base no nome da view + if (str_contains($event->getFile(), 'admin/')) { + $event->getView()->registerCssClass('admin-view'); + } + } + + public function onAfterRender(AfterRender $event): void + { + // Registra no log o tempo de renderização + $this->logger->info('View rendered', [ + 'view' => $event->getFile(), + 'time' => $event->getRenderTime(), + ]); + } +} +``` diff --git a/src/pt-BR/guide/views/widget.md b/src/pt-BR/guide/views/widget.md new file mode 100644 index 00000000..c63f1517 --- /dev/null +++ b/src/pt-BR/guide/views/widget.md @@ -0,0 +1,771 @@ +# Widgets + +Widgets são componentes reutilizáveis e autocontidos que encapsulam uma +lógica complexa de geração de HTML. Eles oferecem uma forma limpa de criar +elementos de interface configuráveis, que podem ser usados em diferentes +views e aplicações. O Yii3 oferece um sistema de widgets flexível por meio +do pacote `yiisoft/widget`. + +## Instalação + +A funcionalidade de widgets vem do pacote `yiisoft/widget`: + +```bash +composer require yiisoft/widget +``` + +Para widgets prontos (como formulários, navegação etc.), você também pode +instalar: + +```bash +composer require yiisoft/yii-widgets +``` + +Esses pacotes já vêm incluídos por padrão no template de aplicação +`yiisoft/app`. + +## Conceitos básicos + +### Classe do widget + +Um widget é uma classe PHP que estende a classe abstrata `Widget` e +implementa um método `render()` que devolve o conteúdo HTML como string. + +### Widget factory + +A `WidgetFactory` é responsável por criar as instâncias dos widgets e pode +injetar dependências por meio do container de DI. + +### Configuração de widgets + +Os widgets podem ser configurados com propriedades e métodos, o que os torna +altamente personalizáveis e reutilizáveis em diferentes contextos. + +## Criando widgets próprios + +### Widget simples + +Este é um widget básico que exibe uma mensagem de alerta: + +```php +message = $message; + return $new; + } + + public function type(string $type): self + { + $new = clone $this; + $new->type = $type; + return $new; + } + + public function closeable(bool $closeable = true): self + { + $new = clone $this; + $new->closeable = $closeable; + return $new; + } + + protected function render(): string + { + if (empty($this->message)) { + return ''; + } + + $classes = ['alert', 'alert-' . $this->type]; + + if ($this->closeable) { + $classes[] = 'alert-dismissible'; + } + + $content = Html::encode($this->message); + + if ($this->closeable) { + $content .= Html::button('×', [ + 'type' => 'button', + 'class' => 'btn-close', + 'data-bs-dismiss' => 'alert', + ]); + } + + return Html::div($content, ['class' => implode(' ', $classes)]); + } +} +``` + +### Usando o widget + +```php + + +
+ message('Operation completed successfully!') + ->type('success') + ->closeable() ?> + + message('Please review the form errors below.') + ->type('danger') ?> +
+``` + +### Widget com dependências + +Os widgets podem usar injeção de dependência para receber serviços: + +```php +userService->getCurrentUser(); + + if ($currentUser === null) { + return $this->renderLoginLink(); + } + + return $this->renderUserMenu($currentUser); + } + + private function renderLoginLink(): string + { + return Html::a('Login', $this->urlGenerator->generate('login'), [ + 'class' => 'btn btn-primary', + ]); + } + + private function renderUserMenu($user): string + { + $items = [ + Html::a('Profile', $this->urlGenerator->generate('user.profile'), [ + 'class' => 'dropdown-item', + ]), + Html::a('Settings', $this->urlGenerator->generate('user.settings'), [ + 'class' => 'dropdown-item', + ]), + '', + Html::a('Logout', $this->urlGenerator->generate('logout'), [ + 'class' => 'dropdown-item', + ]), + ]; + + return Html::div( + Html::button( + Html::encode($user->getName()) . ' ', + [ + 'class' => 'btn btn-secondary dropdown-toggle', + 'type' => 'button', + 'data-bs-toggle' => 'dropdown', + ] + ) . + Html::div(implode('', $items), ['class' => 'dropdown-menu']), + ['class' => 'dropdown'] + ); + } +} +``` + +## Configuração da widget factory + +### Configuração de bootstrap + +Inicialize a widget factory no bootstrap da sua aplicação: + +**config/bootstrap.php** +```php + [ + 'type()' => ['info'], + 'closeable()' => [true], + ], + App\Widget\CardWidget::class => [ + 'headerClass()' => ['card-header bg-primary text-white'], + ], +]; + +WidgetFactory::initialize($container, $widgetDefaults); +``` + +### Configuração do container de DI + +**config/web/di.php** +```php +use App\Widget\AlertWidget; +use App\Widget\UserMenuWidget; + +return [ + // Configurações de widgets podem ser definidas aqui, se necessário + AlertWidget::class => static fn() => new AlertWidget(), + + UserMenuWidget::class => static fn( + App\Service\UserService $userService, + Yiisoft\Router\UrlGeneratorInterface $urlGenerator + ) => new UserMenuWidget($userService, $urlGenerator), +]; +``` + +## Exemplos avançados de widgets + +### Widget de lista de dados + +Um widget que exibe uma lista de itens com paginação: + +```php +paginator = $paginator; + return $new; + } + + public function itemRenderer(callable $renderer): self + { + $new = clone $this; + $new->itemRenderer = $renderer; + return $new; + } + + public function containerClass(string $class): self + { + $new = clone $this; + $new->containerClass = $class; + return $new; + } + + public function itemClass(string $class): self + { + $new = clone $this; + $new->itemClass = $class; + return $new; + } + + public function emptyText(string $text): self + { + $new = clone $this; + $new->emptyText = $text; + return $new; + } + + protected function render(): string + { + if ($this->paginator === null) { + return ''; + } + + $items = $this->paginator->read(); + + if (empty($items)) { + return Html::div($this->emptyText, ['class' => 'empty-message']); + } + + $itemsHtml = ''; + foreach ($items as $item) { + $content = $this->itemRenderer + ? ($this->itemRenderer)($item) + : Html::encode((string) $item); + + $itemsHtml .= Html::div($content, ['class' => $this->itemClass]); + } + + return Html::div($itemsHtml, ['class' => $this->containerClass]); + } +} +``` + +Uso: + +```php + + +paginator($postPaginator) + ->containerClass('posts-list row') + ->itemClass('col-md-4 mb-3') + ->itemRenderer(function ($post) { + return $this->render('_post_card', ['post' => $post]); + }) ?> +``` + +### Widget de formulário + +Um widget que simplifica a renderização de formulários: + +```php +model = $model; + return $new; + } + + public function action(string $action): self + { + $new = clone $this; + $new->action = $action; + return $new; + } + + public function method(string $method): self + { + $new = clone $this; + $new->method = $method; + return $new; + } + + public function options(array $options): self + { + $new = clone $this; + $new->options = $options; + return $new; + } + + public function field(string $attribute, array $options = []): self + { + $new = clone $this; + $new->fields[$attribute] = $options; + return $new; + } + + protected function render(): string + { + if ($this->model === null) { + return ''; + } + + $formOptions = array_merge([ + 'action' => $this->action, + 'method' => $this->method, + 'class' => 'form', + ], $this->options); + + $content = ''; + foreach ($this->fields as $attribute => $options) { + $content .= $this->renderField($attribute, $options); + } + + return Html::form($content, $formOptions); + } + + private function renderField(string $attribute, array $options): string + { + $label = $options['label'] ?? ucfirst($attribute); + $type = $options['type'] ?? 'text'; + $class = $options['class'] ?? 'form-control'; + + $field = Html::div( + Html::label($label, null, ['class' => 'form-label']) . + Html::input($type, $attribute, $this->getModelValue($attribute), [ + 'class' => $class, + 'id' => $attribute, + ]), + ['class' => 'mb-3'] + ); + + return $field; + } + + private function getModelValue(string $attribute): mixed + { + return $this->model->getAttributeValue($attribute); + } +} +``` + +### Widget de breadcrumb + +Um widget para breadcrumbs de navegação: + +```php +items = $items; + return $new; + } + + public function separator(string $separator): self + { + $new = clone $this; + $new->separator = $separator; + return $new; + } + + public function options(array $options): self + { + $new = clone $this; + $new->options = $options; + return $new; + } + + protected function render(): string + { + if (empty($this->items)) { + return ''; + } + + $links = []; + $itemCount = count($this->items); + + foreach ($this->items as $index => $item) { + if ($index === $itemCount - 1) { + // Último item (página atual) - sem link + $links[] = Html::span($item['label'], ['class' => 'breadcrumb-item active']); + } else { + // Item de breadcrumb comum, com link + $url = isset($item['url']) + ? (is_array($item['url']) + ? $this->urlGenerator->generate($item['url'][0], $item['url'][1] ?? []) + : $item['url']) + : '#'; + + $links[] = Html::span( + Html::a($item['label'], $url), + ['class' => 'breadcrumb-item'] + ); + } + } + + $options = array_merge(['class' => 'breadcrumb'], $this->options); + + return Html::nav( + Html::ol(implode('', $links), ['class' => 'breadcrumb']), + $options + ); + } +} +``` + +## Boas práticas com widgets + +### Padrão de configuração + +Use métodos de configuração imutáveis: + +```php +public function someProperty($value): self +{ + $new = clone $this; + $new->someProperty = $value; + return $new; +} +``` + +### Validação + +Valide a configuração do widget no método render: + +```php +protected function render(): string +{ + if (empty($this->items)) { + throw new InvalidArgumentException('Items cannot be empty.'); + } + + // ... lógica de renderização +} +``` + +### Codificação de HTML + +Sempre codifique os dados vindos do usuário: + +```php +protected function render(): string +{ + return Html::div(Html::encode($this->userContent), [ + 'class' => 'user-content', + ]); +} +``` + +### Gerenciamento de assets + +Registre os assets específicos do widget: + +```php +assetManager->register(ChartWidgetAsset::class); + + // Renderiza o conteúdo do widget + return $this->renderChart(); + } +} +``` + +## Usando widgets em layouts + +Os widgets são especialmente úteis em layouts, para elementos de interface +comuns: + +**views/layout/main.php** +```php + + + + + + + +
+ + +
+ +
+ +
+ +
+ +
+ + +``` + +## Testando widgets + +### Testes unitários + +Teste a lógica de renderização do widget: + +```php +message('Test message') + ->type('success'); + + $output = $widget->render(); + + $this->assertStringContainsString('Test message', $output); + $this->assertStringContainsString('alert-success', $output); + } + + public function testRenderEmpty(): void + { + $widget = AlertWidget::widget(); + $output = $widget->render(); + + $this->assertEmpty($output); + } +} +``` + +## Padrões comuns de widgets + +### Renderização condicional + +```php +protected function render(): string +{ + if (!$this->shouldRender()) { + return ''; + } + + return $this->doRender(); +} + +private function shouldRender(): bool +{ + return !empty($this->items) && $this->isVisible; +} +``` + +### Renderização baseada em template + +```php +protected function render(): string +{ + return $this->renderTemplate('widget-template', [ + 'items' => $this->items, + 'options' => $this->options, + ]); +} + +private function renderTemplate(string $template, array $data): string +{ + // Usa um view renderer para renderizar arquivos de template + return $this->viewRenderer->renderPartialAsString($template, $data); +} +``` + +### Integração com eventos + +```php +protected function render(): string +{ + $event = new BeforeWidgetRender($this); + $this->eventDispatcher->dispatch($event); + + $content = $this->doRender(); + + $afterEvent = new AfterWidgetRender($this, $content); + $this->eventDispatcher->dispatch($afterEvent); + + return $afterEvent->getContent(); +} +``` + +Os widgets oferecem uma forma eficaz de criar componentes de interface +reutilizáveis e configuráveis em aplicações Yii3. Eles ajudam a manter uma +separação clara de responsabilidades e deixam suas views mais fáceis de +manter e testar. diff --git a/src/pt-BR/index.md b/src/pt-BR/index.md new file mode 100644 index 00000000..9bc6dff5 --- /dev/null +++ b/src/pt-BR/index.md @@ -0,0 +1,39 @@ +--- +features: + - + details: 'O Yii oferece o máximo de funcionalidade com o mínimo possível de sobrecarga.' + icon: '' + title: Rápido + - + details: 'Padrões sensatos e ferramentas embutidas ajudam você a escrever código sólido e seguro.' + icon: '' + title: Seguro + - + details: 'Escreva mais código em menos tempo com APIs simples e poderosas e com geração de código.' + icon: '' + title: Eficiente +hero: + actions: + - + link: guide/intro/what-is-yii.html + text: 'Comece agora' + theme: brand + class: homeHero2 + image: + alt: Yii + src: /images/yii_logo.svg + name: 'Yii3 Framework' + tagline: 'Um framework simples, poderoso e rápido. Conheça o guia definitivo e moderno do Yii que você sempre quis.' + text: Documentação +layout: home +--- + +

+ +- [Guia definitivo](guide/) — o guia completo que cobre todos os aspectos do + framework. +- [Cookbook da comunidade](cookbook/) — uma coleção de dicas, truques e + soluções da comunidade para tarefas comuns no desenvolvimento com Yii. +- [Detalhes internos](internals/) — documentação para quem contribui com o + próprio framework Yii, incluindo diretrizes, fluxos de trabalho e boas + práticas. diff --git a/src/pt-BR/internals/000-packages.md b/src/pt-BR/internals/000-packages.md new file mode 100644 index 00000000..a0ccf0d7 --- /dev/null +++ b/src/pt-BR/internals/000-packages.md @@ -0,0 +1,87 @@ +# 000 — Pacotes + +O time do Yii3 dividiu o framework em vários pacotes que seguem os acordos +abaixo. + +Em todos os pacotes, o nome do repositório no GitHub corresponde exatamente +ao nome do pacote no Packagist. + +Para ver a lista completa de pacotes e o status de build de cada um, +consulte a [página de status em +yiiframework.com](https://www.yiiframework.com/status/3.0). + +## Pacotes específicos do Yii (framework e extensões) + +- nomeados como `yiisoft/yii-something` ou de forma mais específica: + `yii-type-something`, por exemplo: + - módulos: `yii-module-users`, `yii-module-pages` + - temas: `yii-theme-adminlte`, `yii-theme-hyde` + - widgets: `yii-widget-datepicker` + - ... +- intitulados como "Yii Framework ..." +- podem ter quaisquer dependências e código específico do Yii + +## Pacotes de uso geral (bibliotecas) + +- você pode usá-los independentemente do Yii Framework +- nomeados como `yiisoft/something`, sem o prefixo yii +- intitulados como "Yii ..." +- não podem ter dependências de nenhum pacote específico do Yii +- devem ter o menor número possível de dependências + +## Configurações e padrões + +O que segue se aplica tanto aos pacotes específicos do Yii quanto aos +pacotes de uso geral: + +- O pacote pode ter um diretório `config` com padrões específicos do Yii. +- O pacote pode ter "config-plugin" na seção "extra" do `composer.json`. +- O pacote não pode ter, na seção `require` do `composer.json`, dependências + usadas apenas em `config`. +- Você deve colocar os parâmetros sob o namespace `vendor/package-name`: + +```php +return [ + 'vendor/package-name' => [ + 'param1' => 1, + 'param2' => 2, + ], +]; +``` + +## Versões + +Todos os pacotes seguem o versionamento [SemVer](https://semver.org/): + +- `x.*.*` - mudanças incompatíveis na API. +- `*.x.*` - adição de funcionalidades (compatível com versões anteriores). +- `*.*.x` - correções de bugs (compatível com versões anteriores). + +A primeira versão estável deve ser 1.0.0. + +O número de versão de cada pacote não depende da versão de nenhum outro +pacote nem do nome/versão do framework, apenas do seu próprio contrato +público. O framework como um todo tem o nome "Yii3". + +Não há problema em usar juntos pacotes com versões major diferentes, desde +que sejam compatíveis. + +## Suporte a versões do PHP + +O suporte às versões do PHP em um pacote depende do [ciclo de vida das +versões do PHP](https://www.php.net/supported-versions.php). + +- Versões de pacotes com suporte ativo DEVEM suportar todas as versões do + PHP que têm suporte ativo. +- Tanto os pacotes quanto os templates de aplicação DEVEM ter versões + suportadas que recebem correções de bugs e de segurança. Essas versões + DEVERIAM corresponder às versões do PHP que recebem correções de + segurança. +- Pacotes e templates de aplicação PODEM ter versões suportadas que + funcionam com versões do PHP sem suporte. +- Aumentar a versão mínima do PHP em um pacote ou template de aplicação é + uma mudança minor. + +## composer.json + +Um operador lógico OU em intervalos de versão DEVE usar pipe duplo (`||`). Por exemplo: `"yiisoft/arrays": "^1.0 || ^2.0"`. diff --git a/src/pt-BR/internals/001-yii-values.md b/src/pt-BR/internals/001-yii-values.md new file mode 100644 index 00000000..11de0ab6 --- /dev/null +++ b/src/pt-BR/internals/001-yii-values.md @@ -0,0 +1,85 @@ +# 001 — Objetivo e valores do Yii + +## Objetivo + +O projeto Yii tem como objetivo construir e manter ferramentas e uma +comunidade _práticas_ e _úteis_. + +## Valores + +Os valores que expressamos em nosso trabalho apoiam esse +objetivo. Procuramos + +- Ser práticos + - [Alto desempenho](#alto-desempenho) + - [Padrões sensatos e flexibilidade](#padroes-sensatos-e-flexibilidade) + - [Ser orientado à prática](#ser-orientado-a-pratica) +- Ser úteis + - [Ser simples](#ser-simples) + - [Ser explícito](#ser-explicito) + - [Ser consistente](#ser-consistente) + +## Ser práticos + +### Alto desempenho + +Desempenho é uma condição necessária para a praticidade. O software não deve +desperdiçar recursos de máquina nem recursos humanos. + +### Padrões sensatos e flexibilidade + +Preferimos padrões e convenções sensatos que os usuários possam +personalizar. Buscamos um equilíbrio entre flexibilidade, disciplina e +simplicidade que atenda às necessidades comuns. + +### Ser orientado à prática + +Preferimos a prática à teoria. Por exemplo: + +- Soluções para casos de uso conhecidos devem evitar complexidade excessiva, + oferecendo apenas a flexibilidade necessária. +- Implementações padrão devem levar em conta o uso prático. +- A experiência é pelo menos tão útil quanto a teoria para orientar o + design. +- O contexto é fundamental para determinar o que é adequado. + +## Ser úteis + +Esse valor orienta tanto as decisões técnicas quanto a atividade da +comunidade. O desenvolvimento deve ser guiado pela forma como os recursos +do software ajudam os usuários. Na comunidade, valorizamos qualquer +contribuição útil, seja um pull request ou uma resposta no fórum. + +Quando os outros princípios entram em conflito, escolhemos a solução mais +útil para a comunidade. + +### Ser simples + +As soluções devem ser simples e expressivas: + +- Usamos tanta complexidade quanto necessário, e não mais. +- Evitamos soluções feias, a menos que não haja alternativa. +- Menos regras é melhor do que mais regras. + +### Ser explícito + +Preferimos soluções e código explícitos e óbvios. As soluções devem +expressar claramente o que fazem. Por exemplo: + +- Uma solução direta é melhor do que uma abstrata, a menos que a abstração + tenha um propósito prático. +- Falhas ruidosas são melhores do que falhas silenciosas ou erros + mascarados. +- Conversões explícitas são melhores do que a conversão automática de tipos + do PHP; type hints são bons. +- Nada de mágica, a menos que seja necessário. + +### Ser consistente + +Procuramos ser consistentes em: + +- Estilo de código +- Nomenclatura +- Design +- Estrutura +- Valores e objetivos diff --git a/src/pt-BR/internals/002-issue-workflow.md b/src/pt-BR/internals/002-issue-workflow.md new file mode 100644 index 00000000..44b09afa --- /dev/null +++ b/src/pt-BR/internals/002-issue-workflow.md @@ -0,0 +1,30 @@ +# 002 — Fluxo de issues + +O processo de tratamento das issues recebidas é o seguinte: + +![Esquema do fluxo de issues](/images/internals/002-issue-workflow.svg) + +## Papéis + +Temos vários papéis: + +- Gerentes de processo - fazem a triagem inicial das issues e gerenciam os + labels. +- Tomadores de decisão - participam das discussões, levando-as a uma + resolução. +- Caçadores de bugs - verificam os bugs. +- Contribuidores - escrevem o código dos pull requests. +- Revisores de código - revisam os pull requests. + +Uma mesma pessoa pode assumir um ou mais papéis no processo de resolução de +issues. + +## Labels + +Usamos labels nas issues para marcar várias coisas: status atual, tipo da +issue, componente afetado. Os labels de status falam por si. + +## Milestones + +As issues não são atribuídas a milestones, a menos que sejam críticas ou que +provavelmente exista um bom pull request para elas. diff --git a/src/pt-BR/internals/003-roadmap.md b/src/pt-BR/internals/003-roadmap.md new file mode 100644 index 00000000..c2fb9d11 --- /dev/null +++ b/src/pt-BR/internals/003-roadmap.md @@ -0,0 +1,210 @@ +# 003 — Roadmap + +Queremos que o Yii 3: + +- Não limite o desenvolvedor na escolha da arquitetura. Permita qualquer + coisa, do MVC "clássico" ao DDD. +- Seja baseado em boas práticas como SOLID, GRASP etc. e as ensine à + comunidade. +- Mantenha a maior parte das coisas boas do Yii 2. +- Seja mais aberto à comunidade e à infraestrutura PHP global. + +## Conformidade com PSRs + +A conformidade com PSRs ajuda na personalização, permite usar bibliotecas +PHP gerais e implementar menos wrappers. Aqui está a lista de PSRs que +queremos implementar. + +### PSR-3 Logger + +Implementado como um [pacote separado que não depende de um +framework](https://github.com/yiisoft/log). + +- [x] Os pacotes do framework devem depender apenas da interface. +- [x] Separar os drivers em pacotes. +- [x] Limpar o código. +- [x] [Corrigir o destino de + e-mail](https://github.com/yiisoft/log-target-email). + +### PSR-4 Autoloading + +- [x] O autoloading já está bom. +- [x] Documentar como funciona. + +### PSR-7 HTTP message + +- [x] Remover nossa própria implementação. Pelo menos por enquanto. +- [x] Os pacotes do framework devem depender apenas de interfaces. + +### PSR-11 Container + +Implementado como um [pacote separado que não depende de um +framework](https://github.com/yiisoft/di). + +- [x] Os pacotes do framework não devem usar o container diretamente. Deve + ser possível instanciar tudo manualmente. +- [x] Terminar a refatoração. +- [x] Remover do pacote todas as implementações específicas do + framework. Movê-las para o framework. +- [x] [Implementar fallback para o + autoloader](https://github.com/yiisoft/di/issues/88) + +### PSR-12 Code style + +- [x] Garantir que o código o siga. +- [x] Automatizar a correção de estilo antes do release. + +### PSR-14 Event dispatcher + +- [x] [Implementar como uma biblioteca + separada](https://github.com/yiisoft/event-dispatcher). +- [x] Usar em outros pacotes. +- [x] Polir. + +### PSR-15 HTTP handlers + +- [x] Reescrever o fluxo HTTP para requisição-resposta PSR-7 + formatação da + resposta via emitter. +- [x] Oferecer um emitter SAPI pronto para uso. +- [x] Possibilitar o uso de emitters alternativos, como o RoadRunner. +- [x] Suportar middleware. +- [x] Implementar filtros como middleware: + - [x] [Limitação de taxa](https://github.com/yiisoft/yii-web/issues/63) + - [x] [Autenticação](https://github.com/yiisoft/yii-web/issues/114) +- [x] Reimplementar o router com suporte a middleware para grupos de rotas. +- [x] Filtros devem ser middlewares. + +### PSR-16 Simple cache + +Implementado como um [pacote separado que não depende de um +framework](https://github.com/yiisoft/cache). + +- [x] Os pacotes do framework devem depender apenas de interfaces. +- [x] Separar os drivers em pacotes. +- [x] Limpar o código. + +### PSR-17 HTTP factories + +- [x] Usar as factories PSR. + +### PSR-18 HTTP client + +- [x] Remover nossa própria implementação. Pelo menos por enquanto. +- [x] Os pacotes do framework devem depender apenas de interfaces. + +## Tipos mais estritos + +- [x] Garantir que type hints sejam usados em todo lugar. +- [x] Garantir que os tipos sejam o mais definidos possível. Evitar tipos + variáveis sempre que possível. + +## Template de aplicação único + +- [x] Abandonar basic/advanced. +- [x] Criar um [template de aplicação único que funcione de + imediato](https://github.com/yiisoft/app). + +## Router + +Implementado como um [pacote separado que não depende de um +framework](https://github.com/yiisoft/router). + +- [x] DSL para configuração. +- [x] Possibilidade de rotear para qualquer callable. +- [x] Rotas nomeadas. +- [x] Grupos de rotas com suporte a middleware. + +## Boas práticas e conformidade com SOLID em todas as classes/pacotes + +- [x] Garantir que as interfaces sigam o princípio de "segregação de + interfaces". +- [x] Não usar propriedades públicas. +- [x] Não usar `init()`. +- [x] Não herdar de `BaseObject` ou `Component`. Removê-los. +- [x] Nada de globais. +- [x] Nada de chamadas estáticas, exceto helpers finais. +- [x] Preferir lançar exceções a corrigir a entrada. + +## Kit de ferramentas de desenvolvimento + +- [x] Ferramenta de linha de comando para release +- [x] Ferramenta de linha de comando para desenvolvimento (cria symlinks dos + pacotes em uma aplicação utilizável) + +## Console + +- [x] Separar aplicação web e aplicação de console +- [x] Possivelmente eliminar a aplicação base (ainda é necessária) +- [x] Criar uma interface para o console (usando a do Symfony) +- [x] A implementação pode ser uma das populares (usando a do Symfony) +- [x] Garantir que a aplicação possa adicionar comandos via configuração + +## Documentação + +- [ ] Seguir boas práticas. +- [ ] Não usar o termo "MVC". +- [ ] Upgrade a partir do Yii 2. + +## RBAC + +O RBAC é implementado como [um pacote independente de +framework](https://github.com/yiisoft/rbac). + +- [x] Terminar a refatoração. +- [x] Garantir que siga boas práticas. +- [x] Separar os drivers em pacotes. + +## View + +A view é implementada como [pacote independente de +framework](https://github.com/yiisoft/view). + +- [x] Terminar a refatoração ([veja as + issues](https://github.com/yiisoft/view/issues)). +- [x] Portar os widgets. +- [x] Repensar e implementar os widgets de active form. +- [x] Implementar widgets de cache. + +## Abstrações de dados e grid + +- [x] Terminar as [abstrações de dados](https://github.com/yiisoft/data). +- [x] Portar a ordenação, usando abstrações de dados. Deve fazer parte do + [yii-dataview](https://github.com/yiisoft/yii-dataview). +- [x] Portar a paginação, usando abstrações de dados. Deve fazer parte do + [yii-dataview](https://github.com/yiisoft/yii-dataview). +- [x] Portar o grid, usando abstrações de dados. Deve fazer parte do + [yii-dataview](https://github.com/yiisoft/yii-dataview). +- [x] Portar a lista, usando abstrações de dados. Deve fazer parte do + [yii-dataview](https://github.com/yiisoft/yii-dataview). + +## Validadores + +- [x] Terminar o redesign do [pacote + principal](https://github.com/yiisoft/validator) +- [x] Portar os validadores necessários + +## Debug toolbar + +- [x] Portar a debug toolbar. + +## Gii + +- [x] Portar o Gii. + +## Infraestrutura + +- [x] Cobrir o [config](https://github.com/yiisoft/config) com testes. +- [x] Lançar uma versão estável do + [config](https://github.com/yiisoft/config). + +## Outros + +- [x] [Decidir sobre os + namespaces](https://forum.yiiframework.com/t/lowercase-or-camelcase-namespaces/124983/52). +- [x] [Limpar o error + handler](https://github.com/yiisoft/yii2/issues/14348). Garantir que o + error handler capture erros fatais e use a resposta. +- [x] Tornar os validadores independentes dos models para permitir + reutilizá-los em handlers. +- [x] [Dividir a + IdentityInterface](https://github.com/yiisoft/yii2/issues/13825). diff --git a/src/pt-BR/internals/004-namespaces.md b/src/pt-BR/internals/004-namespaces.md new file mode 100644 index 00000000..5172d465 --- /dev/null +++ b/src/pt-BR/internals/004-namespaces.md @@ -0,0 +1,23 @@ +# 004 — Namespaces + +As regras de namespace dos pacotes são as seguintes: + +1. As partes do namespace usam PascalCase. +2. O namespace raiz do vendor é `Yiisoft`. +3. As partes do nome do pacote são usadas no namespace. +4. Um adjetivo é unido ao substantivo e forma uma única parte. + + +Alguns exemplos: + +| Pacote | Namespace | +|----------------------------|---------------------------| +| yiisoft/yii-web | Yiisoft\Yii\Web | +| yiisoft/di | Yiisoft\Di | +| yiisoft/db-mysql | Yiisoft\Db\Mysql | +| yiisoft/friendly-exception | Yiisoft\FriendlyException | + +## Referências + +- [Discussão no fórum + internacional](https://forum.yiiframework.com/t/use-yiisoft-as-a-root-namespace-instead-of-yii-for-yii-3-packages/125734) diff --git a/src/pt-BR/internals/005-development-tool.md b/src/pt-BR/internals/005-development-tool.md new file mode 100644 index 00000000..ef9a4f3d --- /dev/null +++ b/src/pt-BR/internals/005-development-tool.md @@ -0,0 +1,52 @@ +# 005 — Ferramenta de desenvolvimento do Yii + +No Yii3, o número de pacotes aumentou bastante para permitir mais reuso e +releases independentes. Para facilitar o desenvolvimento do próprio +framework, criamos uma ferramenta especial, disponível em +[yiisoft/yii-dev-tool](https://github.com/yiisoft/yii-dev-tool). + +``` +$ ./yii-dev + _ _ _ _ + | | | |(_)(_) Development Tool + | |_| || || | + \__, ||_||_| for Yii 3.0 + |___/ + +This tool helps with setting up a development environment for Yii 3 packages. + +Usage: + command [options] [arguments] + +Options: + -h, --help Display this help message + +Available commands: + checkout-branch Creates, if not exists, and checkout a git branch + commit Add and commit changes into each package repository + install Install packages + lint Check packages according to PSR12 standard + pull Pull changes from package repositories + push Push changes into package repositories + replicate Copy files specified in replicate.php into each package + status Show git status of packages + update Update packages +``` + +Há muitos comandos disponíveis. Os mais importantes são `install` e +`update`. O que eles fazem: + +1. Instalam/atualizam todos os pacotes listados em + [`packages.php`](https://github.com/yiisoft/yii-dev-tool/blob/master/packages.php) + ou um pacote específico dessa lista, se informado. +2. Para cada pacote instalado, verificam no diretório `vendor` se há pacotes + listados em `packages.php`. Se houver, substituem o diretório do pacote + por um symlink para o código-fonte do outro pacote. + +Como resultado, você terá muitos pacotes usando uns aos outros, sem precisar +de `git push` e `composer install` / `composer update` durante o +desenvolvimento. + +Um [exemplo +detalhado](https://github.com/yiisoft/yii-dev-tool#usage-example) de uso da +ferramenta está disponível no README dela. diff --git a/src/pt-BR/internals/006-git-commit-messages.md b/src/pt-BR/internals/006-git-commit-messages.md new file mode 100644 index 00000000..421c1085 --- /dev/null +++ b/src/pt-BR/internals/006-git-commit-messages.md @@ -0,0 +1,18 @@ +# 006 — Mensagens de commit do Git + + +## Linha de assunto + +- Use `#123` para referenciar uma issue pelo número +- Use o modo imperativo, ou seja, `Fix`, e não `Fixed` +- Não coloque ponto final +- Use `[skip ci]` se não houver necessidade de rodar os testes unitários +- Comece com letra maiúscula +- Limite a 50 caracteres + +## Corpo + +Use o corpo da mensagem **se** precisar de uma explicação extra. Explique o +porquê, não o como. + +- Limite o tamanho das linhas a 72 caracteres diff --git a/src/pt-BR/internals/007-exceptions.md b/src/pt-BR/internals/007-exceptions.md new file mode 100644 index 00000000..09abfe56 --- /dev/null +++ b/src/pt-BR/internals/007-exceptions.md @@ -0,0 +1,16 @@ +# 007 — Exceções + +- Lance exceções em vez de retornar um código de erro. +- O nome da classe de exceção deve ter o sufixo `Exception`. +- Use mensagens de erro gramaticalmente corretas, incluindo a pontuação + final, ou seja, a maioria das exceções deve terminar com ponto. +- `\InvalidArgumentException` deve ser usada diretamente. Não deve haver + exceções herdadas dela. +- `\InvalidArgumentException` nunca deve ser capturada. + +## Referências + +- [Discussão e enquete na comunidade + internacional](https://forum.yiiframework.com/t/naming-exceptions/126613/6) +- [Discussão e enquete na comunidade + russa](https://yiiframework.ru/forum/viewtopic.php?f=39&t=51290) diff --git a/src/pt-BR/internals/008-interfaces.md b/src/pt-BR/internals/008-interfaces.md new file mode 100644 index 00000000..d2a0a6b5 --- /dev/null +++ b/src/pt-BR/internals/008-interfaces.md @@ -0,0 +1,10 @@ +# 008 — Interfaces + +- O nome da interface deve ter o sufixo `Interface`. + +## Referências + +- [Discussão e enquete na comunidade + internacional](https://forum.yiiframework.com/t/naming-interfaces/126612/5) +- [Discussão e enquete na comunidade + russa](https://yiiframework.ru/forum/viewtopic.php?f=39&t=51289) diff --git a/src/pt-BR/internals/009-design-decisions.md b/src/pt-BR/internals/009-design-decisions.md new file mode 100644 index 00000000..08d91534 --- /dev/null +++ b/src/pt-BR/internals/009-design-decisions.md @@ -0,0 +1,93 @@ +# 009 — Decisões de design + +Neste documento, listamos decisões de design importantes tomadas durante o +desenvolvimento do Yii3. + +## Remover propriedades mágicas + +As propriedades mágicas do Yii 2 eram uma ideia interessante: permitiam ao +desenvolvedor começar com uma propriedade pública e depois migrar de forma +transparente para getter/setter chamados via métodos mágicos, sem mudar o +código. + +O principal motivo da remoção no Yii 3 é que isso levava ao uso de +propriedades públicas em todo lugar, resultando em falta de encapsulamento e +código frágil. + +## Remover o service locator + +O service locator, tanto no Yii 1 quanto no Yii 2, era conveniente, mas +também muito abusado. Embora o Yii 2 tivesse um container de injeção de +dependência, o service locator costumava ser preferido, o que causava +dependência do próprio service locator, alto acoplamento e código difícil de +testar. + +O Yii 3 usa apenas injeção de dependência, o que reduz bastante o +acoplamento e torna o código muito mais testável. + +## Extrair pacotes de uso geral + +O Yii 1 e o Yii 2 eram comunidades totalmente fechadas. Todo o código que +tínhamos não era útil fora do Yii, e a maior parte do código "externo" não +era útil no Yii sem wrappers. Comunidades de fora do Yii comentaram muitas +vezes que várias partes do Yii são bem projetadas e únicas, e que as usariam +se estivessem disponíveis como pacotes independentes. + +Como parte do Yii 3, pacotes como cache, RBAC, view etc. foram extraídos +para pacotes independentes de framework. Os benefícios são: + +- Mais uso e mais contribuições +- O time do Yii pode delegar a manutenção +- Releases independentes passam a ser possíveis + +## Adotar PSRs + +O time adotou algumas PSRs no Yii 2, como a PSR-4 e a PSR-2. As interfaces, +em geral, não foram adotadas, embora o Yii faça parte do PHP-FIG. +Principalmente porque, quando o Yii 2 foi lançado, elas ainda estavam em +elaboração ou não tinham adoção suficiente. + +O Yii3 se beneficia das PSRs, já que hoje existem muitas bibliotecas prontas +para uso que você instala via Composer: backends de cache, middlewares, +loggers, containers de DI etc. + +Ao implementar PSRs nos pacotes de uso geral, permitimos que eles sejam +usados em mais projetos, aumentando o nível de contribuição. + +## Melhorar o container de DI + +O problema do container do Yii 2 era que ele foi feito sob medida para os +componentes do Yii 2. A API não foi bem projetada para uso com classes PHP +em geral. + +No Yii3, garantimos que o container possa ser usado para configurar qualquer +classe PHP de forma conveniente. + +Isso deve resultar na ausência de pacotes wrapper específicos do Yii e em +mais uso direto de pacotes do Composer. + +## Adotar strict types + +Os strict types foram introduzidos porque: + +- O PHP 7 agora é o padrão do mercado +- Embora não resolvam nenhum problema significativo do Yii 2, ajudam a + evitar muitos problemas do dia a dia de desenvolvimento + +## Adotar SemVer + +O Yii 2 tem sua própria política de versões. Problemas: + +- Não era um padrão +- O Composer se baseia em SemVer +- É difícil manter um framework construído sobre pacotes se a política de + versionamento não for rígida + +## Impedir que validadores alterem dados + +No Yii 1 e no Yii 2, validadores como "date" alteravam os dados. Era +confuso que um processo de validação, que a princípio não deveria alterar os +dados que valida, fizesse isso. + +[Veja a discussão +relacionada](https://forum.yiiframework.com/t/saving-or-killing-non-validation-in-validators/126086). diff --git a/src/pt-BR/internals/010-code-style.md b/src/pt-BR/internals/010-code-style.md new file mode 100644 index 00000000..d1b6f695 --- /dev/null +++ b/src/pt-BR/internals/010-code-style.md @@ -0,0 +1,214 @@ +# 010 — Estilo de código + +A formatação de código usada nos pacotes do Yii 3 é baseada no [PER Coding +Style 3.0](https://www.php-fig.org/per/coding-style/) com regras extras +adicionadas por cima. + +## Nomes + +- Use apenas inglês. +- Use a notação camelCase, inclusive em abreviações (por exemplo, + `enableIdn`). +- Use o nome mais curto possível, mas que seja explicativo. +- Nunca corte ou abrevie um nome. +- Adicione o sufixo `Collection` a classes, interfaces, traits e variáveis + que sejam uma + [coleção](https://en.wikipedia.org/wiki/Collection_(abstract_data_type)). +- Adicione o sufixo `Middleware` às classes de middleware. + +## Tipos + +- Declare [tipos de argumento e de + retorno](https://www.php.net/manual/en/migration70.new-features.php) + sempre que possível. +- [Use tipos nas + propriedades](https://wiki.php.net/rfc/typed_properties_v2). +- Use tipagem estrita. Evite tipos mixed e union sempre que possível, exceto + tipos compatíveis como `string|Stringable`. + +## Comentários + +Evite comentários inline, a menos que o código não possa ser entendido sem +eles. Um bom exemplo é um contorno para um bug em determinada versão do +PHP. + +O comentário de método é necessário, exceto quando não acrescenta nada ao +que o nome e a assinatura do método já dizem. + +O comentário de classe deve descrever o propósito da classe. + +Veja [PHPDoc](014-docs.md#phpdoc). + +## Formatação + +### Tamanho da linha + +O tamanho máximo da linha é de 120 caracteres. + +Quando uma chamada de função ou método excede o limite, separe os argumentos +em linhas distintas: + +```php +$this->assertSame( + ['' => ['Value must be no less than 5.']], + $result->getErrorMessagesIndexedByPath(), +); +``` + +### Sem alinhamento + +Atribuições de valores a propriedades, variáveis e constantes não devem ser +alinhadas. O mesmo vale para as tags phpdoc. O motivo é que instruções +alinhadas costumam gerar diffs maiores e até conflitos. + +```php +final class X +{ + const A = 'test'; + const BBB = 'test'; + + private int $property = 42; + private int $test = 123; + + /** + * @param int $number Just a number. + * @param array $options Well... options! + */ + public function doIt(int $number, array $options): void + { + $test = 123; + $anotherTest = 123; + } +} +``` + +### Chamadas encadeadas + +Chamadas encadeadas devem ser formatadas para melhor legibilidade. Se for +uma cadeia longa que não cabe no limite de 120 caracteres por linha, cada +chamada deve ficar em uma nova linha: + +```php +$object + ->withName('test') + ->withValue(87) + ->withStatus(Status::NEW) + ->withAuthor($author) + ->withDeadline($deadline); +``` + +Se for uma cadeia curta, não há problema em deixá-la em uma única linha: + +```php +$object = $object->withName('test'); +``` + +## Strings + +- Quando não houver variáveis envolvidas, use `'Hello!'` +- Para inserir variáveis na string, prefira `"Hello, $username!"` + +## Classes e interfaces + +### Final por padrão + +As classes devem ser `final` por padrão. + +### Private por padrão + +Constantes, propriedades e métodos devem ser private por padrão. + +### Composição em vez de herança + +Prefira [composição a herança](../guide/concept/di-container.md). + +### Ordem de propriedades, constantes e métodos + +A ordem deve ser a seguinte: + +- Constantes +- Propriedades +- Métodos + +Dentro de cada categoria, os itens devem ser ordenados por visibilidade: + +- public +- protected +- private + +### Classes abstratas + +Classes abstratas *não devem* ter o prefixo ou sufixo `Abstract`. + +#### Métodos imutáveis + +A convenção para métodos imutáveis é a seguinte: + +```php +public function withName(string $name): self +{ + $new = clone $this; + $new->name = $name; + return $new; +} +``` + +1. O nome do objeto clonado é `$new`. +2. O tipo de retorno é `self`. + +#### Métodos de verificação booleana + +Métodos que servem para verificar se algo é verdadeiro devem ser nomeados +assim: + +```php +public function isDeleted(): bool; +public function hasName(): bool; +public function canDoIt(): bool; +``` + +#### Flags em métodos + +É melhor evitar flags booleanas em métodos. Elas são um sinal de que o +método pode estar fazendo coisas demais e de que deveria haver dois métodos +em vez de um. + +```php +public function login(bool $refreshPage = true): void; +``` + +É melhor que sejam dois métodos: + +```php +public function login(): void; +public function refreshPage(): void; +``` + +## Variáveis + +Adicione o prefixo sublinhado (`_`) em variáveis não usadas. Por exemplo: + +```php +foreach ($items as $key => $_value) { + echo $key; +} +``` + +## Imports + +Prefira importar classes e funções a usar nomes totalmente qualificados: + +```php +use Yiisoft\Arrays\ArrayHelper; +use Yiisoft\Validator\DataSetInterface; +use Yiisoft\Validator\HasValidationErrorMessage; +use Yiisoft\Validator\Result; + +use function is_iterable; +``` + +## Convenções adicionais + +- [Namespaces](004-namespaces.md) +- [Exceções](007-exceptions.md) +- [Interfaces](008-interfaces.md) diff --git a/src/pt-BR/internals/011-error-correction.md b/src/pt-BR/internals/011-error-correction.md new file mode 100644 index 00000000..44fc1b4b --- /dev/null +++ b/src/pt-BR/internals/011-error-correction.md @@ -0,0 +1,5 @@ +# 011 — Correção de erros + +Se, dentro de uma classe, não houver ambiguidade sobre o que o desenvolvedor +que usou a classe de forma incorreta quis dizer, não há problema em corrigir +o erro. Caso contrário, o erro NÃO DEVE ser corrigido. diff --git a/src/pt-BR/internals/012-tests.md b/src/pt-BR/internals/012-tests.md new file mode 100644 index 00000000..571d8af4 --- /dev/null +++ b/src/pt-BR/internals/012-tests.md @@ -0,0 +1,21 @@ +# 012 — Testes + +Para cada pacote, adicionamos testes unitários executados com o +[PHPUnit](https://phpunit.de/). Ao projetar os testes, leve em conta as +diretrizes a seguir. + +- A classe de teste deve ser marcada como `final` por padrão. +- A anotação `@test` não deve ser usada; use o prefixo `test` nos métodos. +- O nome do método de teste deve refletir o propósito do teste. +- "should" não deve ser usado no nome do método de teste. +- Se necessário, o phpdoc do método de teste pode descrever o comportamento + esperado. +- O teste deve seguir o AAA: primeiro prepare (arrange) as pré-condições + necessárias, depois aja (act) e, por fim, verifique (assert) os resultados + esperados. +- Deve haver um caso de teste por método de teste, ou seja, um único AAA. +- O teste deve usar a API pública. Não se deve acessar propriedades ou + métodos privados, nem fazer suposições sobre os detalhes internos da + classe testada. +- Os testes não devem depender do composer-config-plugin nem do container de + DI, a menos que seja necessário. diff --git a/src/pt-BR/internals/013-code-review.md b/src/pt-BR/internals/013-code-review.md new file mode 100644 index 00000000..f5192ac1 --- /dev/null +++ b/src/pt-BR/internals/013-code-review.md @@ -0,0 +1,33 @@ +# 013 — Code review + +Code reviews são essenciais para o sucesso do projeto e tão importantes +quanto contribuir com código. + +As revisões são feitas por meio de pull requests no GitHub. Quando o pull +request está pronto para revisão, recebe o label "status: code review". + +[A lista completa de pull requests que precisam de +revisão](https://github.com/search?q=org%3Ayiisoft+label%3A"status%3Acode+review"&state=open&type=Issues) +está disponível no GitHub. + +## Diretrizes + +- Faça checkout do branch do pull request, abra o projeto na IDE e tenha uma + visão geral. +- O pull request faz sentido como um todo? +- Rode os testes e/ou a aplicação usando o código do pull request. Está tudo + certo? +- Leia todas as linhas de código do pull request. +- Daria para fazer de forma mais simples? +- Há problemas de segurança? +- Há problemas de desempenho? +- Ao deixar comentários, seja educado. +- Evite comentários sobre formatação de código. + +## Itens obrigatórios + +- [ ] Testes que falham sem o código e passam com ele. +- [ ] Type hints. +- [ ] `declare(strict_types=1)`. +- [ ] Documentação: phpdoc, yiisoft/docs. +- [ ] Entrada no changelog (se o pacote for estável). diff --git a/src/pt-BR/internals/014-docs.md b/src/pt-BR/internals/014-docs.md new file mode 100644 index 00000000..130eb6ec --- /dev/null +++ b/src/pt-BR/internals/014-docs.md @@ -0,0 +1,222 @@ +# 014 — Documentação + +A documentação é uma das partes mais importantes do Yii. + +## Documentação de pacotes + +A documentação de um pacote pode ficar no `README.md` ou em +`docs/{language}/{type}`, onde `{language}` é um código de idioma e `{type}` +pode ser "guide", "cookbook" ou outra coisa. Normalmente, `docs` existe +quando o uso ou a configuração do pacote não é trivial ou quando há +necessidade de tradução. + +Alguns indícios de que é hora de criar `docs`: + +1. Há necessidade de tradução. +2. Existem muitos tópicos, e cada um deles é grande por si só. + +Se o tamanho total do readme for menor que cerca de 200 linhas, não há +problema em manter a documentação no readme. + +## Guia definitivo + +O guia definitivo, +[yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/src/guide) +tem como objetivo cobrir o uso dos pacotes como um framework +completo. Diferente da documentação dos pacotes, ele não se concentra em um +único pacote, e sim em determinados casos de uso. + +O guia deve seguir o [guia de estilo da +Microsoft](https://learn.microsoft.com/en-us/style-guide/welcome/). + +### Tradução + +O guia definitivo usa o [po4a](https://github.com/mquinson/po4a) em uma GitHub Action para as traduções. + +Algoritmo de tradução: + +- Instale uma aplicação para trabalhar com arquivos de tradução `.po`. Por + exemplo, [Poedit](https://poedit.net/), + [Lokalize](https://apps.kde.org/ru/lokalize/), + [Gtranslator](https://wiki.gnome.org/Apps/Gtranslator) ou outra. +- Encontre o arquivo que você quer traduzir em + `_translations/guide/{lang}`. Observe que, se o arquivo original estiver + em uma subpasta, o nome da subpasta é adicionado ao nome do arquivo, + separado por um sublinhado. Por exemplo, para traduzir o arquivo + `guide/en/concept/aliases.md`, procure o arquivo + `_translations/guide/{lang}/concept_aliases.md.po`. +- Abra o arquivo com extensão `.po` no `Poedit` a partir da pasta com a + localização desejada, por exemplo + `_translations/guide/ru/intro_what-is-yii.md.po`. Se ainda não existir a + localização, crie uma issue. +- Traduza as strings necessárias e faça push das alterações +- Abra um pull request para o repositório principal + +> [!CAUTION] +> Não altere manualmente a tradução nos arquivos em `/guide/{lang}`. + +Se você alterou o texto em inglês e quer atualizar as traduções: + +- Abra um pull request para o repositório principal +- Faça pull do branch atualizado depois que o workflow `Update docs + translation` da GitHub Action terminar com sucesso +- Atualize a tradução nos arquivos `.po` com o `Poedit` +- Faça push das alterações + +## Blocos + +Os blocos usam o [formato GitHub +Alerts](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts): + +``` +> [!NOTE] +> Informação útil que os usuários devem saber, mesmo lendo o conteúdo por alto. + +> [!TIP] +> Conselho útil para fazer as coisas melhor ou com mais facilidade. + +> [!IMPORTANT] +> Informação essencial que os usuários precisam saber para alcançar o objetivo. + +> [!WARNING] +> Informação urgente que exige atenção imediata do usuário para evitar problemas. + +> [!CAUTION] +> Alerta sobre riscos ou consequências negativas de certas ações. +``` + +Ao traduzir a documentação, esses indicadores de bloco não devem ser +traduzidos. Mantenha-os intactos e traduza apenas o conteúdo do bloco. +Para traduzir o rótulo do bloco, cada tradução do guia deve ter um arquivo +`blocktypes.json` com as traduções. Veja a seguir um exemplo para o alemão: + +```json +{ + "Note": "Hinweis", + "Tip": "Tipp", + "Important": "Wichtig", + "Warning": "Achtung", + "Caution": "Vorsicht" +} +``` + +## PHPDoc + +Não se deve adicionar PHPDoc se ele não acrescentar nada ao que +descreve. Este é um mau exemplo: + +```php +use Psr\Log\LoggerInterface; + +/** + * MyService class + */ +final class MyService extends MyServiceBase +{ + /** + * @var LoggerInterface logger + */ + private LoggerInterface $logger; + + /** + * MyService constructor. + * @param LoggerInterface $logger + */ + public function __construct(LoggerInterface $logger) + { + $this->logger = $logger; + } + + /** + * @inheritDoc + */ + public function doit(): bool + { + return parent::doit(); + } +} +``` + +O PHPDoc, quando presente, deve descrever o propósito do elemento ao qual +foi adicionado. + +Omita valores padrão no PHPDoc quando o PHP já os mostra no valor padrão de +um parâmetro, no valor padrão de uma propriedade promovida ou no +inicializador de uma propriedade. A declaração é a fonte da verdade, e +repetir o valor no texto pode ficar desatualizado após mudanças no código. + +Exemplo de código incorreto: + +```php +/** + * @param bool $skipOnEmpty Whether to skip validation when the value is empty. Defaults to true. + */ +public function __construct( + private bool $skipOnEmpty = true, +) { +} +``` + +Exemplo de código válido: + +```php +/** + * @param bool $skipOnEmpty Whether to skip validation when the value is empty. + */ +public function __construct( + private bool $skipOnEmpty = true, +) { +} +``` + +As tags `@see` devem referenciar explicitamente métodos, propriedades e +constantes da classe. Isso é necessário para que os links sejam exibidos +corretamente nas IDEs e na documentação da API. + +Exemplo de código incorreto: + +```php +/** + * @see SOME_CONST + * @see $prop + * @see doSomething() + */ +final class Example +{ + public const SOME_CONST = ''; + public int $prop; + public function doSomething(): void {} +} +``` + +Exemplo de código válido: + +```php +/** + * @see Example::SOME_CONST + * @see Example::$prop + * @see Example::doSomething() + */ +final class Example +{ + public const SOME_CONST = ''; + public int $prop; + public function doSomething(): void {} +} +``` + +## Checklist do readme + +O readme de cada pacote deve ficar em `README.md` e conter o seguinte: + +- [ ] Logo. +- [ ] Descrição curta do pacote. O que ele faz? +- [ ] Badges de qualidade (build, cobertura de código). +- [ ] Captura de tela (se aplicável). +- [ ] Requisitos. +- [ ] Instalação. Normalmente `composer require`. +- [ ] Primeiros passos. Um ou dois exemplos de uso comuns. +- [ ] Configuração. +- [ ] Contribuindo. Deve conter um link para as diretrizes. +- [ ] Executando os testes. +- [ ] Licença. diff --git a/src/pt-BR/internals/015-phpstorm.md b/src/pt-BR/internals/015-phpstorm.md new file mode 100644 index 00000000..e1150af5 --- /dev/null +++ b/src/pt-BR/internals/015-phpstorm.md @@ -0,0 +1,70 @@ +# 015 — Metadados e atributos do PhpStorm + +## Metadados do PhpStorm + +Os [metadados do +PhpStorm](https://www.jetbrains.com/help/phpstorm/ide-advanced-metadata.html) +ajudam a IDE a entender melhor o código nos casos em que os tipos comuns e +as tags PHPDoc não ajudam. + +Usamos o seguinte conjunto de convenções de estilo para os metadados. + +### Localização dos metadados + +- Os metadados devem ficar no diretório `/.phpstorm.meta.php`. +- A configuração deve ser dividida em arquivos. Cada arquivo deve ter o nome + da classe que configura. + +> [!NOTE] +> O PhpStorm ainda não suporta subdiretórios. + +### Constantes + +Todos os dicionários de constantes devem ser nomeados como `{Class +FQN}::{Group name}`. O nome do grupo deve ser curto e escrito em letras +maiúsculas. Use sublinhado como separador de palavras, por exemplo +`\Yiisoft\Http\Status::STATUSES`. Por exemplo: + +```php +expectedReturnValues( + \Psr\Http\Message\RequestInterface::getMethod(), + argumentsSet('\Yiisoft\Http\Method::METHODS'), +); + +registerArgumentsSet( + '\Yiisoft\Http\Method::METHODS', + \Yiisoft\Http\Method::GET, + \Yiisoft\Http\Method::POST, + \Yiisoft\Http\Method::PUT, + \Yiisoft\Http\Method::DELETE, + \Yiisoft\Http\Method::PATCH, + \Yiisoft\Http\Method::HEAD, + \Yiisoft\Http\Method::OPTIONS, +); +``` + +## Atributos do PhpStorm + +Os [atributos do PhpStorm](https://github.com/JetBrains/phpstorm-attributes) +PODEM ser usados no código, mas o pacote `jetbrains/phpstorm-attributes` +DEVE ser adicionado como dependência de desenvolvimento: + +```shell +composer require --dev jetbrains/phpstorm-attributes +``` + +### Usando com o ComposerRequireChecker + +Quando o +[ComposerRequireChecker](https://github.com/maglnet/ComposerRequireChecker) +também é usado no mesmo pacote, adicione os nomes das classes dos atributos +envolvidos à whitelist na configuração. Por exemplo: + +```json +{ + "symbol-whitelist": [ + "JetBrains\\PhpStorm\\ExpectedValues", + "JetBrains\\PhpStorm\\Pure" + ] +} +``` diff --git a/src/pt-BR/internals/016-security-workflow.md b/src/pt-BR/internals/016-security-workflow.md new file mode 100644 index 00000000..d7c6e29f --- /dev/null +++ b/src/pt-BR/internals/016-security-workflow.md @@ -0,0 +1,68 @@ +# 016 — Fluxo de segurança + +Problemas de segurança normalmente são enviados pelo [formulário de +segurança](https://www.yiiframework.com/security). + +Se um problema for relatado diretamente em uma página pública, como uma issue do repositório ou um tópico do fórum, copie a mensagem +e apague a issue. Agradeça a quem relatou e indique o formulário de segurança para a próxima vez. + +```mermaid +flowchart TD + form[Relato pelo formulário de segurança] --> verify[Verificar o problema] + public[Relato público] --> remove[Salvar os detalhes e apagar a issue pública] + remove --> redirect[Indicar o formulário de segurança a quem relatou] + redirect --> verify + verify -->|precisa de detalhes| requestInfo[Pedir mais informações] + requestInfo --> verify + verify -->|válido| advisory[Criar rascunho de security advisory] + advisory --> severity[Definir a severidade CVSS] + severity --> credit[Perguntar sobre o crédito a quem relatou] + credit --> cve[Solicitar número CVE] + cve --> patch[Preparar pull request com o patch] + patch --> wait[Aguardar a atribuição do CVE] + wait --> release[Release] + release --> publish[Publicar o advisory e enviar entrada ao FriendsOfPHP] +``` + +## Verificar + +Verifique se o problema é válido. Peça mais informações, se necessário. + +## Adicionar security advisory + +Crie um rascunho de security advisory no GitHub. + +### Descobrir a severidade + +1. Obtenha a pontuação CVSS usando a [calculadora do + NVD](https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator). +2. Escolha a severidade com base na [escala de + classificação](https://www.first.org/cvss/specification-document#Qualitative-Severity-Rating-Scale). + +### Dar crédito a quem relatou + +Pergunte a quem relatou se deseja receber crédito por ter encontrado o +problema. Se sim, indique a conta dessa pessoa no GitHub. + +## Solicitar um número CVE + +Quando estiver pronto, solicite um CVE. + +## Preparar um patch + +Prepare um pull request que corrija o problema. O GitHub permite fazer isso +em um fork privado. + +## Aguardar a atribuição do número CVE + +Normalmente leva alguns dias. + +## Release + +- Faça o merge do pull request com o patch logo antes de criar a tag do + próximo release do pacote. +- Publique o security advisory. +- Adicione o CVE em + [FriendsOfPHP/security-advisories](https://github.com/FriendsOfPHP/security-advisories). + Veja [#488](https://github.com/FriendsOfPHP/security-advisories/pull/488) + como exemplo. diff --git a/src/pt-BR/internals/017-tags.md b/src/pt-BR/internals/017-tags.md new file mode 100644 index 00000000..1d4b5353 --- /dev/null +++ b/src/pt-BR/internals/017-tags.md @@ -0,0 +1,43 @@ +# 017 - Tags + +Diferente das classes comuns, as tags são usadas em templates de view, então +a sintaxe é importante. Ela deve ser fácil de escrever, fácil de ler e não +muito verbosa, porque construções parecidas são usadas repetidas vezes. + +## Nomes de classes + +- As tags não têm prefixo nem sufixo, a menos que sejam uma classe base + abstrata. +- Se a tag representa uma especificação, use o nome usado na especificação. + +## Herança + +A herança é permitida com algumas restrições: + +- Se uma classe não é abstrata, ela deve ser final. +- A hierarquia deve ser mantida o mais linear possível. + +## Imutabilidade + +As tags devem: + +- Não ter estado. +- Ser imutáveis. Todo método que modifica uma configuração retorna um clone + com a configuração alterada. +- Não ter efeitos colaterais. Várias chamadas do mesmo método com o mesmo + argumento devem dar o mesmo resultado. + +## Métodos + +### Nomes + +- Diferente de outras classes, os métodos que retornam um clone do objeto + com algumas propriedades modificadas não têm prefixo. +- Mantenha os nomes dos métodos o mais curtos possível, sem prejudicar a + legibilidade. +- Se a tag representa uma especificação, use o nome usado na especificação. + +### Flags booleanas + +O método que corresponde a um atributo booleano deve ter o nome do atributo +e aceitar um argumento booleano como flag. diff --git a/src/pt-BR/internals/018-widgets.md b/src/pt-BR/internals/018-widgets.md new file mode 100644 index 00000000..0131e1bc --- /dev/null +++ b/src/pt-BR/internals/018-widgets.md @@ -0,0 +1,38 @@ +# 018 - Widgets + +Diferente das classes comuns, os widgets são usados em templates de view, +então a sintaxe é importante. Ela deve ser fácil de escrever, fácil de ler +e não muito verbosa, porque construções parecidas são usadas repetidas +vezes. + +## Nomes de classes + +Os widgets não têm prefixo nem sufixo. + +## Herança + +A herança é permitida com algumas restrições: + +- Se uma classe não é abstrata, ela deve ser final. +- A hierarquia deve ser mantida o mais linear possível. + +## Imutabilidade + +Os widgets devem: + +- Não ter estado. +- Ser imutáveis. + +## Métodos + +### Nomes + +- Diferente de outras classes, os métodos que retornam um clone do objeto + com algumas propriedades modificadas não têm prefixo. +- Mantenha os nomes dos métodos o mais curtos possível, sem prejudicar a + legibilidade. + +### Flags booleanas + +O método que corresponde a um atributo booleano deve ter o nome do atributo +e aceitar um argumento booleano como flag. diff --git a/src/pt-BR/internals/019-view-code-style.md b/src/pt-BR/internals/019-view-code-style.md new file mode 100644 index 00000000..f04e19a4 --- /dev/null +++ b/src/pt-BR/internals/019-view-code-style.md @@ -0,0 +1,46 @@ +# 019 — Estilo de código das views + +O código PHP nos arquivos de view não deve ser complicado. O código deve +conter a lógica responsável por formatar os dados, mas não a lógica para +buscar esses dados. + +## Cabeçalho + +O cabeçalho do arquivo de view é usado para colocar o phpdoc que descreve as +variáveis disponíveis e para importar classes: + +```php + +

getTitle()) ?>

+

getDescription()) ?>

+ +``` + +## Short echo + +Prefira o short echo: + +```php + +``` + +## Métodos de classe + +Todos os métodos de classe usados em arquivos de view devem ser públicos, +mesmo que a view seja renderizada pela própria classe. diff --git a/src/pt-BR/internals/020-package-release.md b/src/pt-BR/internals/020-package-release.md new file mode 100644 index 00000000..f5d5186b --- /dev/null +++ b/src/pt-BR/internals/020-package-release.md @@ -0,0 +1,58 @@ +# 020 — Release de pacotes + +## Critérios + +- Nenhuma issue crítica. +- Mudanças na API pública são improváveis. Já passou algum tempo sem issues + relatadas que possam exigir mudanças na API. +- Todas as dependências são estáveis. +- Cobertura de testes próxima de 100% e, idealmente, score MSI de 100%. +- O README está em ordem. +- Tudo tem type hints, exceto em casos especiais. +- A análise do Psalm passa pelo menos no nível 2. +- O phpdoc está em ordem. +- A API pública está em ordem. + +## Política de branches de release + +Use `master` para todos os releases regulares. + +Crie um branch separado apenas ao lançar uma nova versão de uma versão major +anterior. Nesse caso, crie o branch a partir da tag mais recente dessa linha +de versão major anterior e aplique apenas as mudanças necessárias para o +release. + +## Instruções de release + +Faça o release de um pacote com a [Ferramenta de desenvolvimento do +Yii](005-development-tool.md). + +1. Verifique se você consegue assinar commits localmente (veja +[Assinando commits](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits)). + +2. Para releases regulares, faça pull das últimas mudanças do branch + `master`: + +```shell +./yii-dev git/checkout master package-name +./yii-dev git/pull package-name +``` + +Para releases de versões major anteriores, use o branch criado de acordo com +a política de branches de release, em vez de `master`. + +3. Verifique se o pacote atende aos critérios acima. + +4. Execute o comando `release/make`: + +```shell +./yii-dev release/make package-name +``` + +5. Selecione o tipo de versão (major, minor ou patch). + +6. Na pergunta "Push commits and tags, and release on GitHub?", confira o + diff. Se o diff estiver correto, responda "yes". + +7. Para releases major e minor, adicione um registro com as notas de release + em [Yii Framework News](https://www.yiiframework.com/news). diff --git a/src/pt-BR/internals/021-changelog-upgrade.md b/src/pt-BR/internals/021-changelog-upgrade.md new file mode 100644 index 00000000..1f9dc5d1 --- /dev/null +++ b/src/pt-BR/internals/021-changelog-upgrade.md @@ -0,0 +1,68 @@ +# 021 — Changelog e upgrade + +Para todos os pacotes lançados, mantemos um changelog detalhado e um guia de +upgrade. + +## Changelog + +O changelog é escrito para cada versão lançada. O nome do arquivo é +`CHANGELOG.md`. O formato é o seguinte: + +```markdown +# My package Change Log + +## 1.0.2 under development + +- no changes in this release. + +## 1.0.1 March 23, 2021 + +- Bug #42: Short description of the change (@author1, @author2) + +## 1.0.0 February 02, 2021 + +- Initial release. +``` + +Ali, "My package" é o nome do pacote, `1.0.1` é a versão lançada, seguida da +data de release. Para cada versão, há algumas linhas listando as mudanças. +"Bug" indica o tipo da mudança. São usados os seguintes tipos: + +- New — Novas funcionalidades. +- Chg — Mudanças gerais. +- Enh — Melhorias em funcionalidades existentes. +- Bug — Correções de bugs. + +No arquivo de changelog, as linhas devem ser ordenadas como New, Chg, Enh, +Bug. + +"#42" acima é o número da issue ou do pull request correspondente à +mudança. "author1" é o nickname no GitHub do autor do código. "author2" é um +autor adicional. O nickname de um autor DEVE ter o prefixo `@`. + +## Upgrade + +O guia de upgrade é criado quando há uma nova versão major que não é +compatível com a anterior. Ele descreve os passos necessários para fazer o +upgrade do código da aplicação. + +O nome do arquivo é `UPGRADE.md`. O formato é o seguinte: + +```markdown +# Upgrading Instructions for my package + +This file contains the upgrade notes. These notes highlight changes that could break your +application when you upgrade the package from one version to another. + +> **Important!** The following upgrading instructions are cumulative. That is, if you want +> to upgrade from version A to version C and there is version B between A and C, you need +> to follow the instructions for both A and B. + +## Upgrade from 2.x + +- Public method `test()` was removed. Use `perform()` instead. + +## Upgrade from 1.x + +- Clean up the cache after upgrading. Old cache is not compatible with new code. +``` diff --git a/src/pt-BR/internals/022-config-groups.md b/src/pt-BR/internals/022-config-groups.md new file mode 100644 index 00000000..c7a29eb7 --- /dev/null +++ b/src/pt-BR/internals/022-config-groups.md @@ -0,0 +1,75 @@ +# 022 — Grupos de configuração + +Este documento define a convenção de nomes para os grupos do framework +usados com o [yiisoft/config](https://github.com/yiisoft/config). Observe +que esta não é uma convenção de nomes para arquivos de configuração. Eles +podem ter qualquer nome e são mapeados para os nomes de grupo via +`composer.json`. + +## Sufixos dos nomes de grupos de configuração + +- O sufixo "web" se aplica apenas à web, ou seja, geração clássica de HTML + no servidor, REST, RPC etc. +- O sufixo "console" se aplica ao console +- Se não houver sufixo, o grupo é "common" e se aplica tanto à web quanto ao + console +- "web" e "console" podem sobrescrever o que está definido em "common" + +## Parâmetros + +Parâmetros de configuração da aplicação usados em todas as configurações. + +- `params` — parâmetros comuns +- `params-web` — parâmetros da aplicação web +- `params-console` — parâmetros da aplicação de console + +## Container + +Configuração do [yiisoft/di](https://github.com/yiisoft/di). + +### Definições + +- `di` — definições comuns do container +- `di-web` — definições do container para web +- `di-console` — definições do container para console + +### Providers + +- `di-providers` — providers comuns do container +- `di-providers-web` — providers do container para web +- `di-providers-console` — providers do container para console + +### Delegates + +- `di-delegates` — delegates comuns do container +- `di-delegates-web` — delegates do container para web +- `di-delegates-console` — delegates do container para console + +### Tags + +- `di-tags` — tags comuns do container +- `di-tags-web` — tags do container para web +- `di-tags-console` — tags do container para console + +## Eventos + +Configuração do [yiisoft/yii-event](https://github.com/yiisoft/yii-event). + +- `events` — eventos comuns +- `events-web` — eventos da web +- `events-console` — eventos do console + +## Bootstrap + +Bootstrap da aplicação para o +[yiisoft/yii-runner](https://github.com/yiisoft/yii-runner). + +- `bootstrap` — bootstrap comum +- `bootstrap-web` — bootstrap da web +- `bootstrap-console` — bootstrap do console + +## Outros + +- `routes` — rotas do [yiisoft/router](https://github.com/yiisoft/router) +- `widgets` — configuração padrão de widgets do + [yiisoft/widget](https://github.com/yiisoft/widget) diff --git a/src/pt-BR/internals/023-github-actions.md b/src/pt-BR/internals/023-github-actions.md new file mode 100644 index 00000000..62b0fc63 --- /dev/null +++ b/src/pt-BR/internals/023-github-actions.md @@ -0,0 +1,34 @@ +# 023 — GitHub Actions + +Este documento define a convenção de nomes para os arquivos de configuração +das GitHub Actions. + +## Inputs e outputs + +Os nomes de inputs e de outputs devem usar o formato kebab-case. + +Por exemplo: + +```yaml +inputs: + my-input: + description: 'My input' +``` + +## Secrets e variáveis de ambiente + +Os nomes de secrets e de variáveis de ambiente devem usar o formato +SCREAMING_SNAKE_CASE. + +Por exemplo: + +```yaml +secrets: + MY_SECRET: + description: 'My secret' +``` + +```yaml +env: + MY_ENV_VAR: 1 +``` diff --git a/src/pt-BR/internals/index.md b/src/pt-BR/internals/index.md new file mode 100644 index 00000000..1c754e2e --- /dev/null +++ b/src/pt-BR/internals/index.md @@ -0,0 +1,48 @@ +# Detalhes internos do Yii Framework + +Esta seção contém documentação para quem contribui com o próprio framework +Yii. Ela cobre diretrizes, fluxos de trabalho e boas práticas para manter e +desenvolver os pacotes do Yii. + +## Sumário + +- [000 — Pacotes](000-packages.md) - Estrutura e convenções de nomes dos + pacotes +- [001 — Objetivo e valores do Yii](001-yii-values.md) - Objetivos e valores + centrais do projeto +- [002 — Fluxo de issues](002-issue-workflow.md) - Como lidar com issues +- [003 — Roadmap](003-roadmap.md) - Roadmap de desenvolvimento e planos + futuros +- [004 — Namespaces](004-namespaces.md) - Convenções de namespaces +- [005 — Ferramenta de desenvolvimento do Yii](005-development-tool.md) - + Ferramentas de desenvolvimento para pacotes do Yii +- [006 — Mensagens de commit no Git](006-git-commit-messages.md) - Formato + das mensagens de commit +- [007 — Exceções](007-exceptions.md) - Diretrizes para exceções +- [008 — Interfaces](008-interfaces.md) - Princípios de design de interfaces +- [009 — Decisões de design](009-design-decisions.md) - Decisões de + arquitetura e design +- [010 — Estilo de código](010-code-style.md) - Diretrizes de estilo de + código PHP +- [011 — Correção de erros](011-error-correction.md) - Tratamento e correção + de erros +- [012 — Testes](012-tests.md) - Diretrizes e práticas de testes +- [013 — Code review](013-code-review.md) - Processo e diretrizes de code + review +- [014 — Documentação](014-docs.md) - Diretrizes para escrever documentação +- [015 — Metadados e atributos do PhpStorm](015-phpstorm.md) - Integração + com o PhpStorm +- [016 — Fluxo de segurança](016-security-workflow.md) - Tratamento de + problemas de segurança +- [017 — Tags](017-tags.md) - Convenções de tags no Git +- [018 — Widgets](018-widgets.md) - Diretrizes para desenvolver widgets +- [019 — Estilo de código de views](019-view-code-style.md) - Estilo de + código para templates de view +- [020 — Release de pacotes](020-package-release.md) - Processo de release + de pacotes +- [021 — Changelog e upgrade](021-changelog-upgrade.md) - Mantendo + changelogs e notas de upgrade +- [022 — Grupos de configuração](022-config-groups.md) - Organização dos + grupos de configuração +- [023 - GitHub Actions](023-github-actions.md) - Configuração do GitHub + Actions diff --git a/src/ru/cookbook/organizing-code/service.md b/src/ru/cookbook/organizing-code/service.md index f0a09a4d..1a1517c1 100644 --- a/src/ru/cookbook/organizing-code/service.md +++ b/src/ru/cookbook/organizing-code/service.md @@ -115,5 +115,5 @@ into. Check: - Репозиторий - Widget -- [Middleware](middleware.md) +- [Middleware](../../guide/structure/middleware.md) - Entity diff --git a/src/ru/guide/caching/data.md b/src/ru/guide/caching/data.md index 0b7d1a62..86d7aee1 100644 --- a/src/ru/guide/caching/data.md +++ b/src/ru/guide/caching/data.md @@ -2,7 +2,7 @@ Data caching is about storing some PHP variables in a cache and retrieving them later from the cache. It's also the foundation for more advanced -caching features, such as [page caching](page.md). +caching features, such as page caching. To use cache, install [yiisoft/cache](https://github.com/yiisoft/cache) package: @@ -54,7 +54,7 @@ Yii provides the following handlers: - `ArrayCache` — provides caching for the current request only by storing the values in an array. - [APCu](https://github.com/yiisoft/cache-apcu) - uses a PHP - [APC](https://secure.php.net/manual/en/book.apc.php) extension. You can + [APC](https://www.php.net/manual/en/book.apcu.php) extension. You can consider this option as the fastest one when dealing with cache for a centralized thick application (e.g., one server, no dedicated load balancers, etc.). diff --git a/src/ru/guide/caching/overview.md b/src/ru/guide/caching/overview.md index 2e2d4845..bf15f442 100644 --- a/src/ru/guide/caching/overview.md +++ b/src/ru/guide/caching/overview.md @@ -16,6 +16,6 @@ content in the browser cache. Yii supports all these caching mechanisms: * [Data caching](data.md) -* [Fragment caching](fragment.md) -* [Page caching](page.md) -* [HTTP caching](http.md) +* Fragment caching +* Page caching +* HTTP caching diff --git a/src/ru/guide/glossary.md b/src/ru/guide/glossary.md index bbf357a0..da4a6971 100644 --- a/src/ru/guide/glossary.md +++ b/src/ru/guide/glossary.md @@ -213,7 +213,7 @@ does the actual processing. Service is a focused object that performs application work or provides infrastructure behavior and is usually stored in the DI container. Read -more in ["Service components"](structure/service.md). +more in ["Service components"](../cookbook/organizing-code/service.md). ## service provider diff --git a/src/ru/guide/security/best-practices.md b/src/ru/guide/security/best-practices.md index 0507a75f..c03e3170 100644 --- a/src/ru/guide/security/best-practices.md +++ b/src/ru/guide/security/best-practices.md @@ -122,7 +122,7 @@ XSS или кросс-сайтинговый скриптинг становит ``` Если нужно вывести HTML, вам лучше воспользоваться -[HtmlPurifier](http://htmlpurifier.org/). +[HtmlPurifier](https://github.com/ezyang/htmlpurifier). Обратите внимание, что обработка с помощью HtmlPurifier довольно тяжела, поэтому рассмотрите возможность использования кеширования. @@ -211,8 +211,8 @@ token-in-form. Дополнительная информация по теме: -- -- +- +- ## Использование безопасного подключения через TLS diff --git a/src/ru/guide/start/hello.md b/src/ru/guide/start/hello.md index 26326214..16b28fa4 100644 --- a/src/ru/guide/start/hello.md +++ b/src/ru/guide/start/hello.md @@ -5,7 +5,7 @@ ничего не передано — просто говорит «Hello!». Чтобы этого добиться, вы определите маршрут и создадите -[обработчик](../structure/handler.md), который выполнит задачу и сформирует +[обработчик](../structure/action.md), который выполнит задачу и сформирует ответ. Затем вы улучшите решение, используя [представление](../views/view.md) для построения ответа. diff --git a/src/ru/guide/structure/overview.md b/src/ru/guide/structure/overview.md index 3d8f5d9d..19195461 100644 --- a/src/ru/guide/structure/overview.md +++ b/src/ru/guide/structure/overview.md @@ -48,9 +48,9 @@ contexts, it's moved to the ancestor of both contexts. A context may have [an entry point known as "action" or "controller"](action.md). Its job is to take [a request -instance](../runtime/request.md), pass it to [domain layer](domain.md) in a -suitable format, and create [a response](../runtime/response.md) based on -domain layer return. +instance](../runtime/request.md), pass it to [domain +layer](../../cookbook/organizing-code/domain.md) in a suitable format, and +create [a response](../runtime/response.md) based on domain layer return. Besides, Yii applications also have the following: @@ -58,8 +58,9 @@ Besides, Yii applications also have the following: accessible by end users. They're responsible for starting a request handling cycle. Typically, a single entry script is handling the whole application. -* [services](service.md): they're typically stateless objects registered - within dependency container and provide various action methods. +* [services](../../cookbook/organizing-code/service.md): they're typically + stateless objects registered within dependency container and provide + various action methods. * [middleware](middleware.md): they represent a code that needs to be invoked before and after the actual handling of each request by action handlers. diff --git a/src/ru/internals/014-docs.md b/src/ru/internals/014-docs.md index 76c3ea24..88b83b32 100644 --- a/src/ru/internals/014-docs.md +++ b/src/ru/internals/014-docs.md @@ -21,7 +21,7 @@ keep documentation in the readme. ## Definitive guide The definitive guide, -[yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/guide/en) +[yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/src/guide) aims at covering usage of packages as a whole framework. Unlike package documentation, it isn't focused on a single package but is covering certain use-cases. diff --git a/src/zh-CN/cookbook/organizing-code/service.md b/src/zh-CN/cookbook/organizing-code/service.md index 0b1a7efe..54b0c80a 100644 --- a/src/zh-CN/cookbook/organizing-code/service.md +++ b/src/zh-CN/cookbook/organizing-code/service.md @@ -115,5 +115,5 @@ into. Check: - 仓库 - Widget -- [Middleware](middleware.md) +- [Middleware](../../guide/structure/middleware.md) - Entity diff --git a/src/zh-CN/guide/caching/data.md b/src/zh-CN/guide/caching/data.md index ef1f0590..e2850591 100644 --- a/src/zh-CN/guide/caching/data.md +++ b/src/zh-CN/guide/caching/data.md @@ -1,6 +1,6 @@ # 数据缓存 -数据缓存是将一些 PHP 变量存储在缓存中,然后稍后从缓存中检索它们。它也是更高级缓存功能(如 [页面缓存](page.md))的基础。 +数据缓存是将一些 PHP 变量存储在缓存中,然后稍后从缓存中检索它们。它也是更高级缓存功能(如 页面缓存)的基础。 要使用缓存,请安装 [yiisoft/cache](https://github.com/yiisoft/cache) 包: @@ -40,7 +40,7 @@ Yii 提供以下处理器: 一个不进行实际缓存的缓存占位符。此处理器的目的是简化需要检查缓存可用性的代码。例如,在开发期间或服务器没有实际缓存支持时,您可以配置缓存服务使用此处理器。当您启用实际缓存支持时,可以切换到使用相应的缓存处理器。在这两种情况下,您都可以使用相同的代码而无需额外检查。 - `ArrayCache` — 通过将值存储在数组中,仅为当前请求提供缓存。 - [APCu](https://github.com/yiisoft/cache-apcu) - 使用 PHP - [APC](https://secure.php.net/manual/en/book.apc.php) + [APC](https://www.php.net/manual/en/book.apcu.php) 扩展。在处理集中式厚应用程序(例如,单服务器,无专用负载均衡器等)的缓存时,您可以将此选项视为最快的选项。 - [数据库](https://github.com/yiisoft/cache-db) — 使用数据库表存储缓存数据。 - [文件](https://github.com/yiisoft/cache-file) — diff --git a/src/zh-CN/guide/caching/overview.md b/src/zh-CN/guide/caching/overview.md index a4273809..2b6ac6ef 100644 --- a/src/zh-CN/guide/caching/overview.md +++ b/src/zh-CN/guide/caching/overview.md @@ -8,6 +8,6 @@ Web 页面的片段或整体,例如最新文章的渲染结果。在客户端 Yii 支持所有这些缓存机制: * [数据缓存](data.md) -* [片段缓存](fragment.md) -* [页面缓存](page.md) -* [HTTP 缓存](http.md) +* 片段缓存 +* 页面缓存 +* HTTP 缓存 diff --git a/src/zh-CN/guide/glossary.md b/src/zh-CN/guide/glossary.md index de20d887..b466663f 100644 --- a/src/zh-CN/guide/glossary.md +++ b/src/zh-CN/guide/glossary.md @@ -202,7 +202,7 @@ generation"](runtime/routing.md). Service is a focused object that performs application work or provides infrastructure behavior and is usually stored in the DI container. Read -more in ["Service components"](structure/service.md). +more in ["Service components"](../cookbook/organizing-code/service.md). ## service provider diff --git a/src/zh-CN/guide/security/best-practices.md b/src/zh-CN/guide/security/best-practices.md index fb0010d5..72cd11d6 100644 --- a/src/zh-CN/guide/security/best-practices.md +++ b/src/zh-CN/guide/security/best-practices.md @@ -105,7 +105,7 @@ XSS 或跨站脚本攻击发生在向浏览器输出 HTML 时输出未正确转 ``` -如果它应该是 HTML,您可以从 [HtmlPurifier](http://htmlpurifier.org/) +如果它应该是 HTML,您可以从 [HtmlPurifier](https://github.com/ezyang/htmlpurifier) 获得一些帮助。请注意,HtmlPurifier 处理相当繁重,因此请考虑添加缓存。 有关该主题的进一步阅读: @@ -175,8 +175,8 @@ token-in-form. 有关该主题的进一步阅读: -- -- +- +- ## 通过 TLS 使用安全连接 diff --git a/src/zh-CN/guide/start/hello.md b/src/zh-CN/guide/start/hello.md index b9c77ce9..a24d7127 100644 --- a/src/zh-CN/guide/start/hello.md +++ b/src/zh-CN/guide/start/hello.md @@ -2,7 +2,7 @@ 本节描述如何在应用程序中创建一个新的“Hello”页面。这是一个简单的页面,它会回显您传递给它的任何内容,或者如果没有传递任何内容,则显示“Hello!”。 -为实现这个目标,您将定义一个路由并创建一个 [处理器](../structure/handler.md) +为实现这个目标,您将定义一个路由并创建一个 [处理器](../structure/action.md) 来完成工作并形成响应。然后您将改进它,使用[视图](../views/view.md)来构建响应。 通过本教程,您将学习三件事: diff --git a/src/zh-CN/guide/structure/overview.md b/src/zh-CN/guide/structure/overview.md index 08893e15..e3f120d9 100644 --- a/src/zh-CN/guide/structure/overview.md +++ b/src/zh-CN/guide/structure/overview.md @@ -45,11 +45,12 @@ App/ 一个上下文可以有 [一个称为“动作”或“控制器”的入口点](action.md)。它的工作是获取[请求实例](../runtime/request.md),以适当的格式将其传递给 -[领域层](domain.md),并根据领域层的返回创建 [响应](../runtime/response.md)。 +[领域层](../../cookbook/organizing-code/domain.md),并根据领域层的返回创建 +[响应](../runtime/response.md)。 此外,Yii 应用程序还具有以下内容: * [入口脚本](entry-script.md):它们是最终用户可以直接访问的 PHP 脚本。它们负责启动请求处理周期。通常,单个入口脚本处理整个应用程序。 -* [服务](service.md):它们通常是在依赖容器中注册的无状态对象,并提供各种操作方法。 +* [服务](../../cookbook/organizing-code/service.md):它们通常是在依赖容器中注册的无状态对象,并提供各种操作方法。 * [中间件](middleware.md):它们表示需要在操作处理器实际处理每个请求之前和之后调用的代码。 diff --git a/src/zh-CN/internals/014-docs.md b/src/zh-CN/internals/014-docs.md index 96d7cd16..1f63bea8 100644 --- a/src/zh-CN/internals/014-docs.md +++ b/src/zh-CN/internals/014-docs.md @@ -17,7 +17,7 @@ ## 权威指南 权威指南 -[yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/guide/en) +[yiisoft/docs/guide](https://github.com/yiisoft/docs/tree/master/src/guide) 旨在涵盖作为整个框架的包的使用。与包文档不同,它不专注于单个包,而是涵盖某些用例。 指南应遵循 [Microsoft