diff --git a/_translations/po/it/cookbook_configuring-webservers_apache.md.po b/_translations/po/it/cookbook_configuring-webservers_apache.md.po new file mode 100644 index 00000000..fd6af851 --- /dev/null +++ b/_translations/po/it/cookbook_configuring-webservers_apache.md.po @@ -0,0 +1,87 @@ +# Italian 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 09:13+0000\n" +"PO-Revision-Date: 2025-12-24 09:13+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/cookbook/configuring-webservers/apache.md +#, no-wrap +msgid "Configuring web servers: Apache" +msgstr "" + +#. 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 "" + +#. 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" +" # if $showScriptName is false in UrlManager, do not allow accessing URLs with script name\n" +" RewriteRule ^index.php/ - [L,R=404]\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 "" + +#. 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 "" + +#. 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" +"# if $showScriptName is false in UrlManager, do not allow accessing URLs with script name\n" +"RewriteRule ^index.php/ - [L,R=404]\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 "" + +#. type: Plain text +#: ../src/cookbook/configuring-webservers/apache.md +msgid "In the above, note the usage of `SetEnv`. Since the Yii3 application template is using environment variables, this is a possible place to set them. In production environment remember to set `APP_ENV` to `prod`." +msgstr "" diff --git a/_translations/po/it/cookbook_configuring-webservers_general.md.po b/_translations/po/it/cookbook_configuring-webservers_general.md.po new file mode 100644 index 00000000..4a8994ef --- /dev/null +++ b/_translations/po/it/cookbook_configuring-webservers_general.md.po @@ -0,0 +1,70 @@ +# Italian 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 20:05+0000\n" +"PO-Revision-Date: 2025-12-24 20:05+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/cookbook/configuring-webservers/general.md +#, no-wrap +msgid "Configuring web servers: General" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/cookbook/configuring-webservers/general.md +#, no-wrap +msgid "Specific server configurations" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-webservers/general.md +#, fuzzy +#| msgid "[Logging](runtime/logging.md)" +msgid "[Nginx](nginx.md)" +msgstr "[Logging](runtime/logging.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-webservers/general.md +msgid "[Apache](apache.md)" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-webservers/general.md +msgid "[Lighttpd](lighttpd.md)" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-webservers/general.md +msgid "[Nginx Unit](nginx-unit.md)" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/cookbook/configuring-webservers/general.md +msgid "[IIS](iis.md)" +msgstr "" diff --git a/_translations/po/it/cookbook_configuring-webservers_iis.md.po b/_translations/po/it/cookbook_configuring-webservers_iis.md.po new file mode 100644 index 00000000..3ffc7714 --- /dev/null +++ b/_translations/po/it/cookbook_configuring-webservers_iis.md.po @@ -0,0 +1,69 @@ +# Italian 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-05 14:50+0500\n" +"PO-Revision-Date: 2025-09-05 14:50+0500\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: en/configuring-webservers/iis.md +#, no-wrap +msgid "Configuring web servers: IIS" +msgstr "" + +#. type: Plain text +#: en/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 "" + +#. type: Fenced code block (xml) +#: en/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 "" + +#. type: Plain text +#: en/configuring-webservers/iis.md +msgid "Also, the following list of Microsoft's official resources could be useful to configure PHP on IIS:" +msgstr "" + +#. type: Bullet: '1. ' +#: en/configuring-webservers/iis.md +msgid "[How to set up your first IIS website](https://support.microsoft.com/en-us/help/323972/how-to-set-up-your-first-iis-web-site)" +msgstr "" + +#. type: Bullet: '2. ' +#: en/configuring-webservers/iis.md +msgid "[Configure a PHP Website on IIS](https://docs.microsoft.com/en-us/iis/application-frameworks/scenario-build-a-php-website-on-iis/configure-a-php-website-on-iis)" +msgstr "" diff --git a/_translations/po/it/cookbook_configuring-webservers_lighttpd.md.po b/_translations/po/it/cookbook_configuring-webservers_lighttpd.md.po new file mode 100644 index 00000000..d360277a --- /dev/null +++ b/_translations/po/it/cookbook_configuring-webservers_lighttpd.md.po @@ -0,0 +1,35 @@ +# Italian 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-05 14:50+0500\n" +"PO-Revision-Date: 2025-09-05 14:50+0500\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: en/configuring-webservers/lighttpd.md +#, no-wrap +msgid "Configuring web servers: lighttpd" +msgstr "" + +#. type: Plain text +#: en/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 "" + +#. type: Fenced code block +#: en/configuring-webservers/lighttpd.md +#, no-wrap +msgid "url.rewrite-if-not-file = (\"(.*)\" => \"/index.php/$0\")\n" +msgstr "" diff --git a/_translations/po/it/cookbook_configuring-webservers_nginx-unit.md.po b/_translations/po/it/cookbook_configuring-webservers_nginx-unit.md.po new file mode 100644 index 00000000..6da8ace9 --- /dev/null +++ b/_translations/po/it/cookbook_configuring-webservers_nginx-unit.md.po @@ -0,0 +1,97 @@ +# Italian 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-05 14:50+0500\n" +"PO-Revision-Date: 2025-09-05 14:50+0500\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: en/configuring-webservers/nginx-unit.md +#, no-wrap +msgid "Configuring web servers: NGINX Unit" +msgstr "" + +#. type: Plain text +#: en/configuring-webservers/nginx-unit.md +msgid "Run Yii-based apps using [NGINX Unit](https://unit.nginx.org/) with a PHP language module. Here is a sample configuration." +msgstr "" + +#. type: Fenced code block (json) +#: en/configuring-webservers/nginx-unit.md +#, no-wrap +msgid "" +"{\n" +" \"listeners\": {\n" +" \"*:80\": {\n" +" \"pass\": \"routes/yii\"\n" +" }\n" +" },\n" +"\n" +" \"routes\": {\n" +" \"yii\": [\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/\",\n" +" \"fallback\": {\n" +" \"pass\": \"applications/yii/index\"\n" +" }\n" +" }\n" +" }\n" +" ]\n" +" },\n" +"\n" +" \"applications\": {\n" +" \"yii\": {\n" +" \"type\": \"php\",\n" +" \"user\": \"www-data\",\n" +" \"environment\": {\n" +" \"APP_ENV\": \"dev\"\n" +" },\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 "" + +#. type: Plain text +#: en/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 "" + +#. type: Plain text +#: en/configuring-webservers/nginx-unit.md +msgid "In the above, note the usage of `environment`. Since the Yii3 application template is using environment variables, this is a possible place to set them. In production environment remember to set `APP_ENV` to `prod`." +msgstr "" diff --git a/_translations/po/it/cookbook_configuring-webservers_nginx.md.po b/_translations/po/it/cookbook_configuring-webservers_nginx.md.po new file mode 100644 index 00000000..bd4d460a --- /dev/null +++ b/_translations/po/it/cookbook_configuring-webservers_nginx.md.po @@ -0,0 +1,92 @@ +# Italian 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-05 14:50+0500\n" +"PO-Revision-Date: 2025-09-05 14:50+0500\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: en/configuring-webservers/nginx.md +#, no-wrap +msgid "Configuring web servers: Nginx" +msgstr "" + +#. type: Plain text +#: en/configuring-webservers/nginx.md +msgid "To use [Nginx](https://wiki.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 "" + +#. type: Fenced code block (nginx) +#: en/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 "" + +#. type: Plain text +#: en/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 "" + +#. type: Plain text +#: en/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 "" + +#. type: Plain text +#: en/configuring-webservers/nginx.md +msgid "In the above, note the usage of `fastcgi_param APP_ENV`. Since the Yii3 application template is using environment variables, this is a possible place to set them. In production environment remember to set `APP_ENV` to `prod`." +msgstr "" diff --git a/_translations/po/it/cookbook_deployment_docker-swarm-caddy.md.po b/_translations/po/it/cookbook_deployment_docker-swarm-caddy.md.po new file mode 100644 index 00000000..6e1accbf --- /dev/null +++ b/_translations/po/it/cookbook_deployment_docker-swarm-caddy.md.po @@ -0,0 +1,1100 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#, no-wrap +msgid "Deploying Yii applications to Docker Swarm and Caddy" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "SSH access to your server" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Server preparation" +msgstr "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Install Docker" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Initialize Docker Swarm" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#, no-wrap +msgid "Setting up Caddy as reverse proxy" +msgstr "" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +msgid "To deploy Caddy as reverse proxy create a file `caddy-stack.yml`:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +msgid "Deploy Caddy:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Option 1: Using Forgejo" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Deploy Forgejo:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Option 2: Using Gitea" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Deploy Gitea:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Configuring your Yii application" +msgstr "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Update the Makefile configuration" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Configure the production environment" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +msgid "The default `docker/prod/compose.yml` includes:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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:15-alpine\n" +" environment:\n" +" POSTGRES_DB: myapp\n" +" POSTGRES_USER: myapp\n" +" POSTGRES_PASSWORD_FILE: /run/secrets/db_password\n" +" volumes:\n" +" - db_data:/var/lib/postgresql/data\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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Build the production image" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "This executes:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Deploying to Docker Swarm" +msgstr "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Configure SSH access" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Set up Docker context" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Deploy the application" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Verify the deployment" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, fuzzy +msgid "View logs:" +msgstr "Viste" + +#. 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 "" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Monitoring and maintenance" +msgstr "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "View service logs" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Scale the application" +msgstr "" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Adjust the number of replicas:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Resource limits" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Update `docker/prod/compose.yml`:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Set up a firewall" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Keep the system updated" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#: ../src/guide/views/asset.md +#, fuzzy, no-wrap +msgid "Troubleshooting" +msgstr "Testing" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Service won't start" +msgstr "" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Check service events and logs:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "SSL certificate issues" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Container registry connection issues" +msgstr "" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Test registry connectivity:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Summary" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" diff --git a/_translations/po/it/cookbook_deployment_docker-swarm-traefik.md.po b/_translations/po/it/cookbook_deployment_docker-swarm-traefik.md.po new file mode 100644 index 00000000..8a8a849e --- /dev/null +++ b/_translations/po/it/cookbook_deployment_docker-swarm-traefik.md.po @@ -0,0 +1,1100 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"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/cookbook/preface.md +#, no-wrap +msgid "Prerequisites" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "SSH access to your server" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Server preparation" +msgstr "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Install Docker" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Initialize Docker Swarm" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Option 1: Using Forgejo" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Deploy Forgejo:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Option 2: Using Gitea" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Deploy Gitea:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Configuring your Yii application" +msgstr "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Update the Makefile configuration" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Configure the production environment" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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:15-alpine\n" +" environment:\n" +" POSTGRES_DB: myapp\n" +" POSTGRES_USER: myapp\n" +" POSTGRES_PASSWORD_FILE: /run/secrets/db_password\n" +" volumes:\n" +" - db_data:/var/lib/postgresql/data\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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Build the production image" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "This executes:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Deploying to Docker Swarm" +msgstr "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Configure SSH access" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Set up Docker context" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Deploy the application" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Verify the deployment" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, fuzzy +msgid "View logs:" +msgstr "Viste" + +#. 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 "" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Monitoring and maintenance" +msgstr "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "View service logs" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Scale the application" +msgstr "" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Adjust the number of replicas:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Resource limits" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Update `docker/prod/compose.yml`:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Set up a firewall" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Keep the system updated" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#: ../src/guide/views/asset.md +#, fuzzy, no-wrap +msgid "Troubleshooting" +msgstr "Testing" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Service won't start" +msgstr "" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Check service events and logs:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "SSL certificate issues" +msgstr "" + +#. type: Title ### +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Container registry connection issues" +msgstr "" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Test registry connectivity:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-caddy.md +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Summary" +msgstr "" + +#. 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 "" + +#. type: Title # +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Deploying Yii applications to Docker Swarm and Traefik" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm-traefik.md +#, no-wrap +msgid "Setting up Traefik as reverse proxy" +msgstr "" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "To deploy Traefik as reverse proxy create a file `traefik-stack.yml`:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/cookbook/deployment/docker-swarm-traefik.md +msgid "Deploy Traefik:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" diff --git a/_translations/po/it/cookbook_deployment_docker-swarm.md.po b/_translations/po/it/cookbook_deployment_docker-swarm.md.po new file mode 100644 index 00000000..fce00a59 --- /dev/null +++ b/_translations/po/it/cookbook_deployment_docker-swarm.md.po @@ -0,0 +1,33 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/cookbook/deployment/docker-swarm.md +#, no-wrap +msgid "Deploying Yii applications to Docker Swarm" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/docker-swarm.md +msgid "[Using Caddy](docker-swarm-caddy.md)" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/cookbook/deployment/docker-swarm.md +msgid "[Using Traefik](docker-swarm-traefik.md)" +msgstr "" diff --git a/_translations/po/it/cookbook_disabling-csrf-protection.md.po b/_translations/po/it/cookbook_disabling-csrf-protection.md.po new file mode 100644 index 00000000..3a949fa6 --- /dev/null +++ b/_translations/po/it/cookbook_disabling-csrf-protection.md.po @@ -0,0 +1,313 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"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/cookbook/disabling-csrf-protection.md +#, no-wrap +msgid "Security considerations" +msgstr "" + +#. type: Title # +#: ../src/cookbook/disabling-csrf-protection.md +#, no-wrap +msgid "Disabling CSRF protection" +msgstr "" + +#. type: Title ## +#: ../src/cookbook/disabling-csrf-protection.md +#, no-wrap +msgid "What is CSRF protection?" +msgstr "" + +#. 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\\Csrf` middleware." +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/cookbook/disabling-csrf-protection.md +#, no-wrap +msgid "When to disable CSRF protection" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/cookbook/disabling-csrf-protection.md +#, no-wrap +msgid "When external systems cannot provide CSRF tokens" +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Third-party integrations**: External services cannot provide valid CSRF tokens" +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Server-to-server communication**: API endpoints designed for machine-to-machine communication" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Payment processors**: PayPal, Stripe, and other payment systems send webhook notifications" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Version control systems**: GitHub, GitLab webhooks for CI/CD pipelines" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Social media platforms**: Twitter, Facebook webhook notifications" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Communication services**: Slack, Discord bot integrations" +msgstr "" + +#. type: Title ## +#: ../src/cookbook/disabling-csrf-protection.md +#, no-wrap +msgid "How to disable CSRF protection" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 `CsrfMiddleware` middleware to the router configuration in `config/common/routes.php`. For a group that would be the following:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/cookbook/disabling-csrf-protection.md +msgid "For a single route, you can add the middleware directly to the route:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/cookbook/disabling-csrf-protection.md +msgid "When disabling CSRF protection, keep these security considerations in mind:" +msgstr "" + +#. type: Title ### +#: ../src/cookbook/disabling-csrf-protection.md +#, fuzzy, no-wrap +#| msgid "[Authentication](security/authentication.md)" +msgid "Alternative authentication methods" +msgstr "[Autenticazione](security/authentication.md)" + +#. type: Plain text +#: ../src/cookbook/disabling-csrf-protection.md +msgid "For API endpoints, implement proper authentication mechanisms:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**API keys**: Require API keys for authentication" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Bearer tokens**: Use JWT or similar token-based authentication" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**OAuth 2.0**: Implement OAuth 2.0 for third-party access" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**IP whitelisting**: Restrict access to known IP addresses for webhooks" +msgstr "" + +#. type: Title ### +#: ../src/cookbook/disabling-csrf-protection.md +#, no-wrap +msgid "Request validation" +msgstr "" + +#. type: Plain text +#: ../src/cookbook/disabling-csrf-protection.md +msgid "Implement additional validation for requests without CSRF protection:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Signature verification**: Verify webhook signatures (e.g., GitHub's X-Hub-Signature)" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Timestamp validation**: Check request timestamps to prevent replay attacks" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Rate limiting**: Implement rate limiting to prevent abuse" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Input validation**: Strictly validate all input parameters" +msgstr "" + +#. type: Title ### +#: ../src/cookbook/disabling-csrf-protection.md +#, no-wrap +msgid "Example: Webhook signature verification" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/cookbook/disabling-csrf-protection.md +#: ../src/cookbook/making-http-requests.md +#, no-wrap +msgid "Best practices" +msgstr "" + +#. type: Bullet: '1. ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Minimize exposure**: Only disable CSRF protection where absolutely necessary" +msgstr "" + +#. type: Bullet: '2. ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Use HTTPS**: Always use HTTPS for API endpoints and webhooks" +msgstr "" + +#. type: Bullet: '3. ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Monitor logs**: Log all requests to API endpoints for security monitoring" +msgstr "" + +#. type: Bullet: '4. ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Regular security audits**: Periodically review your API endpoints and their security measures" +msgstr "" + +#. type: Bullet: '5. ' +#: ../src/cookbook/disabling-csrf-protection.md +msgid "**Documentation**: Clearly document which endpoints have CSRF protection disabled and why" +msgstr "" + +#. type: Title ## +#: ../src/cookbook/disabling-csrf-protection.md +#, no-wrap +msgid "Conclusion" +msgstr "" + +#. 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 "" + +#. 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 "" diff --git a/_translations/po/it/cookbook_index.md.po b/_translations/po/it/cookbook_index.md.po new file mode 100644 index 00000000..8d9cbc68 --- /dev/null +++ b/_translations/po/it/cookbook_index.md.po @@ -0,0 +1,89 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/cookbook/index.md +#, no-wrap +msgid "Yii3 community cookbook" +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "The Yii community creates the cookbook." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "Yii core team members curate and edit it." +msgstr "" + +#. type: Plain text +#: ../src/cookbook/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 "" + +#. type: Plain text +#: ../src/cookbook/index.md +#, fuzzy +#| msgid "We release this guide under the [Terms of Yii Documentation](https://www.yiiframework.com/license#docs)." +msgid "This book conforms to the [Terms of Yii Documentation](https://www.yiiframework.com/license#docs)." +msgstr "Pubblichiamo questa guida secondo i [Termini della documentazione Yii](https://www.yiiframework.com/license#docs)." + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +#, fuzzy +#| msgid "[Packages](structure/package.md)" +msgid "[Preface](preface.md)" +msgstr "[Pacchetti](structure/package.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 "" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "[Making HTTP requests](making-http-requests.md)" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "[Disabling CSRF protection](disabling-csrf-protection.md)" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +#, fuzzy +#| msgid "[Authentication](security/authentication.md)" +msgid "[Sentry integration](sentry-integration.md)" +msgstr "[Autenticazione](security/authentication.md)" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "[Configuring webservers](configuring-webservers/general.md)" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/cookbook/index.md +msgid "[Deploying to Docker Swarm](deployment/docker-swarm.md)" +msgstr "" diff --git a/_translations/po/it/cookbook_making-http-requests.md.po b/_translations/po/it/cookbook_making-http-requests.md.po new file mode 100644 index 00000000..2961cd72 --- /dev/null +++ b/_translations/po/it/cookbook_making-http-requests.md.po @@ -0,0 +1,543 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title ## +#: ../src/en/cookbook/disabling-csrf-protection.md +#: ../src/en/cookbook/making-http-requests.md +#, no-wrap +msgid "Best practices" +msgstr "" + +#. type: Title # +#: ../src/en/cookbook/making-http-requests.md +#, fuzzy, no-wrap +#| msgid "Handling requests" +msgid "Making HTTP requests" +msgstr "Gestione delle richieste" + +#. type: Plain text +#: ../src/en/cookbook/making-http-requests.md +msgid "When building modern applications, you often need to make HTTP requests to external APIs. This article demonstrates how to make HTTP requests in Yii3 applications using Guzzle with and [PSR interfaces](https://www.php-fig.org/psr/)." +msgstr "" + +#. type: Title ## +#: ../src/en/cookbook/making-http-requests.md +#, no-wrap +msgid "What are PSR interfaces for HTTP" +msgstr "" + +#. type: Plain text +#: ../src/en/cookbook/making-http-requests.md +msgid "The PHP-FIG (PHP Framework Interoperability Group) has defined several PSR standards for HTTP handling:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/cookbook/making-http-requests.md +msgid "**PSR-7**: HTTP message interfaces for requests and responses" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/cookbook/making-http-requests.md +msgid "**PSR-17**: HTTP factory interfaces for creating PSR-7 message objects" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/cookbook/making-http-requests.md +msgid "**PSR-18**: HTTP client interface for sending PSR-7 requests and returning PSR-7 responses" +msgstr "" + +#. type: Plain text +#: ../src/en/cookbook/making-http-requests.md +msgid "Using these interfaces ensures your code is framework-agnostic and follows established PHP standards." +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/en/cookbook/making-http-requests.md +msgid "Install the Guzzle HTTP client with PSR-18 support and PSR-17 factories:" +msgstr "" + +#. type: Fenced code block (shell) +#: ../src/en/cookbook/making-http-requests.md +#, no-wrap +msgid "" +"composer require guzzlehttp/guzzle\n" +"composer require guzzlehttp/psr7\n" +msgstr "" + +#. type: Title ## +#: ../src/en/cookbook/making-http-requests.md +#, no-wrap +msgid "Basic usage" +msgstr "" + +#. type: Title ### +#: ../src/en/cookbook/making-http-requests.md +#, no-wrap +msgid "Simple GET request" +msgstr "" + +#. type: Plain text +#: ../src/en/cookbook/making-http-requests.md +msgid "Here's how to make a basic GET request using PSR-18 interfaces:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/en/cookbook/making-http-requests.md +#, no-wrap +msgid "" +"requestFactory->createRequest(\n" +" 'GET',\n" +" \"https://example.com/users/{$userId}\"\n" +" );\n" +"\n" +" return $this->httpClient->sendRequest($request);\n" +" }\n" +"}\n" +msgstr "" + +#. type: Title ### +#: ../src/en/cookbook/making-http-requests.md +#, no-wrap +msgid "POST request with JSON data" +msgstr "" + +#. type: Plain text +#: ../src/en/cookbook/making-http-requests.md +msgid "Here's an example of making a POST request with JSON payload:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/en/cookbook/making-http-requests.md +#, no-wrap +msgid "" +"streamFactory->createStream($jsonData);\n" +"\n" +" $request = $this->requestFactory->createRequest('POST', 'https://example.com/users')\n" +" ->withHeader('Content-Type', 'application/json')\n" +" ->withHeader('Accept', 'application/json')\n" +" ->withBody($stream);\n" +"\n" +" return $this->httpClient->sendRequest($request);\n" +" }\n" +"}\n" +msgstr "" + +#. type: Title ## +#: ../src/en/cookbook/making-http-requests.md +#, no-wrap +msgid "Configuration in Yii3" +msgstr "" + +#. type: Title ### +#: ../src/en/cookbook/making-http-requests.md +#: ../src/en/guide/concept/configuration.md +#, fuzzy, no-wrap +msgid "Container configuration" +msgstr "[Configurazione](concept/configuration.md)" + +#. type: Plain text +#: ../src/en/cookbook/making-http-requests.md +msgid "Configure the HTTP client and PSR factories in your DI container:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/en/cookbook/making-http-requests.md +#, no-wrap +msgid "" +" [\n" +" 'class' => Client::class,\n" +" '__construct()' => [\n" +" 'config' => [\n" +" 'timeout' => 30,\n" +" 'connect_timeout' => 10,\n" +" ],\n" +" ],\n" +" ],\n" +" \n" +" // Configure PSR-17 factories - these will depend on your chosen PSR-7 implementation\n" +" RequestFactoryInterface::class => static function (): RequestFactoryInterface {\n" +" return new \\GuzzleHttp\\Psr7\\HttpFactory();\n" +" },\n" +" ResponseFactoryInterface::class => static function (): ResponseFactoryInterface {\n" +" return new \\GuzzleHttp\\Psr7\\HttpFactory();\n" +" },\n" +" StreamFactoryInterface::class => static function (): StreamFactoryInterface {\n" +" return new \\GuzzleHttp\\Psr7\\HttpFactory();\n" +" },\n" +" UriFactoryInterface::class => static function (): UriFactoryInterface {\n" +" return new \\GuzzleHttp\\Psr7\\HttpFactory();\n" +" },\n" +"];\n" +msgstr "" + +#. type: Title ### +#: ../src/en/cookbook/making-http-requests.md +#, no-wrap +msgid "Service with error handling" +msgstr "" + +#. type: Plain text +#: ../src/en/cookbook/making-http-requests.md +msgid "Here's a more robust service example with proper error handling:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/en/cookbook/making-http-requests.md +#, no-wrap +msgid "" +"requestFactory->createRequest(\n" +" 'GET',\n" +" \"https://api.openweathermap.org/data/2.5/weather?q={$city}&appid={$this->apiKey}&units=metric\"\n" +" );\n" +"\n" +" $response = $this->httpClient->sendRequest($request);\n" +"\n" +" if ($response->getStatusCode() !== 200) {\n" +" $this->logger->warning('Weather API returned non-200 status', [\n" +" 'status_code' => $response->getStatusCode(),\n" +" 'city' => $city,\n" +" ]);\n" +" return null;\n" +" }\n" +"\n" +" $data = json_decode($response->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);\n" +" return $data;\n" +" } catch (ClientExceptionInterface $e) {\n" +" $this->logger->error('HTTP client error when fetching weather data', [\n" +" 'city' => $city,\n" +" 'error' => $e->getMessage(),\n" +" ]);\n" +" return null;\n" +" } catch (\\JsonException $e) {\n" +" $this->logger->error('Failed to decode weather API response', [\n" +" 'city' => $city,\n" +" 'error' => $e->getMessage(),\n" +" ]);\n" +" return null;\n" +" }\n" +" }\n" +"}\n" +msgstr "" + +#. type: Title ## +#: ../src/en/cookbook/making-http-requests.md +#, no-wrap +msgid "Advanced usage" +msgstr "" + +#. type: Title ### +#: ../src/en/cookbook/making-http-requests.md +#, no-wrap +msgid "Using middlewares" +msgstr "" + +#. type: Plain text +#: ../src/en/cookbook/making-http-requests.md +msgid "Guzzle supports middleware for cross-cutting concerns like authentication, logging, or retrying:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/en/cookbook/making-http-requests.md +#, no-wrap +msgid "" +"push(Middleware::log(\n" +" $this->logger,\n" +" new \\GuzzleHttp\\MessageFormatter('HTTP {method} {uri} - {code} {phrase}')\n" +" ));\n" +" \n" +" // Add retry middleware\n" +" $stack->push(Middleware::retry(\n" +" function (int $retries, RequestInterface $request) {\n" +" return $retries < 3;\n" +" }\n" +" ));\n" +"\n" +" return new Client([\n" +" 'handler' => $stack,\n" +" 'timeout' => 30,\n" +" ]);\n" +" }\n" +"}\n" +msgstr "" + +#. type: Title ### +#: ../src/en/cookbook/making-http-requests.md +#, fuzzy, no-wrap +#| msgid "Handling requests" +msgid "Async requests" +msgstr "Gestione delle richieste" + +#. type: Plain text +#: ../src/en/cookbook/making-http-requests.md +msgid "For better performance when making multiple requests, you can use asynchronous requests:" +msgstr "" + +#. type: Plain text +#: ../src/en/cookbook/making-http-requests.md +#, no-wrap +msgid "> **Note**: Async functionality is not part of PSR interfaces, so this code depends on Guzzle explicitly.\n" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/en/cookbook/making-http-requests.md +#, no-wrap +msgid "" +" $userIds\n" +" * @return array\n" +" */\n" +" public function fetchMultipleUsers(array $userIds): array\n" +" {\n" +" $promises = [];\n" +" \n" +" foreach ($userIds as $userId) {\n" +" $promises[$userId] = $this->httpClient->getAsync(\n" +" \"https://example.com/users/{$userId}\"\n" +" );\n" +" }\n" +"\n" +" // Wait for all requests to complete\n" +" $responses = \\GuzzleHttp\\Promise\\settle($promises)->wait();\n" +" \n" +" $results = [];\n" +" foreach ($responses as $userId => $response) {\n" +" if ($response['state'] === PromiseInterface::FULFILLED) {\n" +" $results[$userId] = $response['value'];\n" +" }\n" +" }\n" +" \n" +" return $results;\n" +" }\n" +"}\n" +msgstr "" + +#. type: Title ## +#: ../src/en/cookbook/making-http-requests.md +#, no-wrap +msgid "Testing HTTP clients" +msgstr "" + +#. type: Plain text +#: ../src/en/cookbook/making-http-requests.md +msgid "When testing services that make HTTP requests, you can use Guzzle's MockHandler:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/en/cookbook/making-http-requests.md +#, no-wrap +msgid "" +" 'London',\n" +" 'main' => ['temp' => 20.5],\n" +" ])),\n" +" ]);\n" +"\n" +" $handlerStack = HandlerStack::create($mockHandler);\n" +" $client = new Client(['handler' => $handlerStack]);\n" +" \n" +" $service = new WeatherService(\n" +" $client,\n" +" new \\GuzzleHttp\\Psr7\\HttpFactory(),\n" +" new \\GuzzleHttp\\Psr7\\HttpFactory(),\n" +" $this->createMock(\\Psr\\Log\\LoggerInterface::class),\n" +" 'test-api-key'\n" +" );\n" +"\n" +" $result = $service->getCurrentWeather('London');\n" +" \n" +" $this->assertNotNull($result);\n" +" $this->assertSame('London', $result['name']);\n" +" $this->assertSame(20.5, $result['main']['temp']);\n" +" }\n" +"}\n" +msgstr "" + +#. type: Bullet: '1. ' +#: ../src/en/cookbook/making-http-requests.md +msgid "**Use PSR interfaces**: Always type-hint against PSR interfaces rather than concrete implementations for better testability and flexibility." +msgstr "" + +#. type: Bullet: '2. ' +#: ../src/en/cookbook/making-http-requests.md +msgid "**Handle errors gracefully**: Always wrap HTTP requests in try-catch blocks and handle network failures appropriately." +msgstr "" + +#. type: Bullet: '3. ' +#: ../src/en/cookbook/making-http-requests.md +msgid "**Configure timeouts**: Set reasonable connection and request timeouts to prevent hanging requests." +msgstr "" + +#. type: Bullet: '4. ' +#: ../src/en/cookbook/making-http-requests.md +msgid "**Log requests**: Use middleware or manual logging to track API calls for debugging and monitoring." +msgstr "" + +#. type: Bullet: '5. ' +#: ../src/en/cookbook/making-http-requests.md +msgid "**Use dependency injection**: Inject HTTP clients and factories through your DI container rather than creating them directly." +msgstr "" + +#. type: Bullet: '6. ' +#: ../src/en/cookbook/making-http-requests.md +msgid "**Mock in tests**: Use Guzzle's MockHandler or similar tools to test your HTTP client code without making real network requests." +msgstr "" + +#. type: Plain text +#: ../src/en/cookbook/making-http-requests.md +msgid "By following these patterns and using PSR interfaces, you'll create maintainable, testable, and interoperable HTTP client code in your Yii3 applications." +msgstr "" diff --git a/_translations/po/it/cookbook_organizing-code_structuring-by-use-case-with-vertical-slices.md.po b/_translations/po/it/cookbook_organizing-code_structuring-by-use-case-with-vertical-slices.md.po new file mode 100644 index 00000000..115ca4de --- /dev/null +++ b/_translations/po/it/cookbook_organizing-code_structuring-by-use-case-with-vertical-slices.md.po @@ -0,0 +1,121 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md +#, fuzzy +#| msgid "[Application structure overview](structure/overview.md)" +msgid "[Application structure overview](../../guide/structure/overview.md)" +msgstr "[Panoramica della struttura applicativa](structure/overview.md)" diff --git a/_translations/po/it/cookbook_preface.md.po b/_translations/po/it/cookbook_preface.md.po new file mode 100644 index 00000000..21e6e434 --- /dev/null +++ b/_translations/po/it/cookbook_preface.md.po @@ -0,0 +1,81 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title ## +#: ../src/en/cookbook/deployment/docker-swarm.md ../src/en/cookbook/preface.md +#, no-wrap +msgid "Prerequisites" +msgstr "" + +#. type: Title # +#: ../src/en/cookbook/preface.md +#, no-wrap +msgid "Preface" +msgstr "" + +#. 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 "Yii è un framework PHP ad alte prestazioni basato su pacchetti per lo sviluppo di applicazioni moderne. Il nome Yii (pronunciato “Yee” o “[ji:]”) significa “semplice ed evolutivo” in cinese. Si può anche considerare come l'acronimo di **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 "Yii è un framework generico per la programmazione web. È possibile utilizzarlo per sviluppare tutti i tipi di applicazioni web utilizzando PHP. Grazie alla sua architettura e al sofisticato supporto della cache, è particolarmente adatto allo sviluppo di applicazioni su larga scala come portali, sistemi di gestione dei contenuti, e-commerce, API REST, ecc." + +#. 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 "" + +#. type: Title ## +#: ../src/en/cookbook/preface.md +#, no-wrap +msgid "What's the book about" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/en/cookbook/preface.md +msgid "You should have Yii3 installed." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/cookbook/preface.md +msgid "You should be familiar with the framework basics and the official guide." +msgstr "" + +#. type: Title ## +#: ../src/en/cookbook/preface.md +#, no-wrap +msgid "How to participate" +msgstr "" + +#. 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 "" diff --git a/_translations/po/it/cookbook_sentry-integration.md.po b/_translations/po/it/cookbook_sentry-integration.md.po new file mode 100644 index 00000000..e15a3487 --- /dev/null +++ b/_translations/po/it/cookbook_sentry-integration.md.po @@ -0,0 +1,252 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\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 "" + +#. type: Title # +#: ../src/en/cookbook/sentry-integration.md +#, no-wrap +msgid "Sentry integration" +msgstr "" + +#. type: Title ## +#: ../src/en/cookbook/sentry-integration.md +#, no-wrap +msgid "What is Sentry" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/en/cookbook/sentry-integration.md +#, no-wrap +msgid "Install the package" +msgstr "" + +#. type: Plain text +#: ../src/en/cookbook/sentry-integration.md +msgid "Install the required package `yiisoft/yii-sentry` with the following command:" +msgstr "" + +#. type: Fenced code block (shell) +#: ../src/en/cookbook/sentry-integration.md +#, no-wrap +msgid "composer require yiisoft/yii-sentry --prefer-dist\n" +msgstr "" + +#. type: Title ### +#: ../src/en/cookbook/sentry-integration.md +#, no-wrap +msgid "Install an HTTP driver" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/en/cookbook/sentry-integration.md +msgid "To install the packages, run the following command:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/en/cookbook/sentry-integration.md +#, no-wrap +msgid "Get and store the token" +msgstr "" + +#. type: Plain text +#: ../src/en/cookbook/sentry-integration.md +msgid "Next, configure the application." +msgstr "" + +#. type: Plain text +#: ../src/en/cookbook/sentry-integration.md +msgid "First, register at [Sentry](https://sentry.io) and create a project." +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/en/cookbook/sentry-integration.md +#, no-wrap +msgid "Configure the HTTP client" +msgstr "" + +#. type: Plain text +#: ../src/en/cookbook/sentry-integration.md +msgid "After installing the HTTP client, configure it." +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title # +#: ../src/en/cookbook/sentry-integration.md +#, fuzzy, no-wrap +#| msgid "Introduction" +msgid "Integration" +msgstr "Introduzione" + +#. type: Title ### +#: ../src/en/cookbook/sentry-integration.md +#, no-wrap +msgid "Web" +msgstr "" + +#. type: Plain text +#: ../src/en/cookbook/sentry-integration.md +msgid "Sentry support for `web` is implemented as middleware." +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/en/cookbook/sentry-integration.md ../src/en/internals/003-roadmap.md +#, no-wrap +msgid "Console" +msgstr "" + +#. 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 "" + +#. 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 "" diff --git a/_translations/po/it/guide_caching_data.md.po b/_translations/po/it/guide_caching_data.md.po new file mode 100644 index 00000000..5bfc2e6d --- /dev/null +++ b/_translations/po/it/guide_caching_data.md.po @@ -0,0 +1,337 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../../guide/en/caching/data.md +#, fuzzy, no-wrap +#| msgid "Caching" +msgid "Data caching" +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)." +msgstr "" + +#. type: Plain text +#: ../../guide/en/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 +#, no-wrap +msgid "composer require yiisoft/cache\n" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../../guide/en/caching/data.md +#, no-wrap +msgid "Cache handlers" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "Yii provides the following handlers:" +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../../guide/en/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 +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 "" + +#. type: Bullet: '- ' +#: ../../guide/en/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 +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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../../guide/en/caching/data.md +#, no-wrap +msgid "Cache keys" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../../guide/en/caching/data.md +#, no-wrap +msgid "Cache expiration" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "You may set the default TTL for the cache:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "Additionally, you can invalidate a cache key explicitly:" +msgstr "" + +#. type: Fenced code block (php) +#: ../../guide/en/caching/data.md +#, no-wrap +msgid "$cache->remove($key);\n" +msgstr "" + +#. type: Title ### +#: ../../guide/en/caching/data.md +#, no-wrap +msgid "Invalidation dependencies" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "Below is a summary of the available cache dependencies:" +msgstr "" + +#. type: Bullet: '- ' +#: ../../guide/en/caching/data.md +msgid "`\\Yiisoft\\Cache\\Dependency\\ValueDependency`: invalidates the cache when specified value changes." +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../../guide/en/caching/data.md +msgid "To implement your own dependency, extend from `\\Yiisoft\\Cache\\Dependency\\Dependency`." +msgstr "" + +#. type: Title ### +#: ../../guide/en/caching/data.md +#, no-wrap +msgid "Cache stampede prevention" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" diff --git a/_translations/po/it/guide_caching_overview.md.po b/_translations/po/it/guide_caching_overview.md.po new file mode 100644 index 00000000..8c57a7c8 --- /dev/null +++ b/_translations/po/it/guide_caching_overview.md.po @@ -0,0 +1,66 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title ## +#: ../src/guide/caching/overview.md ../src/guide/index.md +#, no-wrap +msgid "Caching" +msgstr "Caching" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/caching/overview.md +msgid "Yii supports all these caching mechanisms:" +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/caching/overview.md +#, fuzzy +#| msgid "[Data caching](caching/data.md)" +msgid "[Data caching](data.md)" +msgstr "[Caching dei dati](caching/data.md)" + +#. type: Bullet: '* ' +#: ../src/guide/caching/overview.md +#, fuzzy +#| msgid "[Fragment caching](caching/fragment.md) TODO" +msgid "[Fragment caching](fragment.md)" +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)" +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)" +msgstr "[Caching HTTP](caching/http.md) TODO" diff --git a/_translations/po/it/guide_concept_aliases.md.po b/_translations/po/it/guide_concept_aliases.md.po new file mode 100644 index 00000000..232c2c9b --- /dev/null +++ b/_translations/po/it/guide_concept_aliases.md.po @@ -0,0 +1,275 @@ +# Italian 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: 2025-09-03 17:50+0500\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/guide/concept/aliases.md +#, no-wrap +msgid "Aliases" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/concept/aliases.md +#, no-wrap +msgid "Defining aliases " +msgstr "" + +#. type: Plain text +#: ../src/guide/concept/aliases.md +msgid "You can define an alias via application's `config/params.php`:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/concept/aliases.md +msgid "You can define an alias using another alias (either root or derived):" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/concept/aliases.md +#, no-wrap +msgid "'@foobar' => '@foo/bar', \n" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/concept/aliases.md +#, no-wrap +msgid "Using aliases in configuration " +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/concept/aliases.md +#, no-wrap +msgid "Resolving aliases " +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/concept/aliases.md +#, no-wrap +msgid "Predefined aliases " +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/guide/concept/aliases.md +msgid "`@root` - the base directory of the currently running application." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/concept/aliases.md +msgid "`@assets` - application's public directory where it publishes assets." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/concept/aliases.md +msgid "`@assetsUrl` - URL of base directory with published assets." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/concept/aliases.md +msgid "`@baseUrl` - the base URL of the currently running Web application. Defaults to `/`." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/concept/aliases.md +msgid "`@npm` - node packages directory." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/concept/aliases.md +msgid "`@bower` - bower packages directory." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/concept/aliases.md +msgid "`@vendor` - Composer's `vendor` directory." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/concept/aliases.md +msgid "`@public` - application's publicly accessible directory that with `index.php`." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/concept/aliases.md +msgid "`@runtime` - the runtime path of the currently running application. Defaults to `@root/runtime`." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/concept/aliases.md +msgid "`@layout` - the directory with layouts." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/concept/aliases.md +msgid "`@resources` - directory with views, asset sources and other resources." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/concept/aliases.md +msgid "`@views` - application view templates base directory." +msgstr "" diff --git a/_translations/po/it/guide_concept_autoloading.md.po b/_translations/po/it/guide_concept_autoloading.md.po new file mode 100644 index 00000000..caeab773 --- /dev/null +++ b/_translations/po/it/guide_concept_autoloading.md.po @@ -0,0 +1,78 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\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 "" + +#. type: Title # +#: ../src/en/guide/concept/autoloading.md +#, no-wrap +msgid "Class autoloading" +msgstr "" + +#. type: Plain text +#: ../src/en/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 "" + +#. type: Plain text +#: ../src/en/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 "" + +#. type: Fenced code block (json) +#: ../src/en/guide/concept/autoloading.md +#, no-wrap +msgid "" +"{\n" +" \"autoload\": {\n" +" \"psr-4\": {\n" +" \"App\\\\\": \"src/\"\n" +" }\n" +" }\n" +"}\n" +msgstr "" + +#. type: Plain text +#: ../src/en/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 "" + +#. type: Plain text +#: ../src/en/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 "" + +#. type: Bullet: '- ' +#: ../src/en/guide/concept/autoloading.md +msgid "[PSR-4: Autoloader](https://www.php-fig.org/psr/psr-4/)." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/guide/concept/autoloading.md +msgid "[Composer guide on autoloading](https://getcomposer.org/doc/01-basic-usage.md#autoloading)." +msgstr "" diff --git a/_translations/po/it/guide_concept_configuration.md.po b/_translations/po/it/guide_concept_configuration.md.po new file mode 100644 index 00000000..401ced7e --- /dev/null +++ b/_translations/po/it/guide_concept_configuration.md.po @@ -0,0 +1,512 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title ### +#: ../src/en/cookbook/making-http-requests.md +#: ../src/en/guide/concept/configuration.md +#, fuzzy, no-wrap +msgid "Container configuration" +msgstr "[Configurazione](concept/configuration.md)" + +#. 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 "" + +#. type: Plain text +#: ../src/en/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 "" + +#. type: Plain text +#: ../src/en/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/`." +msgstr "" + +#. type: Title ## +#: ../src/en/guide/concept/configuration.md +#, no-wrap +msgid "Config plugin" +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/configuration.md +msgid "In the application template [yiisoft/config](https://github.com/yiisoft/config) is used. Since writing all application configurations from scratch is a tedious process, many packages offer default configs, and the plugin helps with copying these into the application." +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/configuration.md +msgid "To offer default configs, `composer.json` of the package has to have `config-plugin` section. When installing or updating packages with Composer, the plugin reads `config-plugin` sections for each dependency, copies files themselves to application `config/packages/` if they don't yet exist and writes a merge plan to `config/packages/merge_plan.php`. The merge plan defines how to merge the configs into a single big array ready to be passed to [DI container](di-container.md)." +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/configuration.md +msgid "Take a look at what's in the \"yiisoft/app\" `composer.json` by default:" +msgstr "" + +#. type: Fenced code block (json) +#: ../src/en/guide/concept/configuration.md +#, no-wrap +msgid "" +"\"config-plugin-options\": {\n" +" \"output-directory\": \"config/packages\"\n" +"},\n" +"\"config-plugin\": {\n" +" \"common\": \"config/common/*.php\",\n" +" \"params\": [\n" +" \"config/params.php\",\n" +" \"?config/params-local.php\"\n" +" ],\n" +" \"web\": [\n" +" \"$common\",\n" +" \"config/web/*.php\"\n" +" ],\n" +" \"console\": [\n" +" \"$common\",\n" +" \"config/console/*.php\"\n" +" ],\n" +" \"events\": \"config/events.php\",\n" +" \"events-web\": [\n" +" \"$events\",\n" +" \"config/events-web.php\"\n" +" ],\n" +" \"events-console\": [\n" +" \"$events\",\n" +" \"config/events-console.php\"\n" +" ],\n" +" \"providers\": \"config/providers.php\",\n" +" \"providers-web\": [\n" +" \"$providers\",\n" +" \"config/providers-web.php\"\n" +" ],\n" +" \"providers-console\": [\n" +" \"$providers\",\n" +" \"config/providers-console.php\"\n" +" ],\n" +" \"routes\": \"config/routes.php\"\n" +"},\n" +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/configuration.md +msgid "There are many named configs defined. For each name, there is a configuration." +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/configuration.md +msgid "A string means that the plugin takes config as is and merges it with same-named configs from packages you require. That happens if these packages have `config-plugin` in their `composer.json`." +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/configuration.md +msgid "The array means that the plugin will merge many files in the order they're specified." +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/configuration.md +msgid "`?` at the beginning of the file path indicated that the file may be absent. In this case, it's skipped." +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/configuration.md +msgid "`$` at the beginning of the name means a reference to another named config." +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/configuration.md +msgid "`params` is a bit special because it's reserved for application parameters. These are automatically available as `$params` in all other configuration files." +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/configuration.md +msgid "You can learn more about config plugin features [from its documentation](https://github.com/yiisoft/config/blob/master/README.md)." +msgstr "" + +#. type: Title ## +#: ../src/en/guide/concept/configuration.md +#, no-wrap +msgid "Config files" +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/configuration.md +msgid "Now, as you know how the plugin assembles configs, look at `config` directory:" +msgstr "" + +#. type: Fenced code block +#: ../src/en/guide/concept/configuration.md +#, no-wrap +msgid "" +"common/\n" +" application-parameters.php\n" +" i18n.php\n" +" router.php\n" +"console/\n" +"packages/\n" +" yiisoft/\n" +" dist.lock\n" +" merge_plan.php\n" +"web/\n" +" application.php\n" +" psr17.php\n" +"events.php\n" +"events-console.php\n" +"events-web.php\n" +"params.php\n" +"providers.php\n" +"providers-console.php\n" +"providers-web.php\n" +"routes.php\n" +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/configuration.md +msgid "The application consists of a set of services registered in a [dependency container](di-container.md). The config files that responsible for direct dependency container configuration are under `common/`, `console/` and `web/` directories. We use `web/` for config specific to web application and `console/` for config specific to console commands. Both web and console are sharing configuration under `common/`." +msgstr "" + +#. type: Fenced code block (php) +#: ../src/en/guide/concept/configuration.md +#, no-wrap +msgid "" +" [\n" +" 'class' => ApplicationParameters::class,\n" +" 'charset()' => [$params['app']['charset']],\n" +" 'name()' => [$params['app']['name']],\n" +" ],\n" +"];\n" +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/configuration.md +msgid "Config plugin passes special `$params` variable to all config files. The code passes its values to the service." +msgstr "" + +#. type: Plain text +#: ../src/en/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 "" + +#. type: Plain text +#: ../src/en/guide/concept/configuration.md +msgid "For convenience, there is a naming convention for custom string keys:" +msgstr "" + +#. type: Bullet: '1. ' +#: ../src/en/guide/concept/configuration.md +msgid "Prefix package name such as `yiisoft/cache-file/custom-definition`." +msgstr "" + +#. type: Bullet: '2. ' +#: ../src/en/guide/concept/configuration.md +msgid "In case configuration are for the application itself, skip package prefix, such as `custom-definition`." +msgstr "" + +#. type: Title ### +#: ../src/en/guide/concept/configuration.md +#, no-wrap +msgid "Service providers" +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/configuration.md +msgid "As an alternative to registering dependencies directly, you can use service providers. Basically, these are classes that given parameters are configuring and registering services within the container. Similar to three dependency configuration files described, there are three configs for specifying service providers: `providers-console.php` for console commands, `providers-web.php` for web application and `providers.php` for both:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/en/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' => [\n" +" 'class' => CacheProvider::class,\n" +" '__construct()' => [\n" +" $params['yiisoft/cache-file']['file-cache']['path'],\n" +" ],\n" +" ],\n" +" // ...\n" +msgstr "" + +#. type: Plain text +#: ../src/en/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. These classes could be either created in the project itself or provided by a package." +msgstr "" + +#. type: Plain text +#: ../src/en/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 "" + +#. type: Plain text +#: ../src/en/guide/concept/configuration.md +msgid "Provider should implement a single method, `public function register(Container $container): void`. In this method you need to add a service to container using `set()` method. Below is a provider for a cache service:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/en/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\\Container;\n" +"use Yiisoft\\Di\\Support\\ServiceProvider;\n" +"\n" +"final readonly class CacheProvider extends ServiceProvider\n" +"{\n" +" public function __construct(\n" +" private string $cachePath = '@runtime/cache'\n" +" )\n" +" {\n" +" $this->cachePath = $cachePath;\n" +" }\n" +"\n" +" public function register(Container $container): void\n" +" {\n" +" $container->set(CacheInterface::class, function (ContainerInterface $container) {\n" +" $aliases = $container->get(Aliases::class);\n" +"\n" +" return new FileCache($aliases->get($this->cachePath));\n" +" });\n" +"\n" +" $container->set(YiiCacheInterface::class, Cache::class);\n" +" }\n" +"}\n" +msgstr "" + +#. type: Title ### +#: ../src/en/guide/concept/configuration.md +#, no-wrap +msgid "Routes" +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/configuration.md +msgid "You can configure how web application responds to certain URLs in `config/routes.php`:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/en/guide/concept/configuration.md +#, no-wrap +msgid "" +"use App\\Controller\\SiteController;\n" +"use Yiisoft\\Router\\Route;\n" +"\n" +"return [\n" +" Route::get('/')->action([SiteController::class, 'index'])->name('site/index')\n" +"];\n" +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/configuration.md +msgid "Read more about it in [\"Routes\"](../runtime/routing.md)." +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/en/guide/concept/configuration.md +msgid "Many services emit certain events that you can attach to. You could do that via three config files: `events-web.php` for web application events, `events-console.php` for console events and `events.php` for both. The configuration is an array where keys are event names and values are an array of handlers:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/en/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 definition of an invokable class may be here while your `$container->has('the definition)` \n" +" 'di-alias'\n" +" ],\n" +"];\n" +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/configuration.md +msgid "Read more about it in [\"Events\"](events.md)." +msgstr "" + +#. type: Title ## +#: ../src/en/guide/concept/configuration.md +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Parameters" +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/configuration.md +msgid "Parameters, `config/params.php` store configuration values that are used in other config files to configuring services and service providers." +msgstr "" + +#. type: Plain text +#: ../src/en/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 "" + +#. type: Plain text +#: ../src/en/guide/concept/configuration.md +msgid "Default application `params.php` looks like the following:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/en/guide/concept/configuration.md +#, no-wrap +msgid "" +" [\n" +" 'charset' => 'UTF-8',\n" +" 'locale' => 'en',\n" +" 'name' => 'My Project',\n" +" ],\n" +"\n" +" 'yiisoft/aliases' => [\n" +" 'aliases' => [\n" +" '@root' => dirname(__DIR__),\n" +" '@assets' => '@root/public/assets',\n" +" '@assetsUrl' => '/assets',\n" +" '@baseUrl' => '/',\n" +" '@message' => '@root/resources/message',\n" +" '@npm' => '@root/node_modules',\n" +" '@public' => '@root/public',\n" +" '@resources' => '@root/resources',\n" +" '@runtime' => '@root/runtime',\n" +" '@vendor' => '@root/vendor',\n" +" '@layout' => '@resources/views/layout',\n" +" '@views' => '@resources/views',\n" +" ],\n" +" ],\n" +"\n" +" 'yiisoft/yii-view' => [\n" +" 'injections' => [\n" +" Reference::to(ContentViewInjection::class),\n" +" Reference::to(CsrfViewInjection::class),\n" +" Reference::to(LayoutViewInjection::class),\n" +" ],\n" +" ],\n" +"\n" +" 'yiisoft/yii-console' => [\n" +" 'commands' => [\n" +" 'hello' => Hello::class,\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/configuration.md +msgid "For convenience, there is a naming convention about parameters:" +msgstr "" + +#. type: Bullet: '1. ' +#: ../src/en/guide/concept/configuration.md +msgid "Group parameters package name such as `yiisoft/cache-file`." +msgstr "" + +#. type: Bullet: '2. ' +#: ../src/en/guide/concept/configuration.md +msgid "In case parameters are for the application itself, as in `app`, skip package prefix." +msgstr "" + +#. type: Bullet: '3. ' +#: ../src/en/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 "" + +#. type: Bullet: '4. ' +#: ../src/en/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 "" + +#. type: Title ### +#: ../src/en/guide/concept/configuration.md +#, no-wrap +msgid "Package configs" +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/configuration.md +msgid "Config plugin described copy default package configurations to `packages/` directory. Once copied you own the configs, so you can adjust these as you like. `yiisoft/` in the default template stands for package vendor. Since only `yiisoft` packages are in template, there's a single directory. `merge_plan.php` is used in runtime to get the order on how configs are merged. Note that for config keys there should be a single source of truth. One config can't override values of another config." +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/configuration.md +msgid "`dist.lock` is used by the plugin to keep track of changes and display diff between current config and example one." +msgstr "" diff --git a/_translations/po/it/guide_concept_di-container.md.po b/_translations/po/it/guide_concept_di-container.md.po new file mode 100644 index 00000000..bffe0cfd --- /dev/null +++ b/_translations/po/it/guide_concept_di-container.md.po @@ -0,0 +1,533 @@ +# Italian 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-16 11:13+0000\n" +"PO-Revision-Date: 2025-09-11 10:15+0500\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/guide/concept/di-container.md +#, fuzzy, no-wrap +#| msgid "[Dependency injection container](concept/di-container.md)" +msgid "Dependency injection and container" +msgstr "[Contenitore d’iniezione delle dipendenze](concept/di-container.md)" + +#. type: Title ## +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "Dependency injection " +msgstr "" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "There are two ways of re-using things in OOP: inheritance and composition." +msgstr "" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "Inheritance is simple:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "Another way to handle this is composition:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/guide/concept/di-container.md +msgid "Constructor injection. Best for mandatory dependencies." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/concept/di-container.md +msgid "Method injection. Best for optional dependencies." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/concept/di-container.md +msgid "Property injection. Better to be avoided in PHP except maybe data transfer objects." +msgstr "" + +#. type: Title ### +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "Why use private properties " +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "This design choice provides several benefits:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "DI container " +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/guide/concept/di-container.md +msgid "Define how to instantiate such common dependencies." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/concept/di-container.md +msgid "Instantiate them when required and only once per request." +msgstr "" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "That's what dependency containers are for." +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "Configuring container " +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "configuration could be:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "That's equal to the following:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "" +"$myService = new MyService(42);\n" +"$myService->setDiscount(10);\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "You can provide arguments with names as well:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "There are extra methods of declaring dependency configuration." +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "Here's how to do it for the example above:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "It's possible to use a static method call:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "MyServiceInterface::class => [MyFactory::class, 'create'],\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "Or an instance of an object:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "MyServiceInterface::class => new MyService(),\n" +msgstr "" + +#. type: Title ### +#: ../src/guide/concept/di-container.md +#, fuzzy, no-wrap +#| msgid "Creating a handler " +msgid "Injecting dependencies properly " +msgstr "Creare un gestore di richieste " + +#. 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 "" + +#. type: Plain text +#: ../src/guide/concept/di-container.md +msgid "This is primarily done in constructor and handing method of action handlers:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/concept/di-container.md +#, no-wrap +msgid "References " +msgstr "" + +#. 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 "" diff --git a/_translations/po/it/guide_concept_events.md.po b/_translations/po/it/guide_concept_events.md.po new file mode 100644 index 00000000..91bc147d --- /dev/null +++ b/_translations/po/it/guide_concept_events.md.po @@ -0,0 +1,255 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\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 "" + +#. type: Plain text +#: ../src/en/guide/concept/events.md +msgid "Events allow you to make custom code executed at certain execution points without modifying existing code. You can attach a custom code called \"handler\" to an event so that when the event is triggered, the handler gets executed automatically." +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/events.md +msgid "For example, when a user is signed up, you need to send a welcome email. You can do it right in the `SignupService` but then, when you additionally need to resize user's avatar image, you'll have to change `SignupService` code again. In other words, `SignupService` will be coupled to both code sending welcome email and code resizing avatar image." +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/events.md +#, no-wrap +msgid "" +"To avoid it, instead of telling what do after signup explicitly you can, instead, raise `UserSignedUp` event\n" +"and then finish a signup process. The code sending an email and the code resizing avatar image will attach to the event\n" +" and, therefore, will be executed. If you'll ever need to do more on signup, you'll be able to attach extra event\n" +"handlers without modifying `SignupService`. \n" +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/events.md +msgid "For raising events and attaching handlers to these events, Yii has a special service called event dispatcher. It's available from [yiisoft/event-dispatcher package](https://github.com/yiisoft/event-dispatcher)." +msgstr "" + +#. type: Title ## +#: ../src/en/guide/concept/events.md +#, no-wrap +msgid "Event Handlers " +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/events.md +msgid "An event handler is [PHP callable](https://www.php.net/manual/en/language.types.callable.php) that gets executed when the event it's attached to is triggered." +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/events.md +msgid "The signature of an event handler is:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/en/guide/concept/events.md +#, no-wrap +msgid "" +"function (EventClass $event) {\n" +" // handle it\n" +"}\n" +msgstr "" + +#. type: Title ## +#: ../src/en/guide/concept/events.md +#, no-wrap +msgid "Attaching event handlers " +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/events.md +msgid "You can attach a handler to an event like the following:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/en/guide/concept/events.md +#, no-wrap +msgid "" +"use Yiisoft\\EventDispatcher\\Provider\\Provider;\n" +"\n" +"final readonly class WelcomeEmailSender\n" +"{\n" +" public function __construct(Provider $provider)\n" +" {\n" +" $provider->attach([$this, 'handleUserSignup']);\n" +" }\n" +"\n" +" public function handleUserSignup(UserSignedUp $event)\n" +" {\n" +" // handle it \n" +" }\n" +"}\n" +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/events.md +msgid "The `attach()` method is accepting a callback. Based on the type of this callback argument, the event type is determined." +msgstr "" + +#. type: Title ## +#: ../src/en/guide/concept/events.md +#, no-wrap +msgid "Event handlers order" +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/events.md +msgid "You may attach one or more handlers to a single event. When an event is triggered, the attached handlers will be called in the order that they were attached to the event. In case an event implements `Psr\\EventDispatcher\\StoppableEventInterface`, event handler can stop executing the rest of the handlers that follow it if `isPropagationStopped()` returns `true`." +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/events.md +msgid "In general, it's better not to rely on the order of event handlers." +msgstr "" + +#. type: Title ## +#: ../src/en/guide/concept/events.md +#, no-wrap +msgid "Raising events " +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/events.md +msgid "Events are raised like the following:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/en/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" +" }\n" +"\n" +" public function signup(SignupForm $form)\n" +" {\n" +" // handle signup\n" +"\n" +" $event = new UserSignedUp($form);\n" +" $this->eventDispatcher->dispatch($event);\n" +" }\n" +"}\n" +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/events.md +msgid "First, you create an event supplying it with data that may be useful for handlers. Then you dispatch the event." +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/events.md +msgid "The event class itself may look like the following:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/en/guide/concept/events.md +#, no-wrap +msgid "" +"final readonly class UserSignedUp\n" +"{\n" +" public function __construct(\n" +" public SignupForm $form\n" +" )\n" +" {\n" +" }\n" +"}\n" +msgstr "" + +#. type: Title ## +#: ../src/en/guide/concept/events.md +#, no-wrap +msgid "Events hierarchy" +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/events.md +msgid "Events don't have any name or wildcard matching on purpose. Event class names and class/interface hierarchy and composition could be used to achieve great flexibility:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/en/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 "" + +#. type: Plain text +#: ../src/en/guide/concept/events.md +msgid "With the interface, you can listen to all document-related events:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/en/guide/concept/events.md +#, no-wrap +msgid "" +"$provider->attach(function (DocumentEvent $event) {\n" +" // log events here\n" +"});\n" +msgstr "" + +#. type: Title ## +#: ../src/en/guide/concept/events.md +#, no-wrap +msgid "Detaching event handlers " +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/events.md +msgid "To detach a handler from an event you can call `detach()` method:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/en/guide/concept/events.md +#, no-wrap +msgid "$provider->detach(DocmentEvent::class);\n" +msgstr "" + +#. type: Title ## +#: ../src/en/guide/concept/events.md +#, no-wrap +msgid "Configuring application events" +msgstr "" + +#. type: Plain text +#: ../src/en/guide/concept/events.md +msgid "You usually assign event handlers via application config. See [\"Configuration\"](configuration.md) for details." +msgstr "" diff --git a/_translations/po/it/guide_concept_immutability.md.po b/_translations/po/it/guide_concept_immutability.md.po new file mode 100644 index 00000000..1c95a74c --- /dev/null +++ b/_translations/po/it/guide_concept_immutability.md.po @@ -0,0 +1,225 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/en/guide/concept/immutability.md +#, no-wrap +msgid "Mutable pitfalls (what we avoid)" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/en/guide/concept/immutability.md +#, no-wrap +msgid "Creating an immutable object in PHP" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/en/guide/concept/immutability.md +msgid "We mark the class `final` to prevent subclass mutations; alternatively, design for extension carefully." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/guide/concept/immutability.md +msgid "Validate in the constructor and `with*` methods so every instance is always valid." +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/en/guide/concept/immutability.md +#, no-wrap +msgid "Using clone (and why it is inexpensive)" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/en/guide/concept/immutability.md +#, no-wrap +msgid "Usage style" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" diff --git a/_translations/po/it/guide_databases_db-migrations.md.po b/_translations/po/it/guide_databases_db-migrations.md.po new file mode 100644 index 00000000..096992ca --- /dev/null +++ b/_translations/po/it/guide_databases_db-migrations.md.po @@ -0,0 +1,899 @@ +# Italian 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 10:28+0000\n" +"PO-Revision-Date: 2025-12-27 10:28+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "Migrations" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '2. ' +#: ../src/guide/databases/db-migrations.md +msgid "Scott updates the source code on the production server to the release tag." +msgstr "" + +#. type: Bullet: '3. ' +#: ../src/guide/databases/db-migrations.md +msgid "Scott applies any accumulated database migrations to the production database." +msgstr "" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "Yii provides a set of migration command line tools that allow you to:" +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/databases/db-migrations.md +msgid "create new migrations;" +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/databases/db-migrations.md +msgid "apply migrations;" +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/databases/db-migrations.md +msgid "revert migrations;" +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/databases/db-migrations.md +msgid "re-apply migrations;" +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/databases/db-migrations.md +msgid "show migration history and status." +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "Initial configuration" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "Create a directory to store migrations `src/Migration` right in the project root." +msgstr "" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "Add the following configuration to `config/common/params.php`:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "Creating a migration" +msgstr "" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "To create a new empty migration, run the following command:" +msgstr "" + +#. type: Fenced code block (sh) +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "" +"make shell\n" +"./yii migrate:create \n" +msgstr "" + +#. 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 "" + +#. type: Fenced code block +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "" +"make shell\n" +"./yii migrate:create create_news_table\n" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "Methods available in migration builder belong to the following types:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "Raw queries" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "getDb — to get database connection instance." +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "execute — to execute raw SQL query." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "Data" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "insert / update / delete" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "batchInsert" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "upsert" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "Tables and views" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "createTable / renameTable / dropTable" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "truncateTable" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "addCommentOnTable / dropCommentFromTable" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "createView / dropView" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "Columns" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "addColumn / renameColumn / alterColumn / dropColumn" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "addCommentOnColumn / dropCommentFromColumn" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "Keys and indexes" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "addPrimaryKey / dropPrimaryKey" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "addForeignKey / dropForeignKey" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "createIndex / dropIndex" +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "Keys" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "primaryKey" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "smallPrimaryKey" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "bigPrimaryKey" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "uuidPrimaryKey" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "Boolean" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "boolean" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "Numbers" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "bit" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "tinyint" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "smallint" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "integer" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "bigint" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "flat" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "double" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "decimal" +msgstr "" + +#. type: Title ## +#: ../src/guide/databases/db-migrations.md ../src/internals/010-code-style.md +#, no-wrap +msgid "Strings" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "char" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "string" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "text" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "Date and time" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "timestamp" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "datetime" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "datetimeWithTimezone" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "time" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "timeWithTimezone" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "date" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +#, fuzzy +#| msgid "Special topics" +msgid "Special types" +msgstr "Argomenti speciali" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "money" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "binary" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "uuid" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "array" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "structured" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/databases/db-migrations.md +msgid "json" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "enum" +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "null / notNull" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "defaultValue" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "unique" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "scale / size / unsigned" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "primaryKey / autoIncrement" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "check" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "comment" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "computed" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +#, fuzzy +#| msgid "Extras" +msgid "extra" +msgstr "Extra" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "reference" +msgstr "" + +#. type: Title ### +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "Irreversible migrations" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "Transactional migrations" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/databases/db-migrations.md +#, fuzzy, no-wrap +#| msgid "Generating API documentation" +msgid "Generating a migration" +msgstr "Generazione della documentazione API" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "That would generate the following:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/databases/db-migrations.md +msgid "Commands available are:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "create - empty migration." +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "dropTable - dropping a table." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "addColumn - adding a column." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "dropColumn - dropping a column." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/databases/db-migrations.md +msgid "junction - creating a junction table. Use `--and` specify a second table." +msgstr "" + +#. type: Title ## +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "Applying Migrations" +msgstr "" + +#. 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 "" + +#. type: Fenced code block +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "./yii migrate:up\n" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Fenced code block +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "./yii migrate:up --limit=3\n" +msgstr "" + +#. type: Title ## +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "Reverting Migrations " +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "Redoing Migrations " +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "Listing Migrations " +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/databases/db-migrations.md +#, no-wrap +msgid "Upgrading from Yii 2.0" +msgstr "" + +#. 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 "" + +#. 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 "" diff --git a/_translations/po/it/guide_glossary.md.po b/_translations/po/it/guide_glossary.md.po new file mode 100644 index 00000000..29135fa7 --- /dev/null +++ b/_translations/po/it/guide_glossary.md.po @@ -0,0 +1,209 @@ +# Italian 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-10-22 11:35+0000\n" +"PO-Revision-Date: 2025-10-22 11:35+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../../guide/en/glossary.md +#, no-wrap +msgid "A" +msgstr "" + +#. type: Title ## +#: ../../guide/en/glossary.md +#, no-wrap +msgid "alias" +msgstr "" + +#. type: Plain text +#: ../../guide/en/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 "" + +#. type: Title ## +#: ../../guide/en/glossary.md +#, no-wrap +msgid "asset" +msgstr "" + +#. type: Plain text +#: ../../guide/en/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 "" + +#. type: Title # +#: ../../guide/en/glossary.md +#, no-wrap +msgid "C" +msgstr "" + +#. type: Title ## +#: ../../guide/en/glossary.md +#, no-wrap +msgid "configuration" +msgstr "" + +#. type: Plain text +#: ../../guide/en/glossary.md +msgid "The 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 "" + +#. type: Title # +#: ../../guide/en/glossary.md +#, no-wrap +msgid "D" +msgstr "" + +#. type: Title ## +#: ../../guide/en/glossary.md +#, no-wrap +msgid "DI" +msgstr "" + +#. type: Plain text +#: ../../guide/en/glossary.md +msgid "Dependency Injection is a programming technique where an object injects a dependent object. Read more in [\"Dependency injection and container\"](concept/di-container.md)." +msgstr "" + +#. type: Title # +#: ../../guide/en/glossary.md +#, no-wrap +msgid "I" +msgstr "" + +#. type: Title ## +#: ../../guide/en/glossary.md +#, no-wrap +msgid "installation" +msgstr "" + +#. type: Plain text +#: ../../guide/en/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 "" + +#. type: Title # +#: ../../guide/en/glossary.md +#, no-wrap +msgid "M" +msgstr "" + +#. type: Title ## +#: ../../guide/en/glossary.md +#, no-wrap +msgid "middleware" +msgstr "" + +#. type: Plain text +#: ../../guide/en/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 "" + +#. type: Title ## +#: ../../guide/en/glossary.md +#, no-wrap +msgid "module" +msgstr "" + +#. type: Plain text +#: ../../guide/en/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 "" + +#. type: Title # +#: ../../guide/en/glossary.md +#, no-wrap +msgid "N" +msgstr "" + +#. type: Title ## +#: ../../guide/en/glossary.md +#, no-wrap +msgid "namespace" +msgstr "" + +#. type: Plain text +#: ../../guide/en/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 "" + +#. type: Title # +#: ../../guide/en/glossary.md +#, no-wrap +msgid "P" +msgstr "" + +#. type: Title ## +#: ../../guide/en/glossary.md +#, no-wrap +msgid "package" +msgstr "" + +#. type: Plain text +#: ../../guide/en/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 package manager." +msgstr "" + +#. type: Title # +#: ../../guide/en/glossary.md +#, no-wrap +msgid "R" +msgstr "" + +#. type: Title ## +#: ../../guide/en/glossary.md +#, no-wrap +msgid "rule" +msgstr "" + +#. type: Plain text +#: ../../guide/en/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 "" + +#. type: Title # +#: ../../guide/en/glossary.md +#, no-wrap +msgid "Q" +msgstr "" + +#. type: Title ## +#: ../../guide/en/glossary.md +#, no-wrap +msgid "queue" +msgstr "" + +#. type: Plain text +#: ../../guide/en/glossary.md +msgid "A queue is similar to a stack. Queue follows First-In-First-Out methodology. Yii has a [yiisoft/queue](https://github.com/yiisoft/queue) package." +msgstr "" + +#. type: Title # +#: ../../guide/en/glossary.md +#, no-wrap +msgid "V" +msgstr "" + +#. type: Title ## +#: ../../guide/en/glossary.md +#, no-wrap +msgid "vendor" +msgstr "" + +#. type: Plain text +#: ../../guide/en/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 "" diff --git a/_translations/po/it/guide_index.md.po b/_translations/po/it/guide_index.md.po new file mode 100644 index 00000000..7de372ff --- /dev/null +++ b/_translations/po/it/guide_index.md.po @@ -0,0 +1,596 @@ +# SOME DESCRIPTIVE TITLE +# Copyright (C) YEAR Free Software Foundation, Inc. +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: 2025-12-27 03:24+0000\n" +"PO-Revision-Date: 2026-01-04 21:18+0100\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 3.8\n" + +#. type: Title ## +#: ../src/guide/caching/overview.md ../src/guide/index.md +#, no-wrap +msgid "Caching" +msgstr "Caching" + +#. type: Title # +#: ../src/guide/index.md +#, no-wrap +msgid "The definitive guide to Yii3" +msgstr "La guida definitiva a 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 "Pubblichiamo questa guida secondo i [Termini della documentazione Yii](https://www.yiiframework.com/license#docs)." + +#. type: Title ## +#: ../src/guide/index.md +#, no-wrap +msgid "Introduction" +msgstr "Introduzione" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[About Yii](intro/what-is-yii.md)" +msgstr "[Informazioni su Yii](intro/what-is-yii.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Upgrading from version 2.0](intro/upgrade-from-v2.md)" +msgstr "[Aggiornamento dalla versione 2.0](intro/upgrade-from-v2.md)" + +#. type: Title ## +#: ../src/guide/index.md +#, no-wrap +msgid "Getting started" +msgstr "Per iniziare" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[What do you need to know?](start/prerequisites.md)" +msgstr "[Cosa devi sapere?](start/prerequisites.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Creating a project](start/creating-project.md)" +msgstr "[Creazione di un progetto](start/creating-project.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Running applications](start/workflow.md)" +msgstr "[Applicazioni in esecuzione](start/workflow.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Saying hello](start/hello.md)" +msgstr "[Dire ciao](start/hello.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Working with forms](start/forms.md)" +msgstr "[Lavorare con i moduli](start/forms.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Working with databases](start/databases.md)" +msgstr "[Lavorare con i Database](start/databases.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Generating code with Gii](start/gii.md) TODO" +msgstr "[Generare codice con Gii](start/gii.md) TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Looking ahead](start/looking-ahead.md)" +msgstr "[Guardando avanti](start/looking-ahead.md)" + +#. type: Title ### +#: ../src/guide/index.md ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Application structure" +msgstr "Struttura applicativa" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Application structure overview](structure/overview.md)" +msgstr "[Panoramica della struttura applicativa](structure/overview.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Entry scripts](structure/entry-script.md)" +msgstr "[Script d’avvio](structure/entry-script.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Application](structure/application.md)" +msgstr "[Applicazione](structure/application.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Service components](structure/service.md)" +msgstr "[Componenti di servizio](structure/service.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Actions](structure/action.md)" +msgstr "[Azioni](structure/action.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Domain](structure/domain.md)" +msgstr "[Dominio](structure/domain.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Middleware](structure/middleware.md)" +msgstr "[Middleware](structure/middleware.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Packages](structure/package.md)" +msgstr "[Pacchetti](structure/package.md)" + +#. type: Title ## +#: ../src/guide/index.md +#, no-wrap +msgid "Key concepts" +msgstr "Concetti chiave" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Class autoloading](concept/autoloading.md)" +msgstr "[Caricamento automatico delle classi](concept/autoloading.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Dependency injection container](concept/di-container.md)" +msgstr "[Contenitore d’iniezione delle dipendenze](concept/di-container.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Configuration](concept/configuration.md)" +msgstr "[Configurazione](concept/configuration.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Aliases](concept/aliases.md)" +msgstr "[Alias](concept/aliases.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Events](concept/events.md)" +msgstr "[Eventi](concept/events.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Immutability](concept/immutability.md)" +msgstr "[Immutabilità](concept/immutability.md)" + +#. type: Title ## +#: ../src/guide/index.md +#, no-wrap +msgid "Handling requests" +msgstr "Gestione delle richieste" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Routing and URL generation](runtime/routing.md)" +msgstr "[Routing e generazione di URL](runtime/routing.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Request](runtime/request.md)" +msgstr "[Richiesta](runtime/request.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Response](runtime/response.md)" +msgstr "[Risposta](runtime/response.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Sessions](runtime/sessions.md)" +msgstr "[Sessioni](runtime/sessions.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Cookies](runtime/cookies.md)" +msgstr "[Cookie](runtime/cookies.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Handling errors](runtime/handling-errors.md)" +msgstr "[Gestione degli errori](runtime/handling-errors.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Logging](runtime/logging.md)" +msgstr "[Logging](runtime/logging.md)" + +#. type: Title # +#: ../src/guide/index.md ../src/guide/views/view.md +#, no-wrap +msgid "Views" +msgstr "Viste" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[View](views/view.md)" +msgstr "[Vista](views/view.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Template engines](views/template-engines.md) TODO: verify!" +msgstr "[Motori di template](views/template-engines.md) TODO: verificare!" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[View injections](views/view-injections.md)" +msgstr "[Iniezione di parametri nella vista](views/view-injections.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Scripts, styles and metatags](views/script-style-meta.md) TODO: verify!" +msgstr "[Script, stili e metatag](views/script-style-meta.md) Da fare: verificare!" + +#. 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 "[Widgets](views/widget.md) TODO: verify!" +msgstr "[Widget](views/widget.md) TODO: verify!" + +#. type: Title # +#: ../src/guide/index.md ../src/guide/start/databases.md +#, no-wrap +msgid "Working with databases" +msgstr "Lavorare con i database" + +#. 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 "[Migrazioni](databases/db-migrations.md) TODO: verify/update!" + +#. type: Title ## +#: ../src/guide/index.md +#, no-wrap +msgid "Getting data from users" +msgstr "Ottenere dati dagli utenti" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Creating forms](input/forms.md) TODO" +msgstr "[Creazione di moduli](input/forms.md) TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Validating input](https://github.com/yiisoft/validator/blob/master/docs/guide/en/README.md)" +msgstr "[Convalida degli input](https://github.com/yiisoft/validator/blob/master/docs/guide/en/README.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Uploading files](input/file-upload.md) TODO" +msgstr "[Caricamento dei file](input/file-upload.md) TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Collecting tabular input](input/tabular-input.md) TODO" +msgstr "[Raccolta di input tabulari](input/tabular-input.md) TODO" + +#. type: Title ## +#: ../src/guide/index.md +#, no-wrap +msgid "Displaying data" +msgstr "Visualizzazione dei dati" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Data formatting](output/formatting.md) TODO" +msgstr "[Formattazione dei dati](output/formatting.md) TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Pagination](output/pagination.md) TODO" +msgstr "[Paginazione](output/pagination.md) TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Sorting](output/sorting.md) TODO" +msgstr "[Ordinamento](output/sorting.md) TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Data providers](output/data-providers.md) TODO" +msgstr "[Fornitori di dati](output/data-providers.md) TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Data widgets](output/data-widgets.md) TODO" +msgstr "[Widget dati](output/data-widgets.md) TODO" + +#. type: Title # +#: ../src/guide/index.md ../src/guide/security/overview.md +#, no-wrap +msgid "Security" +msgstr "Sicurezza" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Security overview](security/overview.md)" +msgstr "[Panoramica sulla sicurezza](security/overview.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Authentication](security/authentication.md)" +msgstr "[Autenticazione](security/authentication.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Authorization](security/authorization.md) TODO: verify and complete!" +msgstr "[Verifica delle autorizzazioni](security/authorization.md) TODO: verify and complete!" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Working with passwords](security/passwords.md)" +msgstr "[Lavorare con le password](security/passwords.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Cryptography](security/cryptography.md)" +msgstr "[Crittografia](security/cryptography.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Best practices](security/best-practices.md)" +msgstr "[Migliori pratiche](security/best-practices.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Caching overview](caching/overview.md)" +msgstr "[Panoramica sulla cache](caching/overview.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Data caching](caching/data.md)" +msgstr "[Caching dei dati](caching/data.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Fragment caching](caching/fragment.md) TODO" +msgstr "[Caching dei frammenti](caching/fragment.md) TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Page caching](caching/page.md) TODO" +msgstr "[Caching delle pagine](caching/page.md) TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[HTTP caching](caching/http.md) TODO" +msgstr "[Caching HTTP](caching/http.md) TODO" + +#. type: Title ## +#: ../src/guide/index.md +#, no-wrap +msgid "REST APIs" +msgstr "API REST" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Quick start](rest/quick-start.md) TODO" +msgstr "[Introduzione rapida](rest/quick-start.md) TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Resources](rest/resources.md) TODO" +msgstr "[Risorse](rest/resources.md) Da fare" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Controllers](rest/controllers.md) TODO" +msgstr "[Controller](rest/controllers.md) TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Routing](rest/routing.md) TODO" +msgstr "[Routing](rest/routing.md) TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Authentication](rest/authentication.md) TODO" +msgstr "[Autenticazione](rest/authentication.md) TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Rate limiting](rest/rate-limiting.md) TODO" +msgstr "[Rate limiting](rest/rate-limiting.md) TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Versioning](rest/versioning.md) TODO" +msgstr "[Versionamento](rest/versioning.md) TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Error handling](rest/error-handling.md) TODO" +msgstr "[Gestione degli errori](rest/error-handling.md) TODO" + +#. type: Title ## +#: ../src/guide/index.md +#, no-wrap +msgid "Development tools" +msgstr "Strumenti di sviluppo" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "Debug toolbar and debugger" +msgstr "Barra degli strumenti di debug e debugger" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "Generating code using Gii" +msgstr "Generare codice utilizzando Gii" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "Generating API documentation" +msgstr "Generazione della documentazione API" + +#. type: Title ## +#: ../src/guide/index.md +#, no-wrap +msgid "Testing" +msgstr "Testing" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Testing overview](testing/overview.md) TODO" +msgstr "[Panoramica sul Testing](testing/overview.md) TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Testing environment setup](testing/environment-setup.md) TODO" +msgstr "[Configurazione dell'ambiente di test](testing/environment-setup.md) TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Unit tests](testing/unit.md) TODO" +msgstr "[Test unitari](testing/unit.md) TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Functional tests](testing/functional.md) TODO" +msgstr "[Test funzionali](testing/functional.md) TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Acceptance tests](testing/acceptance.md) TODO" +msgstr "[Test di accettazione](testing/acceptance.md) TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Fixtures](testing/fixtures.md) TODO" +msgstr "[Fixtures](testing/fixtures.md) TODO" + +#. type: Title ## +#: ../src/guide/index.md +#, no-wrap +msgid "Special topics" +msgstr "Argomenti speciali" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Console applications](tutorial/console-applications.md)" +msgstr "[Applicazioni console](tutorial/console-applications.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Internationalization](tutorial/i18n.md) TODO" +msgstr "[Internazionalizzazione](tutorial/i18n.md) TODO" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Mailing](tutorial/mailing.md)" +msgstr "[Mailing](tutorial/mailing.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Performance tuning](tutorial/performance-tuning.md)" +msgstr "[Ottimizzazione delle prestazioni](tutorial/performance-tuning.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Using Yii with event loop](tutorial/using-with-event-loop.md)" +msgstr "[Usare Yii con event loop](tutorial/using-with-event-loop.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Using Yii with RoadRunner](tutorial/using-yii-with-roadrunner.md)" +msgstr "[Usare Yii con 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 "[Usare Yii con Swoole](tutorial/using-yii-with-swoole.md)" + +#. type: Title ## +#: ../src/guide/index.md +#, no-wrap +msgid "Helpers" +msgstr "Helper" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Arrays](https://github.com/yiisoft/arrays/)" +msgstr "[Array](https://github.com/yiisoft/arrays/)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Files](https://github.com/yiisoft/files/)" +msgstr "[File](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à di rete](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 "[Stringhe](https://github.com/yiisoft/strings)" + +#. type: Title ## +#: ../src/guide/index.md +#, no-wrap +msgid "Extras" +msgstr "Extra" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Cookbook](../cookbook/index.md)" +msgstr "[Ricettario](../cookbook/index.md)" + +#. type: Bullet: '- ' +#: ../src/guide/index.md +msgid "[Glossary](glossary.md)" +msgstr "[Glossario](glossary.md)" diff --git a/_translations/po/it/guide_intro_upgrade-from-v2.md.po b/_translations/po/it/guide_intro_upgrade-from-v2.md.po new file mode 100644 index 00000000..b9b0dcbf --- /dev/null +++ b/_translations/po/it/guide_intro_upgrade-from-v2.md.po @@ -0,0 +1,287 @@ +# Italian 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: \n" +"POT-Creation-Date: 2026-01-14 10:30+0000\n" +"PO-Revision-Date: 2026-01-17 21:01+0100\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.8\n" + +#. type: Title ### +#: ../src/guide/index.md ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Application structure" +msgstr "Struttura applicativa" + +#. type: Title # +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Upgrading from Version 2.0" +msgstr "Aggiornamento dalla versione 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 non hai mai utilizzato Yii 2.0, puoi saltare questa sezione e passare direttamente alla sezione “[Per iniziare](../start/prerequisites.md)”.\n" +">\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "While sharing some common ideas and values, Yii3 is conceptually different from Yii 2.0. There is no easy upgrade path, so first [check maintenance policy and end-of-life dates for Yii 2.0](https://www.yiiframework.com/release-cycle) and consider starting new projects on Yii3 while keeping existing ones on Yii 2.0." +msgstr "Pur condividendo alcune idee e valori comuni, Yii3 è concettualmente diverso da Yii 2.0. Non esiste un percorso di aggiornamento semplice, quindi è opportuno innanzitutto [verificare la politica di manutenzione e le date di fine vita di Yii 2.0](https://www.yiiframework.com/release-cycle) e valutare la possibilità di avviare nuovi progetti su Yii3 mantenendo quelli esistenti su Yii 2.0." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "PHP requirements" +msgstr "Requisiti PHP" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Yii3 requires PHP 8.2 or above. As a result, there are language features used that weren't used in Yii 2.0:" +msgstr "Yii3 richiede PHP 8.2 o versioni successive. Di conseguenza, vengono utilizzate funzionalità del linguaggio che non erano presenti in 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 "[Dichiarazioni dei tipi](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 "[Dichiarazioni del tipo di ritorno](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 "[Visibilità delle costanti di 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 "[Argomenti denominati](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 "[Classi anonime](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 "[Generatori](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 "[Funzioni variadiche](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 "[Proprietà in sola lettura](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 "[Classi in sola lettura](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 "[Promozione delle proprietà del costruttore](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 "[Attributi](https://www.php.net/manual/en/language.attributes.php)" + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Preliminary refactoring" +msgstr "Rifattorizzazione preliminare" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "It's a good idea to refactor your Yii 2.0 project before porting it to Yii3. That would both make porting easier and benefit the project in question while it's not moved to Yii3 yet." +msgstr "È una buona idea rifattorizzare il tuo progetto Yii 2.0 prima di trasferirlo su Yii3. Ciò renderebbe più facile il trasferimento e apporterebbe benefici al progetto in questione mentre non è ancora stato trasferito su Yii3." + +#. type: Title ### +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Use DI instead of the service locator" +msgstr "Utilizza l’iniezione delle dipendenze (DI) invece del localizzatore di servizi (Service Locator)" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"Since Yii3 is forcing you to inject dependencies, it's a good idea to prepare and switch from using\n" +"service locator (`Yii::$app->`) to [DI container](https://www.yiiframework.com/doc/guide/2.0/en/concept-di-container).\n" +msgstr "" +"Poiché Yii3 ti obbliga a iniettare le dipendenze, è una buona idea prepararsi e passare dall'uso del\n" +"localizzatore di servizi (`Yii::$app->`) al [contenitore DI](https://www.yiiframework.com/doc/guide/2.0/en/concept-di-container).\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"If usage of DI container is problematic for whatever reason, consider moving all calls to `Yii::$app->` to controller\n" +"actions and widgets and passing dependencies manually from a controller to what needs them.\n" +msgstr "" +"Se l'utilizzo del contenitore DI è problematico per qualsiasi motivo, valuta la possibilità di spostare tutte le chiamate a `Yii::$app->` alle azioni del controller\n" +"e ai widget e di passare manualmente le dipendenze da un controller a ciò che ne ha bisogno.\n" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "See [Dependency injection and container](../concept/di-container.md) for an explanation of the idea." +msgstr "Per una spiegazione dell'idea, consultare [Iniezione di dipendenze e contenitore](../concept/di-container.md)." + +#. type: Title ### +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Introduce repositories for getting data" +msgstr "Introdurre repository per ottenere dati" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Since Active Record isn't the only way to work with a database in Yii3, consider introducing repositories that would hide details of getting data and gather them in a single place. You can later redo it:" +msgstr "Poiché Active Record non è l'unico modo per lavorare con un database in Yii3, prendete in considerazione l'introduzione di repository che nascondano i dettagli relativi all'ottenimento dei dati e li raccolgano in un unico posto. Potrete rifarlo in un secondo momento:" + +#. type: Fenced code block (php) +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "" +"final readonly class PostRepository\n" +"{\n" +" public function getArchive()\n" +" {\n" +" // ...\n" +" }\n" +" \n" +" public function getTop10ForFrontPage()\n" +" {\n" +" // ...\n" +" }\n" +"\n" +"}\n" +msgstr "" +"final readonly class PostRepository\n" +"{\n" +" public function getArchive()\n" +" {\n" +" // ...\n" +" }\n" +" \n" +" public function getTop10ForFrontPage()\n" +" {\n" +" // ...\n" +" }\n" +"\n" +"}\n" + +#. type: Title ### +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Separate domain layer from infrastructure" +msgstr "Separare il livello di dominio dall'infrastruttura" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "In case you have a rich complicated domain, it's a good idea to separate it from infrastructure provided by a framework that's all the business logic has to go to framework-independent classes." +msgstr "Nel caso in cui si disponga di un dominio ricco e complesso, è consigliabile separarlo dall'infrastruttura fornita da un framework, in modo che tutta la logica di business risieda in classi indipendenti dal framework." + +#. type: Title ### +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Move more into components" +msgstr "Suddividi di più in componenti" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Yii3 services are conceptually similar to Yii 2.0 components, so it's a good idea to move reusable parts of your application into components." +msgstr "I servizi Yii3 sono concettualmente simili ai componenti di Yii 2.0, quindi è consigliabile spostare le parti riutilizzabili dell'applicazione nei componenti." + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Things to learn" +msgstr "Cose da imparare" + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v2.md ../src/guide/start/prerequisites.md +#, no-wrap +msgid "Docker" +msgstr "Docker" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Default application templates are using [Docker](https://www.docker.com/get-started/) to run application. It's a good idea to learn how to use it and use it for your own projects since it provides a lot of benefits:" +msgstr "I modelli d’applicazione predefiniti utilizzano [Docker](https://www.docker.com/get-started/) per eseguire l'applicazione. È consigliabile imparare a utilizzarlo e impiegarlo nei propri progetti poiché offre numerosi vantaggi:" + +#. type: Bullet: '1. ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Exactly the same environment as in production." +msgstr "Esattamente lo stesso ambiente della produzione." + +#. type: Bullet: '2. ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "No need to install anything except Docker itself." +msgstr "Non è necessario installare nulla tranne Docker stesso." + +#. type: Bullet: '3. ' +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Environment is per application, not per server." +msgstr "L'ambiente è per applicazione, non per server." + +#. type: Title ### +#: ../src/guide/intro/upgrade-from-v2.md +#, no-wrap +msgid "Environment variables" +msgstr "Variabili d'ambiente" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Yii3 application templates are using [environment variables](https://en.wikipedia.org/wiki/Environment_variable) to configure parts of the application. The concept is [very handy for Dockerized applications](https://12factor.net/) but might be alien to users of Yii 1.1 and Yii 2.0." +msgstr "I modelli dell'applicazione Yii3 utilizzano [variabili d’ambiente](https://en.wikipedia.org/wiki/Environment_variable) per configurare parti dell'applicazione. Il concetto è [molto utile per le applicazioni Dockerizzate](https://12factor.net/) , ma potrebbe risultare estraneo agli utenti di Yii 1.1 e Yii 2.0." + +#. type: Title # +#: ../src/guide/intro/upgrade-from-v2.md ../src/guide/structure/action.md +#, no-wrap +msgid "Actions" +msgstr "Azioni" + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Unlike Yii 2.0, Yii3 does not require controllers. Instead, it uses [actions](../structure/action.md), which are any callables. You can organize these into controllers similar to Yii 2, but it's not required." +msgstr "A differenza di Yii 2.0, Yii3 non richiede l’uso di controller. Utilizza invece le [azioni](../structure/action.md), che sono un qualsiasi oggetto richiamabile. È possibile organizzarle in controller simili a Yii 2, ma non è necessario." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Suggested Yii3 application structure is different from Yii 2.0. It's described in [application structure](../structure/overview.md)." +msgstr "La struttura dell'applicazione Yii3 suggerita è diversa da quella di Yii 2.0. È descritta in [struttura applicativa](../structure/overview.md)." + +#. type: Plain text +#: ../src/guide/intro/upgrade-from-v2.md +msgid "Despite that, Yii3 is flexible, so it's still possible to use a structure similar to Yii 2.0 with Yii3." +msgstr "Nonostante ciò, Yii3 è flessibile, quindi è ancora possibile utilizzare una struttura simile a Yii 2.0 con Yii3." diff --git a/_translations/po/it/guide_intro_what-is-yii.md.po b/_translations/po/it/guide_intro_what-is-yii.md.po new file mode 100644 index 00000000..d69a89f2 --- /dev/null +++ b/_translations/po/it/guide_intro_what-is-yii.md.po @@ -0,0 +1,155 @@ +# Italian 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: \n" +"POT-Creation-Date: 2025-12-27 03:24+0000\n" +"PO-Revision-Date: 2026-01-04 22:08+0100\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.8\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 "Yii è un framework PHP ad alte prestazioni basato su pacchetti per lo sviluppo di applicazioni moderne. Il nome Yii (pronunciato “Yee” o “[ji:]”) significa “semplice ed evolutivo” in cinese. Si può anche considerare come l'acronimo di **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 "Yii è un framework generico per la programmazione web. È possibile utilizzarlo per sviluppare tutti i tipi di applicazioni web utilizzando PHP. Grazie alla sua architettura e al sofisticato supporto della cache, è particolarmente adatto allo sviluppo di applicazioni su larga scala come portali, sistemi di gestione dei contenuti, e-commerce, API REST, ecc." + +#. type: Title # +#: ../src/guide/intro/what-is-yii.md +#, no-wrap +msgid "What is Yii" +msgstr "Cos'è Yii" + +#. type: Title ## +#: ../src/guide/intro/what-is-yii.md +#, no-wrap +msgid "What's Yii best for" +msgstr "Per cosa è più indicato usare Yii" + +#. type: Title ## +#: ../src/guide/intro/what-is-yii.md +#, no-wrap +msgid "How does Yii compare with other frameworks?" +msgstr "Come si posiziona Yii rispetto ad altri framework?" + +#. 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 hai già familiarità con un altro framework, potresti trovare interessante sapere come si posiziona Yii rispetto ad esso:" + +#. 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 "Yii adotta la [filosofia dell'essere pratico e utile](../../internals/001-yii-values.md) ottenendo:" + +#. type: Bullet: ' - ' +#: ../src/guide/intro/what-is-yii.md +msgid "Performance in both development and execution." +msgstr "Prestazioni sia nello sviluppo che nell'esecuzione." + +#. type: Bullet: ' - ' +#: ../src/guide/intro/what-is-yii.md +msgid "Convenient customizable defaults." +msgstr "Comode impostazioni predefinite personalizzabili." + +#. type: Bullet: ' - ' +#: ../src/guide/intro/what-is-yii.md +msgid "Practice-orientation." +msgstr "Orientamento alla pratica." + +#. type: Bullet: ' - ' +#: ../src/guide/intro/what-is-yii.md +msgid "Simplicity." +msgstr "Semplicità." + +#. type: Bullet: ' - ' +#: ../src/guide/intro/what-is-yii.md +msgid "Explicitness." +msgstr "Esplicitezza." + +#. type: Bullet: ' - ' +#: ../src/guide/intro/what-is-yii.md +msgid "Consistency." +msgstr "Coerenza." + +#. 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 "" +" Yii non cercherà mai di sovradimensionare le cose principalmente per seguire alcuni modelli di progettazione.\n" +"- Yii utilizza ampiamente le interfacce PSR con la possibilità di riutilizzare ciò che la comunità PHP ha creato e persino di\n" +" sostituire le implementazioni di base, se necessario.\n" +"- Yii è sia un insieme di librerie che un framework full-stack che fornisce molte funzionalità collaudate e pronte all'uso:\n" +" caching, logging, motore di template, astrazione dei dati, strumenti di sviluppo, generazione di codice e altro ancora.\n" +"- Yii è estensibile. È possibile personalizzare o sostituire ogni parte del codice del core. È inoltre possibile\n" +" sfruttare la solida architettura di Yii per utilizzare o sviluppare pacchetti ridistribuibili.\n" +"- Le prestazioni elevate sono sempre un obiettivo primario di 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 "Yii è supportato da un [forte team di sviluppatori principali](https://www.yiiframework.com/team/) sostenuto finanziariamente dalla [fondazione OpenCollective](https://opencollective.com/yiisoft), nonché da una vasta comunità di professionisti che contribuiscono costantemente allo sviluppo di Yii. Il team di sviluppatori Yii segue da vicino le ultime tendenze nello sviluppo web e le migliori pratiche e funzionalità presenti in altri framework e progetti. Le migliori pratiche e funzionalità più rilevanti trovate altrove vengono incorporate nel framework principale ed esposte tramite interfacce semplici ed eleganti." + +#. type: Title ## +#: ../src/guide/intro/what-is-yii.md +#, no-wrap +msgid "Yii versions" +msgstr "Versioni di 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 "Yii ha attualmente tre versioni principali disponibili: 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 "La versione 1.1 è quella di vecchia generazione ed è ora in modalità bugfix con congelamento delle funzionalità." + +#. 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 "La versione 2.0 è una versione stabile attuale in modalità bugfix con congelamento delle funzionalità." + +#. 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 "La versione 3.0 è quella attualmente in fase di sviluppo. Questa guida riguarda principalmente la versione 3." + +#. type: Title ## +#: ../src/guide/intro/what-is-yii.md +#, no-wrap +msgid "Requirements and prerequisites" +msgstr "Requisiti e prerequisiti" + +#. 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 "Yii3 richiede PHP 8.2 o versioni successive, ma alcuni pacchetti funzionano con versioni precedenti di PHP, come 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 "L'utilizzo di Yii richiede conoscenze di base della programmazione orientata agli oggetti (OOP), poiché Yii è un framework basato esclusivamente su OOP. Yii3 utilizza anche le ultime funzionalità PHP, come le dichiarazioni di tipo e i generatori. Comprendere questi concetti ti aiuterà ad apprendere Yii3 più rapidamente." diff --git a/_translations/po/it/guide_runtime_cookies.md.po b/_translations/po/it/guide_runtime_cookies.md.po new file mode 100644 index 00000000..a2095e64 --- /dev/null +++ b/_translations/po/it/guide_runtime_cookies.md.po @@ -0,0 +1,312 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: en/runtime/cookies.md +#, no-wrap +msgid "Cookies" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: en/runtime/cookies.md +#, no-wrap +msgid "Reading cookies" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: en/runtime/cookies.md +msgid "Here’s an example of how to work with cookies using the `\\Yiisoft\\RequestProvider\\RequestCookieProvider`:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: en/runtime/cookies.md +#, no-wrap +msgid "Signing and encrypting cookies" +msgstr "" + +#. type: Plain text +#: en/runtime/cookies.md +msgid "To prevent the substitution of the cookie value, the package provides two implementations:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: en/runtime/cookies.md +msgid "Encryption is more secure than signing but has lower performance." +msgstr "" + +#. 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 "" + +#. type: Plain text +#: en/runtime/cookies.md +msgid "To validate and get back the pure value, use the `validate()` and `decrypt()` method." +msgstr "" + +#. type: Fenced code block (php) +#: en/runtime/cookies.md +#, no-wrap +msgid "" +"$cookie = $signer->validate($signedCookie);\n" +"$cookie = $encryptor->decrypt($encryptedCookie);\n" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: en/runtime/cookies.md +#, no-wrap +msgid "Automating encryption and signing" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: en/runtime/cookies.md +msgid "This middleware provides the following features:" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/cookies.md +msgid "Validates and decrypts the cookie parameter values from the request." +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: en/runtime/cookies.md +msgid "Creating and using middleware:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: en/runtime/cookies.md +msgid "If the `$cookiesSettings` array is empty, no cookies will be encrypted and signed." +msgstr "" + +#. type: Title ## +#: en/runtime/cookies.md +#, no-wrap +msgid "Cookies security" +msgstr "" + +#. type: Plain text +#: en/runtime/cookies.md +msgid "You should configure each cookie to be secure. Important security settings are:" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/cookies.md +msgid "`httpOnly`. Setting it to `true` would prevent JavaScript to access cookie value." +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" diff --git a/_translations/po/it/guide_runtime_handling-errors.md.po b/_translations/po/it/guide_runtime_handling-errors.md.po new file mode 100644 index 00000000..85dfc8d3 --- /dev/null +++ b/_translations/po/it/guide_runtime_handling-errors.md.po @@ -0,0 +1,442 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/guide/runtime/handling-errors.md +#, fuzzy, no-wrap +#| msgid "Handling requests" +msgid "Handling errors" +msgstr "Gestione delle richieste" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/handling-errors.md +msgid "PSR-15 middleware for mapping certain exceptions to custom responses." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/handling-errors.md +msgid "Production and debug modes." +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/handling-errors.md +msgid "Takes PHP settings into account." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/handling-errors.md +msgid "Handles out of memory errors, fatal errors, warnings, notices, and exceptions." +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/handling-errors.md +msgid "Detects a response format based on a mime type of the request." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/handling-errors.md +msgid "Supports responding with HTML, plain text, JSON, XML, and headers out of the box." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/handling-errors.md +msgid "You can implement your own error rendering for extra types." +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/runtime/handling-errors.md +#, no-wrap +msgid "Using error handler" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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" +" ErrorHandler::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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/runtime/handling-errors.md +#, no-wrap +msgid "Rendering error data" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/handling-errors.md +msgid "`Yiisoft\\ErrorHandler\\Renderer\\HtmlRenderer` - Renders error into HTML." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/handling-errors.md +msgid "`Yiisoft\\ErrorHandler\\Renderer\\JsonRenderer` - Renders error into JSON." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/handling-errors.md +msgid "`Yiisoft\\ErrorHandler\\Renderer\\PlainTextRenderer` - Renders error into plain text." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/handling-errors.md +msgid "`Yiisoft\\ErrorHandler\\Renderer\\XmlRenderer` - Renders error into XML." +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "An Example of header rendering with a debugging mode turned off:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "An Example of header rendering with a debugging mode turned on:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "Example of JSON rendering output with a debugging mode turned off:" +msgstr "" + +#. type: Fenced code block (json) +#: ../src/guide/runtime/handling-errors.md +#, no-wrap +msgid "{\"message\":\"An internal server error occurred.\"}\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "An Example of JSON rendering output with debugging mode turned on:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "Example of HTML rendering with debugging mode turned off:" +msgstr "" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "![View production](/images/guide/runtime/view-production.png)" +msgstr "" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "Example of HTML rendering with debugging mode on and a light theme:" +msgstr "" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "![View development with light theme](/images/guide/runtime/view-development-light.png)" +msgstr "" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "Example of HTML rendering with debugging mode on and a dark theme:" +msgstr "" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "![View development with dark theme](/images/guide/runtime/view-development-dark.png)" +msgstr "" + +#. 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 that you register within the error catcher. By default, it supports JSON, XML, and plain text." +msgstr "" + +#. type: Title ### +#: ../src/guide/runtime/handling-errors.md +#, no-wrap +msgid "Implementing your own renderer" +msgstr "" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "You may customize the error response format by providing your own instance of `Yiisoft\\ErrorHandler\\ThrowableRendererInterface` when registering error catcher middleware." +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/handling-errors.md +#, no-wrap +msgid "" +"use Psr\\Http\\Message\\ServerRequestInterface;\n" +"use Yiisoft\\ErrorHandler\\ErrorData;\n" +"use Yiisoft\\ErrorHandler\\ThrowableRendererInterface;\n" +"\n" +"final readonly class MyRenderer implements ThrowableRendererInterface\n" +"{\n" +" public function render(Throwable $t, ServerRequestInterface $request = null): ErrorData\n" +" {\n" +" return new ErrorData($t->getMessage());\n" +" }\n" +"\n" +" public function renderVerbose(Throwable $t, ServerRequestInterface $request = null): ErrorData\n" +" {\n" +" return new ErrorData(\n" +" $t->getMessage(),\n" +" ['X-Custom-Header' => 'value-header'], // Headers to be added to the response.\n" +" );\n" +" }\n" +"};\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/runtime/handling-errors.md +msgid "You may configure it in the application configuration `config/web.php`:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/handling-errors.md +#, no-wrap +msgid "" +"use Psr\\Container\\ContainerInterface;\n" +"use Psr\\Http\\Message\\ResponseFactoryInterface;\n" +"use Yiisoft\\ErrorHandler\\ErrorHandler;\n" +"use Yiisoft\\ErrorHandler\\Middleware\\ErrorCatcher;\n" +"\n" +"return [\n" +" // ...\n" +" ErrorCatcher::class => static function (ContainerInterface $container): ErrorCatcher {\n" +" $errorCatcher = new ErrorCatcher(\n" +" $container->get(ResponseFactoryInterface::class),\n" +" $container->get(ErrorHandler::class),\n" +" $container,\n" +" );\n" +" // Returns a new instance without renderers by the specified content types.\n" +" $errorCatcher = $errorCatcher->withoutRenderers('application/xml', 'text/xml');\n" +" // Returns a new instance with the specified content type and renderer class.\n" +" return $errorCatcher->withRenderer('my/format', new MyRenderer());\n" +" },\n" +" // ...\n" +"];\n" +msgstr "" + +#. type: Title ## +#: ../src/guide/runtime/handling-errors.md +#, no-wrap +msgid "Friendly exceptions" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" diff --git a/_translations/po/it/guide_runtime_logging.md.po b/_translations/po/it/guide_runtime_logging.md.po new file mode 100644 index 00000000..34f6dd49 --- /dev/null +++ b/_translations/po/it/guide_runtime_logging.md.po @@ -0,0 +1,642 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "Logging" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "Using the Yii logging framework involves the following steps:" +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/runtime/logging.md +msgid "Record [log messages](#log-messages) at various places in your code;" +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/runtime/logging.md +msgid "Configure [log targets](#log-targets) in the application configuration to filter and export log messages;" +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/runtime/logging.md +msgid "Examine the filtered logged messages exported by different targets (e.g. the Yii debugger)." +msgstr "" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "In this section, the focus in on the first two steps." +msgstr "" + +#. type: Title ## +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "Log Messages " +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/logging.md +msgid "`emergency` - System is unusable." +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/logging.md +msgid "`critical` - Critical conditions. Example: Application component unavailable, unexpected exception." +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/logging.md +msgid "`notice` - Normal but significant events." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/logging.md +msgid "`info` - Interesting events. Example: User logs in, SQL logs." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/logging.md +msgid "`debug` - Detailed debug information." +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "Log targets " +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "In the above code, two log targets are registered:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '* ' +#: ../src/guide/runtime/logging.md +msgid "[[\\Yiisoft\\Log\\PsrTarget]]: passes log messages to another PSR-3 compatible logger." +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/runtime/logging.md +msgid "[[\\Yiisoft\\Log\\StreamTarget]]: writes log messages into a specified output stream." +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/runtime/logging.md +msgid "[[\\Yiisoft\\Log\\Target\\Db\\DbTarget]]: saves log messages in database." +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/runtime/logging.md +msgid "[[\\Yiisoft\\Log\\Target\\Email\\EmailTarget]]: sends log messages to pre-specified email addresses." +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/runtime/logging.md +msgid "[[\\Yiisoft\\Log\\Target\\File\\FileTarget]]: saves log messages in files." +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "In the following, we will describe the features common to all log targets." +msgstr "" + +#. type: Title ### +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "Message Filtering " +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "By default, the target will process messages of *any* severity level." +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "By default, the target will process messages of *any* category." +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "Message Formatting " +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "By default, log messages have the following format:" +msgstr "" + +#. type: Fenced code block +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "Timestamp Prefix[Level][Category] Message Context\n" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "function (\\Yiisoft\\Log\\Message $message, array $commonContext): string;\n" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "Message Trace Level " +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "Message flushing and exporting " +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "Toggling log targets " +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/runtime/logging.md +#, no-wrap +msgid "Creating new targets " +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/runtime/logging.md +msgid "The following protected methods will also be available for child targets:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/logging.md +msgid "`getMessages` - Get a list of log messages ([[\\Yii\\Log\\Message]] instances)." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/logging.md +msgid "`getFormattedMessages` - Get a list of log messages formatted as strings." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/logging.md +msgid "`formatMessages` - Get all log messages formatted as a string." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/runtime/logging.md +msgid "`getCommonContext` - Get an array with common context data in the `key => value` format." +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" diff --git a/_translations/po/it/guide_runtime_request.md.po b/_translations/po/it/guide_runtime_request.md.po new file mode 100644 index 00000000..f1ba97c6 --- /dev/null +++ b/_translations/po/it/guide_runtime_request.md.po @@ -0,0 +1,394 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: en/runtime/request.md +#, no-wrap +msgid "Request" +msgstr "" + +#. type: Plain text +#: en/runtime/request.md +msgid "HTTP request has a method, URI, a set of headers and a body:" +msgstr "" + +#. type: Fenced code block +#: en/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 "" + +#. type: Plain text +#: en/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 "" + +#. type: Plain text +#: en/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 "" + +#. type: Fenced code block (php) +#: en/runtime/request.md +#, no-wrap +msgid "" +"public function view(ServerRequestInterface $request): ResponseInterface\n" +"{\n" +" // ...\n" +"}\n" +msgstr "" + +#. type: Title ## +#: en/runtime/request.md +#, no-wrap +msgid "Method" +msgstr "" + +#. type: Plain text +#: en/runtime/request.md +msgid "The method could be obtained from a request object:" +msgstr "" + +#. type: Fenced code block (php) +#: en/runtime/request.md +#, no-wrap +msgid "$method = $request->getMethod();\n" +msgstr "" + +#. type: Plain text +#: en/runtime/request.md +msgid "Usually it's one of the:" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/request.md +msgid "GET" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/request.md +msgid "POST" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/request.md +msgid "PUT" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/request.md +msgid "DELETE" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/request.md +msgid "HEAD" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/request.md +msgid "PATCH" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/request.md +msgid "OPTIONS" +msgstr "" + +#. type: Plain text +#: en/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 "" + +#. type: Fenced code block (php) +#: en/runtime/request.md +#, no-wrap +msgid "" +"use Yiisoft\\Http\\Method;\n" +"\n" +"if ($request->getMethod() === Method::POST) {\n" +" // method is POST\n" +"}\n" +msgstr "" + +#. type: Title ## +#: en/runtime/request.md +#, no-wrap +msgid "URI" +msgstr "" + +#. type: Plain text +#: en/runtime/request.md +msgid "A URI has:" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/request.md +msgid "Scheme (`http`, `https`)" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/request.md +msgid "Host (`yiiframework.com`)" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/request.md +msgid "Port (`80`, `443`)" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/request.md +msgid "Path (`/posts/1`)" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/request.md +msgid "Query string (`page=1&sort=+id`)" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/request.md +msgid "Fragment (`#anchor`)" +msgstr "" + +#. type: Plain text +#: en/runtime/request.md +msgid "You can obtain `UriInterface` from request like the following:" +msgstr "" + +#. type: Fenced code block (php) +#: en/runtime/request.md +#, no-wrap +msgid "$uri = $request->getUri();\n" +msgstr "" + +#. type: Plain text +#: en/runtime/request.md +msgid "Then you can get various details from its methods:" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/request.md +msgid "`getScheme()`" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/request.md +msgid "`getAuthority()`" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/request.md +msgid "`getUserInfo()`" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/request.md +msgid "`getHost()`" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/request.md +msgid "`getPort()`" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/request.md +msgid "`getPath()`" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/request.md +msgid "`getQuery()`" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/request.md +msgid "`getFragment()`" +msgstr "" + +#. type: Title ## +#: en/runtime/request.md en/runtime/response.md +#, no-wrap +msgid "Headers" +msgstr "" + +#. type: Plain text +#: en/runtime/request.md +msgid "There are various methods to inspect request headers. To get all headers as an array:" +msgstr "" + +#. type: Fenced code block (php) +#: en/runtime/request.md +#, no-wrap +msgid "" +"$headers = $request->getHeaders();\n" +"foreach ($headers as $name => $values) {\n" +" // ...\n" +"}\n" +msgstr "" + +#. type: Plain text +#: en/runtime/request.md +msgid "To get a single header:" +msgstr "" + +#. type: Fenced code block (php) +#: en/runtime/request.md +#, no-wrap +msgid "$values = $request->getHeader('Accept-Encoding');\n" +msgstr "" + +#. type: Plain text +#: en/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 "" + +#. type: Fenced code block (php) +#: en/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 "" + +#. type: Plain text +#: en/runtime/request.md +msgid "To check if a header is present in the request:" +msgstr "" + +#. type: Fenced code block (php) +#: en/runtime/request.md +#, no-wrap +msgid "" +"if ($request->hasHeader('Accept-Encoding')) {\n" +" // ...\n" +"}\n" +msgstr "" + +#. type: Title ## +#: en/runtime/request.md en/runtime/response.md +#, no-wrap +msgid "Body" +msgstr "" + +#. type: Plain text +#: en/runtime/request.md +msgid "There are two methods to get body contents. The first is getting the body as it is without parsing:" +msgstr "" + +#. type: Fenced code block (php) +#: en/runtime/request.md +#, no-wrap +msgid "$body = $request->getBody();\n" +msgstr "" + +#. type: Plain text +#: en/runtime/request.md +msgid "The `$body` would be an instance of `Psr\\Http\\Message\\StreamInterface`." +msgstr "" + +#. type: Plain text +#: en/runtime/request.md +msgid "Also, you could get a parsed body:" +msgstr "" + +#. type: Fenced code block (php) +#: en/runtime/request.md +#, no-wrap +msgid "$bodyParameters = $request->getParsedBody();\n" +msgstr "" + +#. type: Plain text +#: en/runtime/request.md +msgid "Parsing depends on PSR-7 implementation and may require middleware for custom body formats." +msgstr "" + +#. type: Fenced code block (php) +#: en/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 "" + +#. type: Title ## +#: en/runtime/request.md +#, no-wrap +msgid "File uploads" +msgstr "" + +#. type: Plain text +#: en/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 "" + +#. type: Fenced code block (php) +#: en/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 "" + +#. type: Title ## +#: en/runtime/request.md +#, no-wrap +msgid "Attributes" +msgstr "" + +#. type: Plain text +#: en/runtime/request.md +msgid "Application middleware may set custom request attributes using `withAttribute()` method. You can get these attributes with `getAttribute()`." +msgstr "" diff --git a/_translations/po/it/guide_runtime_response.md.po b/_translations/po/it/guide_runtime_response.md.po new file mode 100644 index 00000000..a70e67d4 --- /dev/null +++ b/_translations/po/it/guide_runtime_response.md.po @@ -0,0 +1,232 @@ +# Italian 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-26 22:37+0000\n" +"PO-Revision-Date: 2025-12-26 22:37+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title ## +#: ../src/guide/runtime/request.md ../src/guide/runtime/response.md +#, no-wrap +msgid "Headers" +msgstr "" + +#. type: Title ## +#: ../src/guide/runtime/request.md ../src/guide/runtime/response.md +#: ../src/internals/006-git-commit-messages.md +#, no-wrap +msgid "Body" +msgstr "" + +#. type: Title # +#: ../src/guide/runtime/response.md +#, no-wrap +msgid "Response" +msgstr "" + +#. type: Plain text +#: ../src/guide/runtime/response.md +msgid "HTTP response has status code and message, a set of headers and a body:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/runtime/response.md +#, no-wrap +msgid "Status code" +msgstr "" + +#. type: Plain text +#: ../src/guide/runtime/response.md +msgid "You can set a status code like the following:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/runtime/response.md +msgid "Majority of status codes are available from `Status` class for convenience and readability." +msgstr "" + +#. type: Plain text +#: ../src/guide/runtime/response.md +msgid "You can set headers like this:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/response.md +#, no-wrap +msgid "$response = $response->withHeader('Content-type', 'application/json');\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/runtime/response.md +msgid "If there is a need to append a header value to the existing header:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/runtime/response.md +msgid "And, if needed, headers could be removed:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/response.md +#, no-wrap +msgid "$response = $response->withoutHeader('Set-Cookie');\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/runtime/response.md +msgid "Response body is an object implementing `Psr\\Http\\Message\\StreamInterface`." +msgstr "" + +#. type: Plain text +#: ../src/guide/runtime/response.md +msgid "You can write to it via the interface itself:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/runtime/response.md +#, no-wrap +msgid "" +"$body = $response->getBody();\n" +"$body->write('Hello');\n" +msgstr "" + +#. type: Title ## +#: ../src/guide/runtime/response.md +#, no-wrap +msgid "Examples" +msgstr "" + +#. type: Title ### +#: ../src/guide/runtime/response.md +#, no-wrap +msgid "Redirecting" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/runtime/response.md +msgid "Note that there are different statuses used for redirection:" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/runtime/response.md +#, no-wrap +msgid "Responding with JSON" +msgstr "" + +#. 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 "" diff --git a/_translations/po/it/guide_runtime_routing.md.po b/_translations/po/it/guide_runtime_routing.md.po new file mode 100644 index 00000000..f6315112 --- /dev/null +++ b/_translations/po/it/guide_runtime_routing.md.po @@ -0,0 +1,518 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: en/runtime/routing.md +#, fuzzy, no-wrap +#| msgid "[Routing and URL generation](runtime/routing.md)" +msgid "Routing and URL generation" +msgstr "[Routing e generazione di URL](runtime/routing.md)" + +#. type: Plain text +#: en/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 "" + +#. type: Plain text +#: en/runtime/routing.md +msgid "The reverse process of routing is *URL generation*, which creates a URL from a given named route and the associated query parameters. When you later request the created URL, the routing process can resolve it back into the original route and query parameters." +msgstr "" + +#. type: Plain text +#: en/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 "" + +#. type: Title ## +#: en/runtime/routing.md +#, no-wrap +msgid "Configuring routes" +msgstr "" + +#. type: Plain text +#: en/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 "" + +#. type: Fenced code block (php) +#: en/runtime/routing.md +#, no-wrap +msgid "" +"action([SiteController::class, 'index'])\n" +" ->name('site/index')\n" +"];\n" +msgstr "" + +#. type: Plain text +#: en/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 "" + +#. type: Bullet: '- ' +#: en/runtime/routing.md +msgid "get" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/routing.md +msgid "post" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/routing.md +msgid "put" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/routing.md +msgid "delete" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/routing.md +msgid "patch" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/routing.md +msgid "head" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/routing.md +msgid "options" +msgstr "" + +#. type: Plain text +#: en/runtime/routing.md +msgid "If you need many methods, you can use `methods()`:" +msgstr "" + +#. type: Fenced code block (php) +#: en/runtime/routing.md +#, no-wrap +msgid "" +"action([SiteController::class, 'user'])\n" +" ->name('site/user')\n" +"];\n" +msgstr "" + +#. type: Plain text +#: en/runtime/routing.md +msgid "All these methods accept a route pattern and a handler. 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. You could specify a handler as:" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/routing.md +#, fuzzy +#| msgid "[Middleware](structure/middleware.md)" +msgid "[Middleware](../structure/middleware.md) class name." +msgstr "[Middleware](structure/middleware.md)" + +#. type: Bullet: '- ' +#: en/runtime/routing.md +msgid "Handler action (an array of [HandlerClass, handlerMethod])." +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/routing.md +msgid "A callable." +msgstr "" + +#. type: Plain text +#: en/runtime/routing.md +msgid "In case of a handler action, a class of type `HandlerClass` is instantiated and its `handlerMethod` is called:" +msgstr "" + +#. type: Fenced code block (php) +#: en/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 "" + +#. type: Plain text +#: en/runtime/routing.md +msgid "The callable is called as is:" +msgstr "" + +#. type: Fenced code block (php) +#: en/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 "" + +#. type: Plain text +#: en/runtime/routing.md +msgid "For handler action and callable typed parameters are automatically injected using the dependency injection container passed to the route." +msgstr "" + +#. type: Plain text +#: en/runtime/routing.md +msgid "Get current request and handler by type-hinting for `ServerRequestInterface` and `RequestHandlerInterface`. You could add extra handlers to wrap primary one with `middleware()` method:" +msgstr "" + +#. type: Fenced code block (php) +#: en/runtime/routing.md +#, no-wrap +msgid "" +"action([DownloadController::class, 'download'])\n" +" ->name('download/id')\n" +" ->middleware(LimitDownloadRate::class)\n" +"];\n" +msgstr "" + +#. type: Plain text +#: en/runtime/routing.md +msgid "Check [\"the middleware\"](../structure/middleware.md) guide to learn more about how to implement middleware." +msgstr "" + +#. type: Plain text +#: en/runtime/routing.md +msgid "This is especially useful when grouping routes:" +msgstr "" + +#. type: Fenced code block (php) +#: en/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(FormatDataResponseAsJson::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(FormatDataResponseAsJson::class)\n" +" ->name('api/user/profile'),\n" +" )\n" +"];\n" +msgstr "" + +#. type: Plain text +#: en/runtime/routing.md +msgid "Router executes `ApiDataWrapper` before handling any URL starting with `/api`." +msgstr "" + +#. type: Plain text +#: en/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 "" + +#. type: Plain text +#: en/runtime/routing.md +msgid "You can set a default value for a route parameter. For example:" +msgstr "" + +#. type: Fenced code block (php) +#: en/runtime/routing.md +#, no-wrap +msgid "" +"action([SiteController::class, 'user'])\n" +" ->name('site/user')\n" +" ->defaults(['id' => '42'])\n" +"];\n" +msgstr "" + +#. type: Plain text +#: en/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 "" + +#. type: Plain text +#: en/runtime/routing.md +msgid "In cause URL should be valid for a single host, you can specify it with `host()`." +msgstr "" + +#. type: Title ## +#: en/runtime/routing.md +#, no-wrap +msgid "Routing " +msgstr "" + +#. type: Plain text +#: en/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 "" + +#. type: Plain text +#: en/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 "" + +#. type: Title ## +#: en/runtime/routing.md +#, no-wrap +msgid "Generating URLs " +msgstr "" + +#. type: Plain text +#: en/runtime/routing.md +msgid "To generate URL based on a route, a route should have a name:" +msgstr "" + +#. type: Fenced code block (php) +#: en/runtime/routing.md +#, no-wrap +msgid "" +"name('test/index'),\n" +" Route::post('/test/submit/{id}', [TestController::class, 'submit'])\n" +" ->name('test/submit')\n" +"];\n" +msgstr "" + +#. type: Plain text +#: en/runtime/routing.md +msgid "The generation looks like the following:" +msgstr "" + +#. type: Fenced code block (php) +#: en/runtime/routing.md +#, no-wrap +msgid "" +"generate('test/submit', ['id' => '42']);\n" +" // ...\n" +" }\n" +"}\n" +msgstr "" + +#. type: Plain text +#: en/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 "" + +#. type: Plain text +#: en/runtime/routing.md +msgid "Then we use `generate()` method to get actual URL. It accepts a route name and an array of named query parameters. The code will return \"/test/submit/42.\" If you need absolute URL, use `generateAbsolute()` instead." +msgstr "" + +#. type: Title ## +#: en/runtime/routing.md +#, no-wrap +msgid "Route patterns " +msgstr "" + +#. type: Plain text +#: en/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 "" + +#. type: Plain text +#: en/runtime/routing.md +msgid "Basic patterns are static like `/test`. That means they must match exactly in order for a route match." +msgstr "" + +#. type: Title ### +#: en/runtime/routing.md +#, no-wrap +msgid "Named Parameters " +msgstr "" + +#. type: Plain text +#: en/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 "" + +#. type: Plain text +#: en/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 "" + +#. type: Plain text +#: en/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 "" + +#. type: Plain text +#: en/runtime/routing.md +msgid "On a route match router fills the associated request attributes 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 "" + +#. type: Plain text +#: en/runtime/routing.md +msgid "Let's use some examples to illustrate how named parameters work. Assume you've declared the following three patterns:" +msgstr "" + +#. type: Bullet: '1. ' +#: en/runtime/routing.md +msgid "`'posts/{year:\\d{4}}/{category}`" +msgstr "" + +#. type: Bullet: '2. ' +#: en/runtime/routing.md +msgid "`'posts'`" +msgstr "" + +#. type: Bullet: '3. ' +#: en/runtime/routing.md +msgid "`'post/{id:\\d+}'`" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/routing.md +msgid "`/posts` match the second pattern;" +msgstr "" + +#. type: Bullet: '- ' +#: en/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 "" + +#. type: Bullet: '- ' +#: en/runtime/routing.md +msgid "`/post/100` match a third pattern. The `id` parameter value is 100;" +msgstr "" + +#. type: Bullet: '- ' +#: en/runtime/routing.md +msgid "`/posts/php` doesn't match." +msgstr "" + +#. type: Plain text +#: en/runtime/routing.md +msgid "When generating URLs, you should use the following parameters:" +msgstr "" + +#. type: Fenced code block (php) +#: en/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 "" + +#. type: Title ### +#: en/runtime/routing.md +#, no-wrap +msgid "Optional parts " +msgstr "" + +#. type: Plain text +#: en/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 "" + +#. type: Fenced code block (php) +#: en/runtime/routing.md +#, no-wrap +msgid "" +"use \\Yiisoft\\Router\\Route;\n" +"\n" +"Route::get('/posts[/{id}]')->defaults(['id' => '1']);\n" +msgstr "" + +#. type: Plain text +#: en/runtime/routing.md +msgid "Optional parts are only supported in a trailing position, not in the middle of a route." +msgstr "" diff --git a/_translations/po/it/guide_runtime_sessions.md.po b/_translations/po/it/guide_runtime_sessions.md.po new file mode 100644 index 00000000..439549c6 --- /dev/null +++ b/_translations/po/it/guide_runtime_sessions.md.po @@ -0,0 +1,252 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: en/runtime/sessions.md +#, no-wrap +msgid "Sessions" +msgstr "" + +#. type: Plain text +#: en/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 "" + +#. type: Plain text +#: en/runtime/sessions.md +msgid "To add it to your application, use composer:" +msgstr "" + +#. type: Fenced code block (shell) +#: en/runtime/sessions.md +#, no-wrap +msgid "composer require yiisoft/session\n" +msgstr "" + +#. type: Title ## +#: en/runtime/sessions.md +#, no-wrap +msgid "Configuring middleware" +msgstr "" + +#. type: Plain text +#: en/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 "" + +#. type: Plain text +#: en/runtime/sessions.md +msgid "To add a session for a certain group of routes, edit `config/routes.php` like the following:" +msgstr "" + +#. type: Fenced code block (php) +#: en/runtime/sessions.md +#, no-wrap +msgid "" +"middleware(SessionMiddleware::class)\n" +" ->routes(\n" +" // ...\n" +" )\n" +"];\n" +msgstr "" + +#. type: Plain text +#: en/runtime/sessions.md +msgid "To add a session to the whole application, edit `config/application.php` like the following:" +msgstr "" + +#. type: Fenced code block (php) +#: en/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" +" CsrfMiddleware::class,\n" +" SessionMiddleware::class, // <-- add this\n" +" ErrorCatcher::class,\n" +" ]\n" +" );\n" +" }),\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" + +#. type: Title ## +#: en/runtime/sessions.md +#, no-wrap +msgid "Opening and closing session" +msgstr "" + +#. type: Fenced code block (php) +#: en/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 "" + +#. type: Plain text +#: en/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 "" + +#. type: Plain text +#: en/runtime/sessions.md +msgid "There are two more ways to close a session:" +msgstr "" + +#. type: Fenced code block (php) +#: en/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 "" + +#. type: Title ## +#: en/runtime/sessions.md +#, fuzzy, no-wrap +#| msgid "Working with databases" +msgid "Working with session data" +msgstr "Lavorare con i database" + +#. type: Plain text +#: en/runtime/sessions.md +msgid "Usually you will use the following methods to work with session data:" +msgstr "" + +#. type: Fenced code block (php) +#: en/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 "" + +#. type: Title ## +#: en/runtime/sessions.md +#, no-wrap +msgid "Flash messages" +msgstr "" + +#. type: Plain text +#: en/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 "" + +#. type: Plain text +#: en/runtime/sessions.md +msgid "`FlashInteface` usage is the following:" +msgstr "" + +#. type: Fenced code block (php) +#: en/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 "" + +#. type: Title ## +#: en/runtime/sessions.md +#, no-wrap +msgid "Custom session storage" +msgstr "" + +#. type: Plain text +#: en/runtime/sessions.md +msgid "When using `Yiisoft\\Session\\Session`, you can use your own storage implementation:" +msgstr "" + +#. type: Fenced code block (php) +#: en/runtime/sessions.md +#, no-wrap +msgid "" +"$handler = new MySessionHandler();\n" +"$session = new \\Yiisoft\\Session\\Session([], $handler);\n" +msgstr "" + +#. type: Plain text +#: en/runtime/sessions.md +msgid "Custom storage must implement `\\SessionHandlerInterface`." +msgstr "" diff --git a/_translations/po/it/guide_security_authentication.md.po b/_translations/po/it/guide_security_authentication.md.po new file mode 100644 index 00000000..53d54a6a --- /dev/null +++ b/_translations/po/it/guide_security_authentication.md.po @@ -0,0 +1,433 @@ +# Italian 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-12 19:52+0000\n" +"PO-Revision-Date: 2025-09-11 10:15+0500\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/guide/security/authentication.md +#, no-wrap +msgid "Authentication" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '* ' +#: ../src/guide/security/authentication.md +msgid "Configure the `Yiisoft\\User\\CurrentUser` service;" +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/security/authentication.md +msgid "Create a class implementing the `\\Yiisoft\\Auth\\IdentityInterface` interface;" +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/security/authentication.md +msgid "Create a class implementing the `\\Yiisoft\\Auth\\IdentityRepositoryInterface` interface;" +msgstr "" + +#. type: Plain text +#: ../src/guide/security/authentication.md +#, fuzzy +#| msgid "[VarDumper](https://github.com/yiisoft/var-dumper)" +msgid "To use the `Yiisoft\\User\\CurrentUser` service, install [yiisoft/user](https://github.com/yiisoft/user) package:" +msgstr "[VarDumper](https://github.com/yiisoft/var-dumper)" + +#. type: Fenced code block (shell) +#: ../src/guide/security/authentication.md +#, fuzzy, no-wrap +#| msgid "composer create-project yiisoft/app your_project\n" +msgid "composer require yiisoft/user\n" +msgstr "composer create-project yiisoft/app your_project\n" + +#. type: Title ## +#: ../src/guide/security/authentication.md +#, fuzzy, no-wrap +#| msgid "Configuring router" +msgid "Configuring `Yiisoft\\User\\CurrentUser`" +msgstr "Configurazione del router" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/security/authentication.md +#, no-wrap +msgid "Implementing`\\Yiisoft\\Auth\\IdentityInterface` " +msgstr "" + +#. type: Plain text +#: ../src/guide/security/authentication.md +msgid "The identity class must implement the `\\Yiisoft\\Auth\\IdentityInterface` which has a single method:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/security/authentication.md +msgid "In the following example, an identity class is implemented as a pure PHP object." +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/security/authentication.md +#, no-wrap +msgid "" +"id;\n" +" }\n" +"}\n" +msgstr "" + +#. type: Title ## +#: ../src/guide/security/authentication.md +#, no-wrap +msgid "Implementing`\\Yiisoft\\Auth\\IdentityRepositoryInterface` " +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/security/authentication.md +msgid "A dummy implementation may look like the following:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/security/authentication.md +#, no-wrap +msgid "Using `\\Yiisoft\\User\\CurrentUser`" +msgstr "" + +#. 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 "" + +#. 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 actionIndex(ServerRequestInterface $request, CurrentUser $user)\n" +" { \n" +" if ($user->isGuest()) {\n" +" // user is guest\n" +" } else {\n" +" $identity = $user->getIdentity();\n" +" // do something based on identity\n" +" } \n" +" }\n" +"}\n" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/security/authentication.md +msgid "To log in a user, you may use the following code:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/security/authentication.md +msgid "To log out a user, call" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/security/authentication.md +#, no-wrap +msgid "" +"/* @var $user \\Yiisoft\\User\\CurrentUser */\n" +"$user->logout();\n" +msgstr "" + +#. type: Title ## +#: ../src/guide/security/authentication.md +#, no-wrap +msgid "Protecting Routes" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/security/authentication.md +msgid "First, configure the `Yiisoft\\Auth\\AuthenticationMethodInterface`:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/security/authentication.md +msgid "Then, apply the `Yiisoft\\Auth\\Middleware\\Authentication` middleware to a route:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/security/authentication.md +#, no-wrap +msgid " Or to a group of routes:\n" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/security/authentication.md +#, fuzzy, 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" +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 "" +"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: Title ## +#: ../src/guide/security/authentication.md +#, no-wrap +msgid "Authentication Events " +msgstr "" + +#. type: Plain text +#: ../src/guide/security/authentication.md +msgid "The user service raises a few events during the login and logout processes." +msgstr "" + +#. 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 "" + +#. type: Bullet: '* ' +#: ../src/guide/security/authentication.md +msgid "`\\Yiisoft\\User\\Event\\AfterLogin`: raised after a successful login." +msgstr "" + +#. 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 "" + +#. type: Bullet: '* ' +#: ../src/guide/security/authentication.md +msgid "`\\Yiisoft\\User\\Event\\AfterLogout`: raised after a successful logout." +msgstr "" + +#. 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 "" diff --git a/_translations/po/it/guide_security_authorization.md.po b/_translations/po/it/guide_security_authorization.md.po new file mode 100644 index 00000000..1478ea25 --- /dev/null +++ b/_translations/po/it/guide_security_authorization.md.po @@ -0,0 +1,867 @@ +# Italian 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-16 21:14+0000\n" +"PO-Revision-Date: 2025-12-24 10:12+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Authorization" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Checking for permission " +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Role-based access control (RBAC) " +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "To ease description next, there are some basic RBAC concepts first." +msgstr "" + +#. type: Title ### +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Basic concepts " +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Configuring RBAC " +msgstr "" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Yii RBAC requires storage to be provided." +msgstr "" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "One of the following storages could be installed:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/security/authorization.md +#, fuzzy +#| msgid "[Strings](https://github.com/yiisoft/strings)" +msgid "[PHP storage](https://github.com/yiisoft/rbac-php) - PHP file storage;" +msgstr "[Stringhe](https://github.com/yiisoft/strings)" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/security/authorization.md +#, fuzzy +#| msgid "[Strings](https://github.com/yiisoft/strings)" +msgid "You can also provide your own storage using the [yiisoft/rbac](https://github.com/yiisoft/rbac) package." +msgstr "[Stringhe](https://github.com/yiisoft/strings)" + +#. type: Title #### +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Configuring RBAC with the [PHP storage](https://github.com/yiisoft/rbac-php) " +msgstr "" + +#. type: Plain text +#: ../src/guide/security/authorization.md +#, fuzzy +#| msgid "[VarDumper](https://github.com/yiisoft/var-dumper)" +msgid "Install [yiisoft/rbac-php](https://github.com/yiisoft/rbac-php) package:" +msgstr "[VarDumper](https://github.com/yiisoft/var-dumper)" + +#. type: Fenced code block +#: ../src/guide/security/authorization.md +#, fuzzy, no-wrap +#| msgid "composer create-project yiisoft/app your_project\n" +msgid "composer require yiisoft/rbac-php\n" +msgstr "composer create-project yiisoft/app your_project\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 "" + +#. 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" +"\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" +msgstr "" + +#. 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 "" + +#. type: Title #### +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Configuring RBAC with the [DB storage](https://github.com/yiisoft/rbac-db) " +msgstr "" + +#. type: Plain text +#: ../src/guide/security/authorization.md +#, fuzzy +#| msgid "[Strings](https://github.com/yiisoft/strings)" +msgid "Install [yiisoft/rbac-db](https://github.com/yiisoft/rbac-db) package:" +msgstr "[Stringhe](https://github.com/yiisoft/strings)" + +#. type: Fenced code block +#: ../src/guide/security/authorization.md +#, fuzzy, no-wrap +#| msgid "composer create-project yiisoft/app your_project\n" +msgid "composer require yiisoft/rbac-db\n" +msgstr "composer create-project yiisoft/app your_project\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 "" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "[Configure connection](https://yiisoft.github.io/docs/guide/start/databases.html#configuring-connection)." +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/security/authorization.md +#, fuzzy +#| msgid "Application structure" +msgid "Apply migrations:" +msgstr "Struttura applicativa" + +#. type: Fenced code block +#: ../src/guide/security/authorization.md +#, fuzzy, no-wrap +#| msgid "APP_ENV=dev ./yii serve --port=80\n" +msgid "APP_ENV=dev ./yii migrate:up\n" +msgstr "APP_ENV=dev ./yii serve --port=80\n" + +#. type: Title ### +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Building authorization data " +msgstr "" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Building authorization data is all about the following tasks:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/security/authorization.md +msgid "defining roles and permissions;" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/security/authorization.md +msgid "establishing relations between roles and permissions;" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/security/authorization.md +msgid "defining rules;" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/security/authorization.md +msgid "associating rules with roles and permissions;" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/security/authorization.md +msgid "assigning roles to users." +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Either way, in the end, you'll get the following RBAC hierarchy:" +msgstr "" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "![Simple RBAC hierarchy](/images/guide/security/rbac-hierarchy-1.svg \"Simple RBAC hierarchy\")" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Using console command" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Add the command to `config/console/commands.php`:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "You can execute the command above from the console the following way:" +msgstr "" + +#. type: Fenced code block +#: ../src/guide/security/authorization.md +#, fuzzy, no-wrap +#| msgid "APP_ENV=dev ./yii serve --port=80\n" +msgid "APP_ENV=dev ./yii rbac:init\n" +msgstr "APP_ENV=dev ./yii serve --port=80\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 "" + +#. type: Title #### +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Using migrations" +msgstr "" + +#. type: Plain text +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "**TODO**: finish it when migrations are implemented.\n" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Create new migration using `APP_ENV=dev ./yii migrate:create init_rbac` then implement creating a hierarchy:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "You could apply migration by using `APP_ENV=dev ./yii migrate:up`." +msgstr "" + +#. type: Title ## +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Assigning roles to users" +msgstr "" + +#. type: Plain text +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "TODO: update when signup implemented in demo / template.\n" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Using rules " +msgstr "" + +#. 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 "" + +#. 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\\Rule;\n" +"\n" +"/**\n" +" * Checks if the authorID matches user passed via params.\n" +" */\n" +"final readonly class AuthorRule extends Rule\n" +"{\n" +" private const NAME = 'isAuthor';\n" +"\n" +" public function __construct() {\n" +" parent::__construct(self::NAME);\n" +" }\n" +"\n" +" public function execute(string $userId, Item $item, array $parameters = []): bool\n" +" {\n" +" return isset($params['post']) ? $params['post']->getAuthorId() == $userId : false;\n" +" }\n" +"}\n" +msgstr "" + +#. 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 "" + +#. type: Fenced code block (php) +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "" +"/** @var \\Yiisoft\\Rbac\\ManagerInterface $auth */\n" +"\n" +"// add the rule\n" +"$rule = new AuthorRule();\n" +"$auth->add($rule);\n" +"\n" +"// add the \"updateOwnPost\" permission and associate the rule with it.\n" +"$updateOwnPost = (new \\Yiisoft\\Rbac\\Permission('updateOwnPost'))\n" +" ->withDescription('Update own post')\n" +" ->withRuleName($rule->getName());\n" +"$auth->add($updateOwnPost);\n" +"\n" +"// \"updateOwnPost\" will be used from \"updatePost\"\n" +"$auth->addChild($updateOwnPost, $updatePost);\n" +"\n" +"// allow \"author\" to update their own posts\n" +"$auth->addChild($author, $updateOwnPost);\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Now you've got the following hierarchy:" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Access check " +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "![Access check](/images/guide/security/rbac-access-check-1.svg \"Access check\")" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "Here is what happens if the current user is John:" +msgstr "" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "![Access check](/images/guide/security/rbac-access-check-2.svg \"Access check\")" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/security/authorization.md +msgid "![Access check](/images/guide/security/rbac-access-check-3.svg \"Access check\")" +msgstr "" + +#. type: Title ## +#: ../src/guide/security/authorization.md +#, no-wrap +msgid "Implementing your own access checker" +msgstr "" + +#. 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 "" + +#. 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 "" diff --git a/_translations/po/it/guide_security_best-practices.md.po b/_translations/po/it/guide_security_best-practices.md.po new file mode 100644 index 00000000..c03b8761 --- /dev/null +++ b/_translations/po/it/guide_security_best-practices.md.po @@ -0,0 +1,497 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"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/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 "" + +#. type: Title # +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "Security best practices" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "Basic principles" +msgstr "" + +#. 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 "" + +#. type: Bullet: '1. ' +#: ../src/guide/security/best-practices.md +msgid "Filter input." +msgstr "" + +#. type: Bullet: '2. ' +#: ../src/guide/security/best-practices.md +msgid "Escape output." +msgstr "" + +#. type: Title ### +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "Filter input" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "In Yii, most probably you'll use form validation to do similar checks." +msgstr "" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "Further reading on the topic:" +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 "Escape output" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Fenced code block (sql) +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "SELECT * FROM user WHERE username = ''; DROP TABLE user; --'\n" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/guide/security/best-practices.md +msgid "" +msgstr "" + +#. type: Title ## +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "Avoiding XSS" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "Avoiding XSS is quite easy in Yii. There are two cases:" +msgstr "" + +#. type: Bullet: '1. ' +#: ../src/guide/security/best-practices.md +msgid "You want to output data as plain text." +msgstr "" + +#. type: Bullet: '2. ' +#: ../src/guide/security/best-practices.md +msgid "You want to output data as HTML." +msgstr "" + +#. 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 "" + +#. type: Fenced code block (php) +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "\n" +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 "" + +#. type: Title ## +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "Avoiding CSRF" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "For this reason, Yii applies extra mechanisms to protect against CSRF attacks." +msgstr "" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "To avoid CSRF, you should always:" +msgstr "" + +#. 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 "" + +#. type: Bullet: '2. ' +#: ../src/guide/security/best-practices.md +msgid "Keep Yii CSRF protection enabled." +msgstr "" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "Yii has CSRF protection as `Yiisoft\\Yii\\Web\\Middleware\\Csrf` middleware. Make sure it's in your application middleware stack." +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 file exposure" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "Avoiding debug info and tools in production" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "Secure server configuration" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "Avoiding `Host`-header attacks" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/guide/security/best-practices.md +msgid "Apache 2: " +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/security/best-practices.md +msgid "Nginx: " +msgstr "" + +#. type: Title ### +#: ../src/guide/security/best-practices.md +#, no-wrap +msgid "Configuring SSL peer validation" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "or" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '2. ' +#: ../src/guide/security/best-practices.md +msgid "Add the following to your php.ini:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/security/best-practices.md +msgid "Note that you should keep the file up to date." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/security/best-practices.md +msgid "[OWASP top 10](https://owasp.org/Top10/)" +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/guide/security/best-practices.md +msgid "[PHP manual: security](https://www.php.net/manual/en/security.php)" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/security/best-practices.md +msgid "[Information security at STackExchange](https://security.stackexchange.com/)" +msgstr "" diff --git a/_translations/po/it/guide_security_cryptography.md.po b/_translations/po/it/guide_security_cryptography.md.po new file mode 100644 index 00000000..b186a290 --- /dev/null +++ b/_translations/po/it/guide_security_cryptography.md.po @@ -0,0 +1,235 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: en/security/cryptography.md +#, no-wrap +msgid "Cryptography" +msgstr "" + +#. type: Plain text +#: en/security/cryptography.md +msgid "In this section, we'll review the following security aspects:" +msgstr "" + +#. type: Bullet: '- ' +#: en/security/cryptography.md +#, fuzzy +#| msgid "Generating API documentation" +msgid "Generating random data" +msgstr "Generazione della documentazione API" + +#. type: Bullet: '- ' +#: en/security/cryptography.md +msgid "Encryption and Decryption" +msgstr "" + +#. type: Bullet: '- ' +#: en/security/cryptography.md +msgid "Confirming Data Integrity" +msgstr "" + +#. type: Plain text +#: en/security/cryptography.md +msgid "To use these features, you need to install `yiisoft/security` package:" +msgstr "" + +#. type: Fenced code block +#: en/security/cryptography.md +#, no-wrap +msgid "composer install yiisoft/security\n" +msgstr "" + +#. type: Title ## +#: en/security/cryptography.md +#, no-wrap +msgid "Generating pseudorandom data" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: en/security/cryptography.md +msgid "`\\Yiisoft\\Security\\Random` makes generating pseudorandom data simple:" +msgstr "" + +#. type: Fenced code block (php) +#: en/security/cryptography.md +#, no-wrap +msgid "$key = \\Yiisoft\\Security\\Random::string(42);\n" +msgstr "" + +#. type: Plain text +#: en/security/cryptography.md +msgid "The code above would give you a random string consisting of 42 characters." +msgstr "" + +#. type: Plain text +#: en/security/cryptography.md +msgid "If you need bytes or integers, use PHP functions directly:" +msgstr "" + +#. type: Bullet: '- ' +#: en/security/cryptography.md +msgid "`random_bytes()` for bytes. Note that the output may not be ASCII." +msgstr "" + +#. type: Bullet: '- ' +#: en/security/cryptography.md +msgid "`random_int()` for integers." +msgstr "" + +#. type: Title ## +#: en/security/cryptography.md +#, no-wrap +msgid "Encryption and decryption" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: en/security/cryptography.md +msgid "Decrypting it:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: en/security/cryptography.md +msgid "You could use a key instead of a password:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: en/security/cryptography.md +#, no-wrap +msgid "Confirming data integrity" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: en/security/cryptography.md +msgid "The `$key` should be present at both sending and receiving sides. On the sending side:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: en/security/cryptography.md +msgid "On the receiving side:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: en/security/cryptography.md +#, no-wrap +msgid "Masking token length" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: en/security/cryptography.md +msgid "To mask a token:" +msgstr "" + +#. type: Fenced code block (php) +#: en/security/cryptography.md +#, no-wrap +msgid "$maskedToken = \\Yiisoft\\Security\\TokenMask::apply($token);\n" +msgstr "" + +#. type: Plain text +#: en/security/cryptography.md +msgid "To get the original value from the masked one:" +msgstr "" + +#. type: Fenced code block (php) +#: en/security/cryptography.md +#, no-wrap +msgid "$token = \\Yiisoft\\Security\\TokenMask::remove($maskedToken);\n" +msgstr "" diff --git a/_translations/po/it/guide_security_overview.md.po b/_translations/po/it/guide_security_overview.md.po new file mode 100644 index 00000000..a7c59f10 --- /dev/null +++ b/_translations/po/it/guide_security_overview.md.po @@ -0,0 +1,82 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: en/security/overview.md +#, no-wrap +msgid "Security" +msgstr "Sicurezza" + +#. 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 "" + +#. type: Bullet: '* ' +#: en/security/overview.md +#, fuzzy +#| msgid "[Authentication](security/authentication.md)" +msgid "[Authentication](authentication.md)" +msgstr "[Autenticazione](security/authentication.md)" + +#. type: Bullet: '* ' +#: en/security/overview.md +#, fuzzy +#| msgid "[Authentication](security/authentication.md)" +msgid "[Authorization](authorization.md)" +msgstr "[Autenticazione](security/authentication.md)" + +#. type: Bullet: '* ' +#: en/security/overview.md +#, fuzzy +#| msgid "[Working with passwords](security/passwords.md)" +msgid "[Working with Passwords](passwords.md)" +msgstr "[Lavorare con le password](security/passwords.md)" + +#. type: Bullet: '* ' +#: en/security/overview.md +#, fuzzy +#| msgid "[Cryptography](security/cryptography.md)" +msgid "[Cryptography](cryptography.md)" +msgstr "[Crittografia](security/cryptography.md)" + +#. type: Bullet: '* ' +#: en/security/overview.md +#, fuzzy +#| msgid "[Best practices](security/best-practices.md)" +msgid "[Best Practices](best-practices.md)" +msgstr "[Migliori pratiche](security/best-practices.md)" + +#. type: Bullet: '* ' +#: en/security/overview.md +#, fuzzy +#| msgid "[Request](runtime/request.md)" +msgid "[Trusted request](trusted-request.md)" +msgstr "[Richiesta](runtime/request.md)" + +#. type: Plain text +#: en/security/overview.md +msgid "See also:" +msgstr "" + +#. type: Bullet: '* ' +#: en/security/overview.md +#, fuzzy +#| msgid "[View](views/view.md)" +msgid "[Views security](../views/view.md#security)" +msgstr "[Vista](views/view.md)" diff --git a/_translations/po/it/guide_security_passwords.md.po b/_translations/po/it/guide_security_passwords.md.po new file mode 100644 index 00000000..ba313b94 --- /dev/null +++ b/_translations/po/it/guide_security_passwords.md.po @@ -0,0 +1,79 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: en/security/passwords.md +#, fuzzy, no-wrap +#| msgid "Working with databases" +msgid "Working with passwords" +msgstr "Lavorare con i database" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: en/security/passwords.md +msgid "To use it, you need to require the package first:" +msgstr "" + +#. type: Fenced code block +#: en/security/passwords.md +#, no-wrap +msgid "composer require yiisoft/security\n" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" diff --git a/_translations/po/it/guide_security_trusted-request.md.po b/_translations/po/it/guide_security_trusted-request.md.po new file mode 100644 index 00000000..bdee3b6f --- /dev/null +++ b/_translations/po/it/guide_security_trusted-request.md.po @@ -0,0 +1,77 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: en/security/trusted-request.md +#, no-wrap +msgid "Trusted request" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" diff --git a/_translations/po/it/guide_start_creating-project.md.po b/_translations/po/it/guide_start_creating-project.md.po new file mode 100644 index 00000000..c209a8d1 --- /dev/null +++ b/_translations/po/it/guide_start_creating-project.md.po @@ -0,0 +1,154 @@ +# Italian 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: \n" +"POT-Creation-Date: 2026-01-09 11:54+0000\n" +"PO-Revision-Date: 2026-01-10 21:35+0100\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.8\n" + +#. type: Title # +#: ../src/guide/start/creating-project.md +#, no-wrap +msgid "Creating a project" +msgstr "Creazione di un progetto" + +#. 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 "In questa guida forniremo comandi sia per [Docker](https://docs.docker.com/get-started/get-docker/) che per il server di sviluppo integrato con tutto installato 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 si desidera utilizzare un altro server web,\n" +"> consultare [\"Configurazione dei server 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 "Si consiglia di iniziare con un template di progetto che sia un progetto Yii minimale funzionante che implementa alcune funzionalità di base. Può fungere da buon punto di partenza per i propri progetti." + +#. 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 "È possibile creare un nuovo progetto da un template utilizzando il gestore di pacchetti [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 "Gli utenti Docker possono eseguire i seguenti comandi:" + +#. 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" +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" + +#. type: Plain text +#: ../src/guide/start/creating-project.md +msgid "If you want development version instead of release one:" +msgstr "Se vuoi la versione di sviluppo invece di quella di rilascio:" + +#. 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 "Questo installa l'ultima versione stabile del template di progetto Yii in una directory denominata `your_project`. È possibile scegliere un nome di directory diverso se lo si desidera." + +#. 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 si desidera installare l'ultima versione di sviluppo di Yii, è possibile aggiungere `--stability=dev` al comando.\n" +"> Non utilizzare la versione di sviluppo di Yii in produzione perché potrebbe compromettere il codice in esecuzione.\n" + +#. type: Plain text +#: ../src/guide/start/creating-project.md +msgid "Go into the newly created directory and run:" +msgstr "Accedere alla directory appena creata ed eseguire:" + +#. type: Fenced code block (sh) +#: ../src/guide/start/creating-project.md +#, no-wrap +msgid "APP_ENV=dev ./yii serve --port=80\n" +msgstr "APP_ENV=dev ./yii serve --port=80\n" + +#. type: Plain text +#: ../src/guide/start/creating-project.md +msgid "For Docker users, run:" +msgstr "Per gli utenti Docker, eseguire:" + +#. 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 "Aprire il browser all'URL `http://localhost/`." + +#. type: Plain text +#: ../src/guide/start/creating-project.md +#, no-wrap +msgid "" +"> [!NOTE]\n" +"> The HTTP server listens on port 80. If that port is already in use, specify the port via `--port` or, in case of Docker,\n" +"> `DEV_PORT` in the `docker/.env` file.\n" +msgstr "" +"> [!NOTE]\n" +"> Il server HTTP è in ascolto sulla porta 80. Se quella porta è già in uso, specificare la porta tramite `--port` o, nel caso di Docker,\n" +"> `DEV_PORT` nel file `docker/.env`.\n" + +#. type: Plain text +#: ../src/guide/start/creating-project.md +msgid "![Successful Installation of Yii](/images/guide/start/app-installed.png)" +msgstr "![Installazione riuscita di Yii](/images/guide/start/app-installed.png)" diff --git a/_translations/po/it/guide_start_databases.md.po b/_translations/po/it/guide_start_databases.md.po new file mode 100644 index 00000000..c2de5a35 --- /dev/null +++ b/_translations/po/it/guide_start_databases.md.po @@ -0,0 +1,1024 @@ +# Italian 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-12 12:47+0000\n" +"PO-Revision-Date: 2025-12-27 06:16+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. 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 "" + +#. 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 "" + +#. type: Title # +#: ../src/guide/index.md ../src/guide/start/databases.md +#, no-wrap +msgid "Working with databases" +msgstr "Lavorare con i database" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/guide/start/databases.md +#, fuzzy +#| msgid "[Json](https://github.com/yiisoft/json)" +msgid "[Yii DB](https://github.com/yiisoft/db)" +msgstr "[Json](https://github.com/yiisoft/json)" + +#. type: Bullet: '- ' +#: ../src/guide/start/databases.md +#, fuzzy +#| msgid "[Active Record](https://github.com/yiisoft/active-record/blob/master/README.md)" +msgid "[Yii Active Record](https://github.com/yiisoft/active-record)" +msgstr "[Active Record](https://github.com/yiisoft/active-record/blob/master/README.md)" + +#. type: Bullet: '- ' +#: ../src/guide/start/databases.md +msgid "[Cycle](https://github.com/cycle) via [Yii Cycle package](https://github.com/yiisoft/yii-cycle)" +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/guide/start/databases.md +msgid "[PDO](https://www.php.net/manual/en/book.pdo.php)" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "For non-relational ones, there are usually official libraries available:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/start/databases.md +#, fuzzy +#| msgid "[Strings](https://github.com/yiisoft/strings)" +msgid "[ElasticSearch](https://github.com/elastic/elasticsearch-php)" +msgstr "[Stringhe](https://github.com/yiisoft/strings)" + +#. type: Bullet: '- ' +#: ../src/guide/start/databases.md +msgid "[Redis](https://redis.io/docs/latest/develop/clients/php/)" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/guide/start/databases.md ../src/internals/000-packages.md +msgid "..." +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/start/databases.md +#, no-wrap +msgid "Installing PostgreSQL" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "If you use Docker, it is a bit simpler. Modify `docker/dev/compose.yml`:" +msgstr "" + +#. 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:-15}-alpine\n" +" environment:\n" +" POSTGRES_DB: app\n" +" POSTGRES_PASSWORD: password\n" +" POSTGRES_USER: user\n" +" volumes:\n" +" - ../runtime/db:/var/lib/postgresql/data: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" +"\n" +"volumes:\n" +" db:\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Note that we add `depends_on` so application waits for database to be up." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Also, we'll need a `pdo_pgsql` extension to communicate with PostgreSQL. You can enable it locally in `php.ini`. If you use Docker, check `docker/Dockerfile` and add `pdo_pgsql` in `install-php-extensions` list. Then rebuild PHP image with `make build && make down && make up`." +msgstr "" + +#. type: Title ## +#: ../src/guide/start/databases.md +#, fuzzy, no-wrap +#| msgid "[Configuration](concept/configuration.md)" +msgid "Configuring connection" +msgstr "[Configurazione](concept/configuration.md)" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Now that we have the database, it's time to define the connection." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "First we need a package to be installed:" +msgstr "" + +#. type: Fenced code block (sh) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "make composer require yiisoft/db-pgsql\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Now create `config/common/di/db-pgsql.php`:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "And define parameters in `config/common/params.php`. For Docker that would be:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "`db` host is resolved automatically within the Docker network." +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/start/databases.md +#, no-wrap +msgid "Creating and applying migrations" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "For the initial state of the application and for further database changes, it is a good idea to use migrations. These are files that create database changes. Applied migrations are tracked in the database, allowing us to know the current state and which migrations remain to be applied." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "To use migrations we need another package installed:" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Create a directory to store migrations `src/Migration` right in the project root. Add the following configuration to `config/common/params.php`:" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Now you can use `make yii migrate:create page` to create a new migration. For our example we need a `page` table with some columns:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Fenced code block (shell) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "make composer require ramsey/uuid\n" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Apply the migration with `make yii migrate:up`." +msgstr "" + +#. type: Title ## +#: ../src/guide/start/databases.md +#, no-wrap +msgid "An entity" +msgstr "" + +#. 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 "" + +#. type: Fenced code block (php) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "" +"toSlug($this->title);\n" +" }\n" +"}\n" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/start/databases.md ../src/guide/structure/domain.md +#: ../src/guide/structure/service.md +#, no-wrap +msgid "Repository" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Now that we have entity, we need a place for methods to save an entity, delete it and select either a single page or multiple pages." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Create `src/Web/Page/PageRepository.php`:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/start/databases.md +#, no-wrap +msgid "" +" $page->id,\n" +" 'title' => $page->title,\n" +" 'slug' => $page->getSlug(),\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}}', $data, ['id' => $page->id])->execute();\n" +" } else {\n" +" $this->connection->createCommand()->insert('{{%page}}', $data)->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" +" $data = $this->connection\n" +" ->select()\n" +" ->from('{{%page}}')\n" +" ->all();\n" +"\n" +" foreach ($data as $page) {\n" +" yield $this->createPage($page);\n" +" }\n" +" }\n" +"\n" +" private function createPage(?array $data): ?Page\n" +" {\n" +" if ($data === null) {\n" +" return null;\n" +" }\n" +"\n" +" return Page::create(\n" +" id: $data['id'],\n" +" title: $data['title'],\n" +" text: $data['text'],\n" +" createdAt: new DateTimeImmutable($data['created_at']),\n" +" updatedAt: new DateTimeImmutable($data['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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/start/databases.md +#, no-wrap +msgid "Actions and routes" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "We need some actions to:" +msgstr "" + +#. type: Bullet: '1. ' +#: ../src/guide/start/databases.md +msgid "List all pages." +msgstr "" + +#. type: Bullet: '2. ' +#: ../src/guide/start/databases.md +msgid "View a page." +msgstr "" + +#. type: Bullet: '3. ' +#: ../src/guide/start/databases.md +msgid "Delete a page." +msgstr "" + +#. type: Bullet: '4. ' +#: ../src/guide/start/databases.md +msgid "Create a page." +msgstr "" + +#. type: Bullet: '5. ' +#: ../src/guide/start/databases.md +msgid "Update a page." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Then we need routing for all these." +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Let's tackle these one by one." +msgstr "" + +#. type: Title ### +#: ../src/guide/start/databases.md +#, no-wrap +msgid "List all pages" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Create `src/Web/Page/ListAction.php`:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Define list view in `src/Web/Page/list.php`:" +msgstr "" + +#. 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->getSlug()])) ?>\n" +"
  • \n" +" \n" +"
\n" +"\n" +"generate('page/edit', ['slug' => 'new'])) ?>\n" +msgstr "" + +#. type: Title ### +#: ../src/guide/start/databases.md +#, no-wrap +msgid "View a page" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Create `src/Web/Page/ViewAction.php`:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Now, a template in `src/Web/Page/view.php`:" +msgstr "" + +#. 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->getSlug()])) ?> |\n" +"\n" +"\n" +"post($urlGenerator->generate('page/delete', ['slug' => $page->getSlug()]))\n" +" ->csrf($csrf);\n" +"?>\n" +"open() ?>\n" +" \n" +"close() ?>\n" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/start/databases.md +#, no-wrap +msgid "Delete a page" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Create `src/Web/Page/DeleteAction.php`:" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/start/databases.md +#, no-wrap +msgid "Create or update a page" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "First of all, we need a form at `src/Web/Page/Form.php`:" +msgstr "" + +#. 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" +" updatedAt: new DateTimeImmutable(),\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->getSlug()]),\n" +" );\n" +" }\n" +"\n" +" return $this->viewRenderer->render(__DIR__ . '/edit', [\n" +" 'form' => $form,\n" +" 'isNew' => $isNew,\n" +" 'slug' => $slug,\n" +" ]);\n" +" }\n" +"}\n" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Now, a template in `src/Web/Page/edit.php`:" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/start/databases.md +#, no-wrap +msgid "Routing" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Adjust `config/common/routes.php`:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/start/databases.md +#, no-wrap +msgid "Trying it out" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/databases.md +msgid "Now try it out by opening `http://localhost/pages` in your browser." +msgstr "" diff --git a/_translations/po/it/guide_start_forms.md.po b/_translations/po/it/guide_start_forms.md.po new file mode 100644 index 00000000..ea82dbfd --- /dev/null +++ b/_translations/po/it/guide_start_forms.md.po @@ -0,0 +1,340 @@ +# Italian 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-26 22:37+0000\n" +"PO-Revision-Date: 2025-12-26 22:37+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/guide/start/forms.md +#, fuzzy, no-wrap +#| msgid "Working with databases" +msgid "Working with forms" +msgstr "Lavorare con i database" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "Through this tutorial, you will learn how to:" +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/start/forms.md +msgid "Create a form model to represent the data entered by a user through a form." +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/start/forms.md +msgid "Declare rules to validate the data entered." +msgstr "" + +#. type: Bullet: '* ' +#: ../src/guide/start/forms.md +msgid "Build an HTML form in a view." +msgstr "" + +#. type: Title ## +#: ../src/guide/start/forms.md +#, no-wrap +msgid "Installing form package" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "To install form package, issue the following command in your application directory:" +msgstr "" + +#. type: Fenced code block +#: ../src/guide/start/forms.md +#, no-wrap +msgid "composer require yiisoft/form-model\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "For Docker that would be:" +msgstr "" + +#. type: Fenced code block +#: ../src/guide/start/forms.md +#, no-wrap +msgid "make composer require yiisoft/form-model\n" +msgstr "" + +#. type: Title ## +#: ../src/guide/start/forms.md +#, no-wrap +msgid "Creating a form " +msgstr "" + +#. 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/App/Web/Echo/Form.php`:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/start/forms.md +#, no-wrap +msgid "" +" " +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "Here's what you end up with in `/src/Web/Echo/Action.php`:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/start/forms.md +#, no-wrap +msgid "Adjusting view" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/start/forms.md +#, no-wrap +msgid "Trying it Out " +msgstr "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "To see how it works, use your browser to access the following URL:" +msgstr "" + +#. type: Fenced code block +#: ../src/guide/start/forms.md +#, no-wrap +msgid "http://localhost:8080/say\n" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "![Form with a validation error](/images/guide/start/form-error.png)" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/start/forms.md +msgid "![Form with a success message](/images/guide/start/form-success.png)" +msgstr "" + +#. type: Title ## +#: ../src/guide/start/forms.md ../src/guide/start/hello.md +#, no-wrap +msgid "Summary " +msgstr "Riepilogo " + +#. 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 "" + +#. 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 "" + +#. 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 "" diff --git a/_translations/po/it/guide_start_gii.md.po b/_translations/po/it/guide_start_gii.md.po new file mode 100644 index 00000000..a0f3def8 --- /dev/null +++ b/_translations/po/it/guide_start_gii.md.po @@ -0,0 +1,24 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/guide/start/gii.md +#, fuzzy, no-wrap +#| msgid "Generating code using Gii" +msgid "Generating code with Gii" +msgstr "Generare codice utilizzando Gii" diff --git a/_translations/po/it/guide_start_hello.md.po b/_translations/po/it/guide_start_hello.md.po new file mode 100644 index 00000000..3a77b87b --- /dev/null +++ b/_translations/po/it/guide_start_hello.md.po @@ -0,0 +1,364 @@ +# Italian 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: \n" +"POT-Creation-Date: 2025-12-25 21:55+0000\n" +"PO-Revision-Date: 2026-01-07 20:45+0100\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.8\n" + +#. type: Title ## +#: ../src/guide/start/forms.md ../src/guide/start/hello.md +#, no-wrap +msgid "Summary " +msgstr "Riepilogo " + +#. type: Title # +#: ../src/guide/start/hello.md +#, no-wrap +msgid "Saying hello" +msgstr "Dire ciao" + +#. 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 "Questa sezione descrive come creare una nuova pagina “Hello” nella tua applicazione. È una pagina semplice che restituirà tutto ciò che le passi o, se non viene passato nulla, dirà semplicemente \"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 "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." + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "Through this tutorial, you will learn three things:" +msgstr "Attraverso questo tutorial, imparerai tre cose:" + +#. type: Bullet: '1. ' +#: ../src/guide/start/hello.md +msgid "How to create a handler to respond to a request." +msgstr "Come creare un gestore di richieste per rispondere a una richiesta." + +#. type: Bullet: '2. ' +#: ../src/guide/start/hello.md +msgid "How to map URL to the handler." +msgstr "Come mappare l'URL al gestore di richieste." + +#. type: Bullet: '3. ' +#: ../src/guide/start/hello.md +msgid "How to use [view](../views/view.md) to compose the response's content." +msgstr "Come usare [una vista](../views/view.md) per comporre il contenuto della risposta." + +#. type: Title ## +#: ../src/guide/start/hello.md +#, no-wrap +msgid "Creating a handler " +msgstr "Creare un gestore di richieste " + +#. 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 "Per il compito \"Hello\", creerai una classe gestore di richieste che legge un parametro `message` dalla richiesta e visualizza quel messaggio all'utente. Se la richiesta non fornisce un parametro `message`, l'azione visualizzerà il messaggio \"Hello\" predefinito." + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "Create `src/Web/Echo/Action.php`:" +msgstr "Crea `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 "Nel tuo esempio, il metodo `__invoke` riceve il parametro `$message` che con l'aiuto dell'attributo `RouteArgument` ottiene il messaggio dall'URL. Il valore predefinito è `\"Hello!\"`. Se la richiesta viene effettuata a `/say/Goodbye`, l'azione assegna il valore \"Goodbye\" alla variabile `$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 "L'applicazione passa la risposta attraverso lo [stack di middleware](../structure/middleware.md) all'emettitore che invia la risposta all'utente finale." + +#. type: Title ## +#: ../src/guide/start/hello.md +#, no-wrap +msgid "Configuring router" +msgstr "Configurazione del 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 "Ora, per mappare il tuo gestore di richieste all'URL, devi aggiungere una rotta in `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` request attribute. `[]` marks this part of the pattern as optional." +msgstr "Nell'esempio sopra, mappi il pattern `/say[/{message}]` a `\\App\\Web\\Echo\\Action`. Per una richiesta, il router crea un'istanza e chiama il metodo `__invoke()`. La parte `{message}` del pattern scrive tutto ciò che viene specificato in questa posizione nell'attributo `message` della richiesta. `[]` marca questa parte del pattern come facoltativa." + +#. 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 "Dai anche un nome `echo/say` a questa rotta per poter generare URL che puntano ad essa." + +#. type: Title ## +#: ../src/guide/start/hello.md +#, no-wrap +msgid "Trying it out " +msgstr "Provarlo " + +#. 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 "Dopo aver creato l'azione e la vista apri `http://localhost/say/Hello+World` nel tuo browser." + +#. type: Plain text +#: ../src/guide/start/hello.md +msgid "This URL displays a page with \"The message is: Hello World\"." +msgstr "Questo URL visualizza una pagina con “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 ometti il parametro `message` nell'URL, la pagina visualizza “The message is: Hello!\"." + +#. type: Title ## +#: ../src/guide/start/hello.md +#, no-wrap +msgid "Creating a View Template " +msgstr "Creare un modello di vista " + +#. 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 "Solitamente, il compito è più complicato che stampare \"hello world\" e comporta il rendering di HTML complesso. Per questo compito, è utile usare modelli di vista. Sono script che scrivi per generare il corpo della risposta." + +#. 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 "Per il compito \"Hello\", crea un modello `src/Web/Echo/template.php` che stampa il parametro `message` ricevuto dal metodo dell'azione:" + +#. 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 "Nel codice sopra, il parametro `message` utilizza la codifica HTML prima di stamparlo. Questo è necessario perché il parametro proviene da un utente finale ed è vulnerabile ad [attacchi cross-site scripting (XSS)](https://en.wikipedia.org/wiki/Cross-site_scripting) tramite l'incorporamento di JavaScript malevolo nel parametro." + +#. 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, puoi inserire più contenuto nella vista `say`. Il contenuto può consistere di tag HTML, testo semplice e persino istruzioni PHP. Infatti, il servizio di vista esegue la vista `say` come uno 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 "Per usare la vista, devi modificare `src/Web/Echo/Action.php`:" + +#. type: Fenced code block (php) +#: ../src/guide/start/hello.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 "Ora apri il tuo browser e controllalo di nuovo. Dovresti vedere il testo simile ma con un layout applicato." + +#. 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 "Inoltre, hai separato la parte su come funziona e la parte su come viene presentata. Nelle applicazioni più grandi, questo aiuta molto a gestire la complessità." + +#. 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 "In questa sezione, hai toccato le parti del gestore di richieste e del modello della tipica applicazione web. Hai creato un gestore di richieste come parte di una classe per gestire una richiesta specifica. Hai anche creato una vista per comporre il contenuto della risposta. In questo semplice esempio, non è stata coinvolta alcuna fonte di dati poiché l'unico dato utilizzato era il parametro `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 "Hai anche imparato sul routing in Yii, che funge da ponte tra le richieste utente e i gestori di richieste." + +#. 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 "Nella prossima sezione, imparerai come recuperare dati e aggiungere una nuova pagina contenente un modulo HTML." diff --git a/_translations/po/it/guide_start_looking-ahead.md.po b/_translations/po/it/guide_start_looking-ahead.md.po new file mode 100644 index 00000000..ca74172d --- /dev/null +++ b/_translations/po/it/guide_start_looking-ahead.md.po @@ -0,0 +1,28 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/guide/start/looking-ahead.md +#, no-wrap +msgid "Looking ahead" +msgstr "" + +#. 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 "" diff --git a/_translations/po/it/guide_start_prerequisites.md.po b/_translations/po/it/guide_start_prerequisites.md.po new file mode 100644 index 00000000..bae2f91b --- /dev/null +++ b/_translations/po/it/guide_start_prerequisites.md.po @@ -0,0 +1,99 @@ +# Italian 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: \n" +"POT-Creation-Date: 2025-12-24 13:00+0000\n" +"PO-Revision-Date: 2026-01-06 18:00+0100\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.8\n" + +#. type: Title ## +#: ../src/guide/intro/upgrade-from-v2.md ../src/guide/start/prerequisites.md +#, no-wrap +msgid "Docker" +msgstr "Docker" + +#. type: Title # +#: ../src/guide/start/prerequisites.md +#, no-wrap +msgid "What do you need to know?" +msgstr "Cosa devi sapere?" + +#. 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 "La curva di apprendimento di Yii non è così ripida come quella di altri framework PHP, ma ci sono comunque alcune cose che dovresti imparare prima di iniziare a usare 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 "Yii è un framework PHP, quindi assicurarsi di [leggere e comprendere il riferimento del linguaggio](https://www.php.net/manual/en/langref.php)." + +#. type: Title ## +#: ../src/guide/start/prerequisites.md +#, no-wrap +msgid "Object-oriented programming" +msgstr "Programmazione orientata agli oggetti" + +#. 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 "È necessaria una conoscenza di base della programmazione orientata agli oggetti. Se non si ha familiarità con questo argomento, consultare uno dei numerosi tutorial disponibili, [come quello offerto da 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 "Quando si sviluppa con Yii, si scrive codice in modo orientato agli oggetti, quindi assicurarsi di avere familiarità con il [supporto OOP di PHP](https://www.php.net/manual/en/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 "Si noti che più l'applicazione è complessa, più concetti OOP avanzati si dovrebbero apprendere per gestire con successo tale complessità." + +#. type: Title ## +#: ../src/guide/start/prerequisites.md +#, no-wrap +msgid "Command line and Composer" +msgstr "Riga di 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 "Yii utilizza ampiamente il gestore di pacchetti PHP standard de facto, [Composer](https://getcomposer.org), quindi assicurarsi di leggere e comprendere la sua [guida](https://getcomposer.org/doc/01-basic-usage.md). Se non si ha familiarità con l'uso della riga di comando, è il momento di iniziare a provarla. Una volta appresi i concetti di base, non si vorrà più farne a meno." + +#. 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 "Poiché Yii è un framework web e il web utilizza principalmente HTTP, è consigliabile [saperne di più](https://developer.mozilla.org/en-US/docs/Web/HTTP)." + +#. 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 "Il modello di applicazione predefinito sfrutta Docker, pertanto ti consigliamo di [leggere e comprendere i concetti](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 "Inoltre, sarà utile familiarizzare con i principi della [twelve-factor app](https://12factor.net/)." diff --git a/_translations/po/it/guide_start_workflow.md.po b/_translations/po/it/guide_start_workflow.md.po new file mode 100644 index 00000000..f2e3690e --- /dev/null +++ b/_translations/po/it/guide_start_workflow.md.po @@ -0,0 +1,196 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/guide/start/workflow.md +#, fuzzy, no-wrap +#| msgid "[Running applications](start/workflow.md)" +msgid "Running applications" +msgstr "[Applicazioni in esecuzione](start/workflow.md)" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/start/workflow.md +#, no-wrap +msgid "Functionality " +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/start/workflow.md +#, no-wrap +msgid "" +"\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/start/workflow.md +msgid "In addition to the web application, you can access a console script via `APP_ENV=dev ./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 "" + +#. type: Title ## +#: ../src/guide/start/workflow.md +#, fuzzy, no-wrap +#| msgid "[Application](structure/application.md)" +msgid "Application structure " +msgstr "[Applicazione](structure/application.md)" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/start/workflow.md +#, no-wrap +msgid "Request Lifecycle " +msgstr "" + +#. type: Plain text +#: ../src/guide/start/workflow.md +msgid "The following diagram shows how an application handles a request." +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '5. ' +#: ../src/guide/start/workflow.md +msgid "The Router finds out what handler to execute based on request and configuration." +msgstr "" + +#. type: Bullet: '6. ' +#: ../src/guide/start/workflow.md +msgid "The handler may load some data, possibly from a database." +msgstr "" + +#. 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 "" + +#. 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 "" diff --git a/_translations/po/it/guide_structure_action.md.po b/_translations/po/it/guide_structure_action.md.po new file mode 100644 index 00000000..62ef0a1c --- /dev/null +++ b/_translations/po/it/guide_structure_action.md.po @@ -0,0 +1,179 @@ +# Italian 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 16:53+0000\n" +"PO-Revision-Date: 2025-09-04 11:19+0500\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/guide/structure/action.md +#, no-wrap +msgid "Actions" +msgstr "Azioni" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/structure/action.md +msgid "The class itself would be like:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/structure/action.md +msgid "The class itself would look like the following:" +msgstr "" + +#. 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 PostController\n" +"{\n" +" public function actionIndex(ServerRequestInterface $request): ResponseInterface\n" +" {\n" +" // render posts list\n" +" }\n" +" \n" +" \n" +" public function actionView(ServerRequestInterface $request): ResponseInterface\n" +" {\n" +" // render a single post \n" +" }\n" +"}\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/action.md +msgid "We usually call such a class \"controller.\"" +msgstr "" + +#. type: Title ## +#: ../src/guide/structure/action.md +#, no-wrap +msgid "Autowiring" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" diff --git a/_translations/po/it/guide_structure_application.md.po b/_translations/po/it/guide_structure_application.md.po new file mode 100644 index 00000000..a3b25d11 --- /dev/null +++ b/_translations/po/it/guide_structure_application.md.po @@ -0,0 +1,49 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/guide/structure/application.md +#, fuzzy, no-wrap +#| msgid "Application structure" +msgid "Application" +msgstr "Struttura applicativa" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/structure/application.md +msgid "Typically, the runtime consists of:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '3. ' +#: ../src/guide/structure/application.md +msgid "Shutdown. Fire `ApplicationShutdown` event." +msgstr "" diff --git a/_translations/po/it/guide_structure_domain.md.po b/_translations/po/it/guide_structure_domain.md.po new file mode 100644 index 00000000..3626564e --- /dev/null +++ b/_translations/po/it/guide_structure_domain.md.po @@ -0,0 +1,188 @@ +# Italian 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-11-02 16:25+0000\n" +"PO-Revision-Date: 2025-11-02 16:25+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title ## +#: ../../guide/en/concept/autoloading.md +#: ../../guide/en/security/best-practices.md ../../guide/en/structure/domain.md +#: ../../guide/en/tutorial/console-applications.md +#, no-wrap +msgid "References" +msgstr "" + +#. type: Bullet: '- ' +#: ../../guide/en/start/databases.md ../../guide/en/structure/domain.md +#: ../../guide/en/structure/service.md +#, no-wrap +msgid "Repository" +msgstr "" + +#. type: Title # +#: ../../guide/en/structure/domain.md +#, no-wrap +msgid "Domain" +msgstr "" + +#. type: Plain text +#: ../../guide/en/structure/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 "" + +#. type: Plain text +#: ../../guide/en/structure/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 "" + +#. type: Title ## +#: ../../guide/en/structure/domain.md +#, no-wrap +msgid "Bounded context" +msgstr "" + +#. type: Plain text +#: ../../guide/en/structure/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 "" + +#. type: Title ## +#: ../../guide/en/structure/domain.md +#, no-wrap +msgid "Building blocks" +msgstr "" + +#. type: Plain text +#: ../../guide/en/structure/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 "" + +#. type: Bullet: '- ' +#: ../../guide/en/structure/domain.md ../../guide/en/structure/service.md +#, no-wrap +msgid "Entity" +msgstr "" + +#. type: Plain text +#: ../../guide/en/structure/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 "" + +#. type: Title ### +#: ../../guide/en/structure/domain.md +#, no-wrap +msgid "Value object" +msgstr "" + +#. type: Plain text +#: ../../guide/en/structure/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 "" + +#. type: Title ### +#: ../../guide/en/structure/domain.md +#, no-wrap +msgid "Aggregate" +msgstr "" + +#. type: Plain text +#: ../../guide/en/structure/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 "" + +#. type: Plain text +#: ../../guide/en/structure/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 "" + +#. type: Title ### +#: ../../guide/en/structure/domain.md +#, no-wrap +msgid "Domain event" +msgstr "" + +#. type: Plain text +#: ../../guide/en/structure/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 "" + +#. type: Title ### +#: ../../guide/en/structure/domain.md +#, no-wrap +msgid "Data transfer object" +msgstr "" + +#. type: Plain text +#: ../../guide/en/structure/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 "" + +#. type: Title ### +#: ../../guide/en/structure/domain.md +#, no-wrap +msgid "Service" +msgstr "" + +#. type: Plain text +#: ../../guide/en/structure/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 "" + +#. type: Plain text +#: ../../guide/en/structure/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 "" + +#. type: Plain text +#: ../../guide/en/structure/domain.md +msgid "Repository is usually implemented as a service." +msgstr "" + +#. type: Title ### +#: ../../guide/en/structure/domain.md +#, no-wrap +msgid "Instantiating building blocks" +msgstr "" + +#. type: Plain text +#: ../../guide/en/structure/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 "" + +#. type: Bullet: '- ' +#: ../../guide/en/structure/domain.md +msgid "[BoundedContext by Martin Fowler](https://martinfowler.com/bliki/BoundedContext.html)" +msgstr "" + +#. type: Bullet: '- ' +#: ../../guide/en/structure/domain.md +msgid "[ValueObject by Martin Fowler](https://martinfowler.com/bliki/ValueObject.html)" +msgstr "" + +#. type: Bullet: '- ' +#: ../../guide/en/structure/domain.md +msgid "[Aggregate by Marting Fowler](https://martinfowler.com/bliki/DDD_Aggregate.html)" +msgstr "" diff --git a/_translations/po/it/guide_structure_entry-script.md.po b/_translations/po/it/guide_structure_entry-script.md.po new file mode 100644 index 00000000..f3ad9ed5 --- /dev/null +++ b/_translations/po/it/guide_structure_entry-script.md.po @@ -0,0 +1,198 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: en/structure/entry-script.md +#, no-wrap +msgid "Entry scripts" +msgstr "" + +#. type: Plain text +#: en/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 "" + +#. type: Plain text +#: en/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 "" + +#. type: Plain text +#: en/structure/entry-script.md +msgid "Entry script for console application is `./yii`." +msgstr "" + +#. type: Plain text +#: en/structure/entry-script.md +msgid "Entry scripts mainly perform the following work with the help of `ApplicationRunner`:" +msgstr "" + +#. type: Bullet: '* ' +#: en/structure/entry-script.md +msgid "Register [Composer autoloader](https://getcomposer.org/doc/01-basic-usage.md#autoloading);" +msgstr "" + +#. type: Bullet: '* ' +#: en/structure/entry-script.md +msgid "Obtain configuration;" +msgstr "" + +#. type: Bullet: '* ' +#: en/structure/entry-script.md +msgid "Use configuration to initialize a dependency injection container;" +msgstr "" + +#. type: Bullet: '* ' +#: en/structure/entry-script.md +msgid "Get an instance of the request." +msgstr "" + +#. type: Bullet: '* ' +#: en/structure/entry-script.md +msgid "Pass it to `Application` to handle and get a response from it." +msgstr "" + +#. type: Bullet: '* ' +#: en/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 "" + +#. type: Title ## +#: en/structure/entry-script.md +#, no-wrap +msgid "Web Applications " +msgstr "" + +#. type: Plain text +#: en/structure/entry-script.md +msgid "The following is the code in the entry script for the application template:" +msgstr "" + +#. type: Fenced code block (php) +#: en/structure/entry-script.md +#, no-wrap +msgid "" +"debug();\n" +"// Run application:\n" +"$runner->run();\n" +msgstr "" + +#. type: Title ## +#: en/structure/entry-script.md +#, fuzzy, no-wrap +#| msgid "[Console applications](tutorial/console-applications.md)" +msgid "Console Applications " +msgstr "[Applicazioni console](tutorial/console-applications.md)" + +#. type: Plain text +#: en/structure/entry-script.md +msgid "Similarly, the following is the code for the entry script of a console application:" +msgstr "" + +#. type: Fenced code block (php) +#: en/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 "" + +#. type: Title ## +#: en/structure/entry-script.md +#, no-wrap +msgid "Alternative runtimes" +msgstr "" + +#. type: Plain text +#: en/structure/entry-script.md +msgid "For alternative runtimes such as RoadRunner or Swoole, special entry scripts should be used. See:" +msgstr "" + +#. type: Bullet: '- ' +#: en/structure/entry-script.md +#, fuzzy +#| msgid "[Using Yii with RoadRunner](tutorial/using-yii-with-roadrunner.md)" +msgid "[Using Yii with RoadRunner](../tutorial/using-yii-with-roadrunner.md)" +msgstr "[Usare Yii con RoadRunner](tutorial/using-yii-with-roadrunner.md)" + +#. type: Bullet: '- ' +#: en/structure/entry-script.md +#, fuzzy +#| msgid "[Using Yii with Swoole](tutorial/using-yii-with-swoole.md)" +msgid "[Using Yii with Swoole](../tutorial/using-yii-with-swoole.md)" +msgstr "[Usare Yii con Swoole](tutorial/using-yii-with-swoole.md)" diff --git a/_translations/po/it/guide_structure_handler.md.po b/_translations/po/it/guide_structure_handler.md.po new file mode 100644 index 00000000..11daf269 --- /dev/null +++ b/_translations/po/it/guide_structure_handler.md.po @@ -0,0 +1,23 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: en/structure/handler.md +#, no-wrap +msgid "Request handlers" +msgstr "" diff --git a/_translations/po/it/guide_structure_middleware.md.po b/_translations/po/it/guide_structure_middleware.md.po new file mode 100644 index 00000000..aa62d43b --- /dev/null +++ b/_translations/po/it/guide_structure_middleware.md.po @@ -0,0 +1,375 @@ +# Italian 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 14:31+0000\n" +"PO-Revision-Date: 2025-12-24 10:12+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "Middleware" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/guide/structure/middleware.md +msgid "Pass the request to the next middleware performing some work before / after it." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/structure/middleware.md +msgid "Form the response and return it." +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "Depending on middleware used, application behavior may vary significantly." +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +#, fuzzy +#| msgid "[Middleware](structure/middleware.md)" +msgid "![Middleware](/images/guide/middleware.svg)" +msgstr "[Middleware](structure/middleware.md)" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +#, fuzzy +#| msgid "[Middleware](structure/middleware.md)" +msgid "![Middleware](/images/guide/middleware_alternative.svg)" +msgstr "[Middleware](structure/middleware.md)" + +#. type: Title ## +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "Using middleware" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "Now register the middleware in DI container configuration `config/web.php`:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "In the `config/routes.php`, add new route:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "The action itself could be the following:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "To apply middleware to application overall regardless of URL, adjust `config/application.php`:" +msgstr "" + +#. 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" +" CsrfMiddleware::class,\n" +" Router::class,\n" +" ]\n" +" );\n" +" }),\n" +" 'fallbackHandler' => Reference::to(NotFoundHandler::class),\n" +" ],\n" +" ],\n" +"];\n" +msgstr "" + +#. type: Title ## +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "Creating your own middleware" +msgstr "" + +#. 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 "" + +#. type: Fenced code block (php) +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface;\n" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "Forming a response directly" +msgstr "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "To respond directly, one needs a response factory passed via constructor:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/structure/middleware.md +#, fuzzy, no-wrap +#| msgid "" +#| "responseFactory->createResponse();\n" +#| " $response->getBody()->write('The message is: ' . Html::encode($message));\n" +#| " return $response;\n" +#| " }\n" +#| "}\n" +msgid "" +"responseFactory->createResponse();\n" +" $response->getBody()->write('Hello!');\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: Title ### +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "Delegating handling to the next middleware" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/structure/middleware.md +msgid "To get it in the next middleware:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "$answer = $request->getAttribute('answer');\n" +msgstr "" + +#. type: Title ### +#: ../src/guide/structure/middleware.md +#, no-wrap +msgid "Capturing response to manipulate it" +msgstr "" + +#. 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 "" + +#. 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 "" diff --git a/_translations/po/it/guide_structure_overview.md.po b/_translations/po/it/guide_structure_overview.md.po new file mode 100644 index 00000000..edb6c96e --- /dev/null +++ b/_translations/po/it/guide_structure_overview.md.po @@ -0,0 +1,163 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title ## +#: ../src/en/guide/structure/overview.md +#: ../src/en/guide/views/script-style-meta.md +#, no-wrap +msgid "Overview" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/en/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 +msgid "Customer" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Profile" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Products list" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Checkout" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/guide/structure/overview.md +msgid "Logistics" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/guide/structure/overview.md +msgid "Delivery" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Addresses" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/guide/structure/overview.md +#, fuzzy +#| msgid "Helpers" +msgid "Helpdesk" +msgstr "Helper" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Support" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Claims" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Returns" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/guide/structure/overview.md +msgid "Accounting" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Transactions" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/en/guide/structure/overview.md +msgid "Taxes" +msgstr "" + +#. type: Plain text +#: ../src/en/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 +#, 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/en/guide/structure/overview.md +msgid "Besides, Yii applications also have the following:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" diff --git a/_translations/po/it/guide_structure_package.md.po b/_translations/po/it/guide_structure_package.md.po new file mode 100644 index 00000000..89580896 --- /dev/null +++ b/_translations/po/it/guide_structure_package.md.po @@ -0,0 +1,342 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: en/structure/package.md +#, no-wrap +msgid "Packages" +msgstr "" + +#. type: Plain text +#: en/structure/package.md +msgid "Reusable code could be released as [a Composer package](https://getcomposer.org/doc/05-repositories.md#package). It could be an infrastructure library, a module representing one of the application contexts or, basically, any reusable code." +msgstr "" + +#. type: Title ## +#: en/structure/package.md +#, no-wrap +msgid "Using packages " +msgstr "" + +#. type: Plain text +#: en/structure/package.md +msgid "By default, Composer installs packages registered on [Packagist](https://packagist.org/) — the biggest repository for open source PHP packages. You can look for packages on Packagist. You may also [create your own repository](https://getcomposer.org/doc/05-repositories.md#repository) and configure Composer to use it. This is useful if you're developing private packages that you want to share within your projects only." +msgstr "" + +#. type: Plain text +#: en/structure/package.md +msgid "Packages installed by Composer are stored in the `vendor` directory of your project. Because the Composer is a dependency manager, when it installs a package, it will also install all its dependent packages." +msgstr "" + +#. type: Plain text +#: en/structure/package.md +#, no-wrap +msgid "" +"> [!WARNING]\n" +"> `vendor` directory of your application should never be modified.\n" +msgstr "" + +#. type: Plain text +#: en/structure/package.md +msgid "A package could be installed with the following command:" +msgstr "" + +#. type: Fenced code block +#: en/structure/package.md +#, no-wrap +msgid "composer install vendor-name/package-name\n" +msgstr "" + +#. type: Plain text +#: en/structure/package.md +msgid "After it's done, Composer modifies `composer.json` and `composer.lock`. The former defines what packages to install, and their version constraints the latter stores a snapshot of exact versions actually installed." +msgstr "" + +#. type: Plain text +#: en/structure/package.md +msgid "Classes from the package will be available immediately via [autoloading](../concept/autoloading.md)." +msgstr "" + +#. type: Title ## +#: en/structure/package.md +#, no-wrap +msgid "Creating packages " +msgstr "" + +#. type: Plain text +#: en/structure/package.md +msgid "You may consider creating a package when you feel the need to share with other people your great code. A package can contain any code you like, such as a helper class, a widget, a service, middleware, the whole module, etc." +msgstr "" + +#. type: Plain text +#: en/structure/package.md +msgid "Below are the basic steps you may follow." +msgstr "" + +#. type: Bullet: '1. ' +#: en/structure/package.md +msgid "Create a project for your package and host it on a VCS repository, such as [GitHub.com](https://github.com). The development and maintenance work for the package should be done on this repository." +msgstr "" + +#. type: Bullet: '2. ' +#: en/structure/package.md +msgid "Under the root directory of the project, create a file named `composer.json` as required by Composer. Please refer to the next subsection for more details." +msgstr "" + +#. type: Bullet: '3. ' +#: en/structure/package.md +msgid "Register your package with a Composer repository, such as [Packagist](https://packagist.org/), so that other users can find and install your package using Composer." +msgstr "" + +#. type: Title ### +#: en/structure/package.md +#, no-wrap +msgid "`composer.json` " +msgstr "" + +#. type: Plain text +#: en/structure/package.md +msgid "Each Composer package must have a `composer.json` file in its root directory. The file contains the metadata about the package. You may find the complete specification about this file in the [Composer Manual](https://getcomposer.org/doc/01-basic-usage.md#composer-json-project-setup). The following example shows the `composer.json` file for the `yiisoft/yii-widgets` package:" +msgstr "" + +#. type: Fenced code block (json) +#: en/structure/package.md +#, no-wrap +msgid "" +"{\n" +" \"name\": \"yiisoft/yii-widgets\",\n" +" \"type\": \"library\",\n" +" \"description\": \"Yii widgets collection\",\n" +" \"keywords\": [\n" +" \"yii\",\n" +" \"widgets\"\n" +" ],\n" +" \"homepage\": \"https://www.yiiframework.com/\",\n" +" \"license\": \"BSD-3-Clause\",\n" +" \"support\": {\n" +" \"issues\": \"https://github.com/yiisoft/yii-widgets/issues?state=open\",\n" +" \"forum\": \"https://www.yiiframework.com/forum/\",\n" +" \"wiki\": \"https://www.yiiframework.com/wiki/\",\n" +" \"irc\": \"ircs://irc.libera.chat:6697/yii\",\n" +" \"chat\": \"https://t.me/yii3en\",\n" +" \"source\": \"https://github.com/yiisoft/yii-widgets\"\n" +" },\n" +" \"funding\": [\n" +" {\n" +" \"type\": \"opencollective\",\n" +" \"url\": \"https://opencollective.com/yiisoft\"\n" +" },\n" +" {\n" +" \"type\": \"github\",\n" +" \"url\": \"https://github.com/sponsors/yiisoft\"\n" +" }\n" +" ],\n" +" \"require\": {\n" +" \"php\": \"^7.4|^8.0\",\n" +" \"yiisoft/aliases\": \"^1.1|^2.0\",\n" +" \"yiisoft/cache\": \"^1.0\",\n" +" \"yiisoft/html\": \"^2.0\",\n" +" \"yiisoft/view\": \"^4.0\",\n" +" \"yiisoft/widget\": \"^1.0\"\n" +" },\n" +" \"require-dev\": {\n" +" \"phpunit/phpunit\": \"^9.5\",\n" +" \"roave/infection-static-analysis-plugin\": \"^1.16\",\n" +" \"spatie/phpunit-watcher\": \"^1.23\",\n" +" \"vimeo/psalm\": \"^4.18\",\n" +" \"yiisoft/psr-dummy-provider\": \"^1.0\",\n" +" \"yiisoft/test-support\": \"^1.3\"\n" +" },\n" +" \"autoload\": {\n" +" \"psr-4\": {\n" +" \"Yiisoft\\\\Yii\\\\Widgets\\\\\": \"src\"\n" +" }\n" +" },\n" +" \"autoload-dev\": {\n" +" \"psr-4\": {\n" +" \"Yiisoft\\\\Yii\\\\Widgets\\\\Tests\\\\\": \"tests\"\n" +" }\n" +" },\n" +" \"extra\": {\n" +" \"branch-alias\": {\n" +" \"dev-master\": \"3.0.x-dev\"\n" +" }\n" +" },\n" +" \"scripts\": {\n" +" \"test\": \"phpunit --testdox --no-interaction\",\n" +" \"test-watch\": \"phpunit-watcher watch\"\n" +" },\n" +" \"config\": {\n" +" \"sort-packages\": true,\n" +" \"allow-plugins\": {\n" +" \"infection/extension-installer\": true,\n" +" \"composer/package-versions-deprecated\": true\n" +" }\n" +" }\n" +"}\n" +msgstr "" + +#. type: Title #### +#: en/structure/package.md +#, no-wrap +msgid "Package Name " +msgstr "" + +#. type: Plain text +#: en/structure/package.md +msgid "Each Composer package should have a package name which uniquely identifies the package among all others. The format of package names is `vendorName/projectName`. For example, in the package name `yiisoft/queue`, the vendor name, and the project name are `yiisoft` and `queue`, respectively." +msgstr "" + +#. type: Plain text +#: en/structure/package.md +#, no-wrap +msgid "" +"> [!WARNING]\n" +"> Don't use `yiisoft` as your vendor name as it's reserved for use by the Yii itself.\n" +msgstr "" + +#. type: Plain text +#: en/structure/package.md +msgid "We recommend you prefix `yii-` to the project name for packages that aren't able to work as general PHP packages and require Yii application. This will allow users to more easily tell whether a package is Yii specific." +msgstr "" + +#. type: Title #### +#: en/structure/package.md +#, no-wrap +msgid "Dependencies " +msgstr "" + +#. type: Plain text +#: en/structure/package.md +msgid "If your extension depends on other packages, you should list them in `require` section of `composer.json`. Make sure you also list appropriate version constraints (e.g. `^1.0`, `@stable`) for each dependent package. Use stable dependencies when your extension is released in a stable version." +msgstr "" + +#. type: Title #### +#: en/structure/package.md +#, no-wrap +msgid "Class Autoloading " +msgstr "" + +#. type: Plain text +#: en/structure/package.md +msgid "In order for your classes to be autoloaded, you should specify the `autoload` entry in the `composer.json` file, like shown below:" +msgstr "" + +#. type: Fenced code block (json) +#: en/structure/package.md +#, no-wrap +msgid "" +"{\n" +" // ....\n" +"\n" +" \"autoload\": {\n" +" \"psr-4\": {\n" +" \"MyVendorName\\\\MyPackageName\\\\\": \"src\"\n" +" }\n" +" }\n" +"}\n" +msgstr "" + +#. type: Plain text +#: en/structure/package.md +msgid "You may list one or multiple root namespaces and their corresponding file paths." +msgstr "" + +#. type: Title ### +#: en/structure/package.md +#, no-wrap +msgid "Recommended Practices " +msgstr "" + +#. type: Plain text +#: en/structure/package.md +msgid "Because packages are meant to be used by other people, you often need to make an extra effort during development. Below, we introduce some common and recommended practices in creating high-quality extensions." +msgstr "" + +#. type: Title #### +#: en/structure/package.md +#, no-wrap +msgid "Testing " +msgstr "" + +#. type: Plain text +#: en/structure/package.md +msgid "You want your package to run flawlessly without bringing problems to other people. To reach this goal, you should test your extension before releasing it to the public." +msgstr "" + +#. type: Plain text +#: en/structure/package.md +msgid "It's recommended that you create various test cases to cover your extension code rather than relying on manual tests. Each time before you release a new version of your package, you may run these test cases to make sure everything is in good shape. For more details, please refer to the [Testing](../testing/overview.md) section." +msgstr "" + +#. type: Title #### +#: en/structure/package.md +#, no-wrap +msgid "Versioning " +msgstr "" + +#. type: Plain text +#: en/structure/package.md +msgid "You should give each release of your extension a version number (e.g. `1.0.1`). We recommend you follow the [semantic versioning](https://semver.org) practice when determining what version numbers should be used." +msgstr "" + +#. type: Title #### +#: en/structure/package.md +#, no-wrap +msgid "Releasing " +msgstr "" + +#. type: Plain text +#: en/structure/package.md +msgid "To let other people know about your package, you need to release it to the public." +msgstr "" + +#. type: Plain text +#: en/structure/package.md +msgid "If it's the first time you're releasing a package, you should register it in a Composer repository, such as [Packagist](https://packagist.org/). After that, all you need to do is create a release tag (for example, `v1.0.1`) on the VCS repository of your extension and notify the Composer repository about the new release. People will then be able to find the new release and install or update the package through the Composer repository." +msgstr "" + +#. type: Plain text +#: en/structure/package.md +msgid "In the release of your package, in addition to code files, you should also consider including the following to help other people learn about and use your extension:" +msgstr "" + +#. type: Bullet: '* ' +#: en/structure/package.md +msgid "A readme file in the package root directory: it describes what your extension does and how to install and use it. We recommend you write it in [Markdown](https://daringfireball.net/projects/markdown/) format and name the file as `README.md`." +msgstr "" + +#. type: Bullet: '* ' +#: en/structure/package.md +msgid "A changelog file in the package root directory: it lists what changes are made in each release. The file may be written in Markdown format and named as `CHANGELOG.md`." +msgstr "" + +#. type: Bullet: '* ' +#: en/structure/package.md +msgid "An upgrade file in the package root directory: it gives the instructions on how to upgrade from older releases of the extension. The file may be written in Markdown format and named as `UPGRADE.md`." +msgstr "" + +#. type: Bullet: '* ' +#: en/structure/package.md +msgid "Tutorials, demos, screenshots, etc.: these are needed if your extension provides many features that can't be fully covered in the readme file." +msgstr "" + +#. type: Bullet: '* ' +#: en/structure/package.md +msgid "API documentation: your code should be well-documented to allow other people to more easily read and understand it." +msgstr "" diff --git a/_translations/po/it/guide_structure_service.md.po b/_translations/po/it/guide_structure_service.md.po new file mode 100644 index 00000000..4a414782 --- /dev/null +++ b/_translations/po/it/guide_structure_service.md.po @@ -0,0 +1,199 @@ +# Italian 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-11-02 16:25+0000\n" +"PO-Revision-Date: 2025-11-02 16:25+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Bullet: '- ' +#: ../../guide/en/start/databases.md ../../guide/en/structure/domain.md +#: ../../guide/en/structure/service.md +#, no-wrap +msgid "Repository" +msgstr "" + +#. type: Bullet: '- ' +#: ../../guide/en/structure/domain.md ../../guide/en/structure/service.md +#, no-wrap +msgid "Entity" +msgstr "" + +#. type: Title # +#: ../../guide/en/structure/service.md +#, fuzzy, no-wrap +#| msgid "[Service components](structure/service.md)" +msgid "Service components" +msgstr "[Componenti di servizio](structure/service.md)" + +#. type: Plain text +#: ../../guide/en/structure/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 "" + +#. type: Fenced code block (php) +#: ../../guide/en/structure/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 "" + +#. type: Plain text +#: ../../guide/en/structure/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 "" + +#. type: Fenced code block (php) +#: ../../guide/en/structure/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 "" + +#. type: Plain text +#: ../../guide/en/structure/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 "" + +#. type: Title ## +#: ../../guide/en/structure/service.md +#, no-wrap +msgid "Service dependencies and configuration" +msgstr "" + +#. type: Plain text +#: ../../guide/en/structure/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 "" + +#. type: Bullet: '- ' +#: ../../guide/en/structure/service.md +msgid "After the service is created, it shouldn't be re-configured in runtime." +msgstr "" + +#. type: Bullet: '- ' +#: ../../guide/en/structure/service.md +msgid "DI container instance usually **shouldn't** be injected as a dependency. Prefer concrete interfaces." +msgstr "" + +#. type: Bullet: '- ' +#: ../../guide/en/structure/service.md +msgid "In case of complicated or \"heavy\" initialization, try to postpone it until the service method is called." +msgstr "" + +#. type: Plain text +#: ../../guide/en/structure/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 "" + +#. type: Fenced code block (php) +#: ../../guide/en/structure/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 "" + +#. type: Title ## +#: ../../guide/en/structure/service.md +#, no-wrap +msgid "Service methods" +msgstr "" + +#. type: Plain text +#: ../../guide/en/structure/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 "" + +#. type: Fenced code block (php) +#: ../../guide/en/structure/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 "" + +#. type: Plain text +#: ../../guide/en/structure/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 "" + +#. type: Title ## +#: ../../guide/en/structure/service.md +#, no-wrap +msgid "Is everything a service?" +msgstr "" + +#. type: Plain text +#: ../../guide/en/structure/service.md +msgid "Often it makes sense to choose another class type to place your code into. Check:" +msgstr "" + +#. type: Bullet: '- ' +#: ../../guide/en/structure/service.md +msgid "Widget" +msgstr "" + +#. type: Bullet: '- ' +#: ../../guide/en/structure/service.md +#, fuzzy +#| msgid "[Middleware](structure/middleware.md)" +msgid "[Middleware](middleware.md)" +msgstr "[Middleware](structure/middleware.md)" diff --git a/_translations/po/it/guide_tutorial_console-applications.md.po b/_translations/po/it/guide_tutorial_console-applications.md.po new file mode 100644 index 00000000..07bd8121 --- /dev/null +++ b/_translations/po/it/guide_tutorial_console-applications.md.po @@ -0,0 +1,141 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title ## +#: en/concept/autoloading.md en/security/best-practices.md +#: en/structure/domain.md en/tutorial/console-applications.md +#, no-wrap +msgid "References" +msgstr "" + +#. type: Title # +#: en/tutorial/console-applications.md +#, no-wrap +msgid "Console applications" +msgstr "" + +#. type: Plain text +#: en/tutorial/console-applications.md +msgid "Console applications are mainly used to create utility, background processing and maintenance tasks." +msgstr "" + +#. type: Plain text +#: en/tutorial/console-applications.md +msgid "To get support for console application in your project, get `yiisoft/yii-console` via composer:" +msgstr "" + +#. type: Fenced code block +#: en/tutorial/console-applications.md +#, no-wrap +msgid "composer require yiisoft/yii-console\n" +msgstr "" + +#. type: Plain text +#: en/tutorial/console-applications.md +msgid "After it's installed, you can access the entry point as" +msgstr "" + +#. type: Fenced code block +#: en/tutorial/console-applications.md +#, no-wrap +msgid "./yii\n" +msgstr "" + +#. type: Plain text +#: en/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 "" + +#. type: Plain text +#: en/tutorial/console-applications.md +msgid "Commands are executed with `symfony/console`. To create your own console command, you need to define a command:" +msgstr "" + +#. type: Fenced code block (php) +#: en/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 "" + +#. type: Plain text +#: en/tutorial/console-applications.md +msgid "Now register the command in `config/params.php`:" +msgstr "" + +#. type: Fenced code block (php) +#: en/tutorial/console-applications.md +#, no-wrap +msgid "" +"return [\n" +" 'console' => [\n" +" 'commands' => [\n" +" 'demo/hello' => App\\Demo\\HelloCommand::class,\n" +" ],\n" +" ], \n" +"];\n" +msgstr "" + +#. type: Plain text +#: en/tutorial/console-applications.md +msgid "After it's done, the command could be executed as" +msgstr "" + +#. type: Fenced code block +#: en/tutorial/console-applications.md +#, no-wrap +msgid "./yii demo:hello Alice\n" +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/console-applications.md +msgid "[Symfony Console component guide](https://symfony.com/doc/current/components/console.html)" +msgstr "" diff --git a/_translations/po/it/guide_tutorial_mailing.md.po b/_translations/po/it/guide_tutorial_mailing.md.po new file mode 100644 index 00000000..b27fe205 --- /dev/null +++ b/_translations/po/it/guide_tutorial_mailing.md.po @@ -0,0 +1,608 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: en/tutorial/mailing.md +#, no-wrap +msgid "Mailing" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: en/tutorial/mailing.md +#, no-wrap +msgid "Configuring the Mailer" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "You can also create an instance manually as follows:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "The `Yiisoft\\Mailer\\MailerInterface` provides two main methods:" +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`send()` - Sends the given email message." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`sendMultiple()` - Sends many messages at once." +msgstr "" + +#. type: Title ## +#: en/tutorial/mailing.md +#, no-wrap +msgid "Creating a Message" +msgstr "" + +#. type: Title ### +#: en/tutorial/mailing.md +#, no-wrap +msgid "Simple Text Message" +msgstr "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "To create a simple message with a text body, use `Yiisoft\\Mailer\\Message`:" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: en/tutorial/mailing.md +#, no-wrap +msgid "Simple HTML Message" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: en/tutorial/mailing.md +#, no-wrap +msgid "HTML Message from template" +msgstr "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "For this example, we will use package rendering package [view](https://github.com/yiisoft/view)." +msgstr "" + +#. 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 "" + +#. type: Title ### +#: en/tutorial/mailing.md +#, no-wrap +msgid "Using Layouts" +msgstr "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "You can also pass parameters to layouts from your template message:" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: en/tutorial/mailing.md +#, no-wrap +msgid "Layout Example" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: en/tutorial/mailing.md +#, no-wrap +msgid "Adding More Data" +msgstr "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "The `Yiisoft\\Mailer\\MessageInterface` provides several methods to customize your message:" +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withCharset()` - Returns a new instance with the specified charset." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withFrom()` - Returns a new instance with the specified sender email address." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withTo()` - Returns a new instance with the specified recipient(s) email address." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withReplyTo()` - Returns a new instance with the specified reply-to address." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withCc()` - Returns a new instance with the specified Cc (extra copy receiver) addresses." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withBcc()` - Returns a new instance with the specified Bcc (hidden copy receiver) addresses." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withSubject()` - Returns a new instance with the specified message subject." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withDate()` - Returns a new instance with the specified date when the message was sent." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withPriority()` - Returns a new instance with the specified priority of this message." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withReturnPath()` - Returns a new instance with the specified return-path (the bounce address) of this message." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withSender()` - Returns a new instance with the specified actual sender email address." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withHtmlBody()` - Returns a new instance with the specified message HTML content." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withTextBody()` - Returns a new instance with the specified message plain text content." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withAddedHeader()` - Returns a new instance with the specified added custom header value." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withHeader()` - Returns a new instance with the specified custom header value." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`withHeaders()` - Returns a new instance with the specified custom header values." +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: en/tutorial/mailing.md +#, no-wrap +msgid "Getters" +msgstr "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "The following getters are available to retrieve message data:" +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getCharset()` - Returns the charset of this message." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getFrom()` - Returns the message sender email address." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getTo()` - Returns the message recipient(s) email address." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getReplyTo()` - Returns the reply-to address of this message." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getCc()` - Returns the Cc (extra copy receiver) addresses of this message." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getBcc()` - Returns the Bcc (hidden copy receiver) addresses of this message." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getSubject()` - Returns the message subject." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getDate()` - Returns the date when the message was sent, or null if it wasn't set." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getPriority()` - Returns the priority of this message." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getReturnPath()` - Returns the return-path (the bounce address) of this message." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getSender()` - Returns the message actual sender email address." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getHtmlBody()` - Returns the message HTML body." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getTextBody()` - Returns the message text body." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`getHeader()` - Returns all values for the specified header." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`__toString()` - Returns string representation of this message." +msgstr "" + +#. type: Title ## +#: en/tutorial/mailing.md +#, no-wrap +msgid "Attaching Files" +msgstr "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "You can attach files to your message using the `withAttached()` method:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: en/tutorial/mailing.md +#, no-wrap +msgid "Embedding Images" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "In your view or layout template, you can reference the embedded image using its CID:" +msgstr "" + +#. type: Fenced code block (php) +#: en/tutorial/mailing.md +#, no-wrap +msgid "\">\n" +msgstr "" + +#. type: Title ## +#: en/tutorial/mailing.md +#, no-wrap +msgid "Sending a Message" +msgstr "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "To send an email message:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: en/tutorial/mailing.md +#, no-wrap +msgid "Sending Multiple Messages" +msgstr "" + +#. type: Plain text +#: en/tutorial/mailing.md +msgid "You can send multiple messages at once:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: en/tutorial/mailing.md +#, no-wrap +msgid "Implementing your own mail driver" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: en/tutorial/mailing.md +#, fuzzy, no-wrap +#| msgid "Development tools" +msgid "For Development" +msgstr "Strumenti di sviluppo" + +#. 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 "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`Yiisoft\\Mailer\\StubMailer` - A simple mailer that stores messages in a local array." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`Yiisoft\\Mailer\\FileMailer` - A mock mailer that saves email messages as files instead of sending them." +msgstr "" + +#. type: Bullet: '- ' +#: en/tutorial/mailing.md +msgid "`Yiisoft\\Mailer\\NullMailer` - A mailer that discards messages without sending or storing them." +msgstr "" + +#. 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 "" + +#. 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 "" diff --git a/_translations/po/it/guide_tutorial_performance-tuning.md.po b/_translations/po/it/guide_tutorial_performance-tuning.md.po new file mode 100644 index 00000000..571f3c93 --- /dev/null +++ b/_translations/po/it/guide_tutorial_performance-tuning.md.po @@ -0,0 +1,346 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "Performance tuning" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "Optimizing your PHP Environment " +msgstr "" + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "A well-configured PHP environment is important. To get maximum performance:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/performance-tuning.md +msgid "[Tune `realpath()` cache](https://github.com/samdark/realpath_cache_tuner)." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/performance-tuning.md +msgid "Make sure [XDebug](https://xdebug.org/) isn't installed in the production environment." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/performance-tuning.md +msgid "Try [PHP 7 preloading](https://wiki.php.net/rfc/preload)." +msgstr "" + +#. type: Title ## +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "Optimizing your code " +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/performance-tuning.md +msgid "[Speeding up array_merge()](https://www.exakat.io/speeding-up-array_merge/)" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "Using caching techniques " +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "Optimizing session storage " +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "Optimizing databases " +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "Optimizing composer autoloader " +msgstr "" + +#. 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 "" + +#. type: Fenced code block +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "composer dumpautoload -o\n" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "Processing data offline " +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "There are two methods to process data offline: pull and push." +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "Using preloading" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "Preloading benchmarks" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Fenced code block (shell) +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "ab -n 1000 -c 10 -t 10\n" +msgstr "" + +#. 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 "" + +#. type: Fenced code block (shell) +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "composer install --optimize-autoloader --no-dev\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +msgid "With preloading enabled, the entire composer class map (825 files) was used:" +msgstr "" + +#. 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 "" + +#. type: Title #### +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "Test results" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/tutorial/performance-tuning.md +#, no-wrap +msgid "Performance profiling " +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/tutorial/performance-tuning.md +#, fuzzy, no-wrap +#| msgid "[Yii DB](https://github.com/yiisoft/db/blob/master/docs/guide/en/README.md)" +msgid "\n" +msgstr "[Yii DB](https://github.com/yiisoft/db/blob/master/docs/guide/en/README.md)" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/performance-tuning.md +msgid "[Blackfire](https://blackfire.io/)" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/performance-tuning.md +msgid "[XHProf](https://secure.php.net/manual/en/book.xhprof.php)" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/tutorial/performance-tuning.md +msgid "[XDebug profiler](https://xdebug.org/docs/profiler)" +msgstr "" diff --git a/_translations/po/it/guide_tutorial_using-with-event-loop.md.po b/_translations/po/it/guide_tutorial_using-with-event-loop.md.po new file mode 100644 index 00000000..77660d5f --- /dev/null +++ b/_translations/po/it/guide_tutorial_using-with-event-loop.md.po @@ -0,0 +1,137 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../../guide/en/tutorial/using-with-event-loop.md +#, no-wrap +msgid "Using Yii with event loop" +msgstr "" + +#. type: Plain text +#: ../../guide/en/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 "" + +#. type: Plain text +#: ../../guide/en/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 "" + +#. type: Plain text +#: ../../guide/en/tutorial/using-with-event-loop.md +msgid "There are multiple tools that could be used to achieve it. Notably, [FrankenPHP](https://frankenphp.dev/), [RoadRunner](https://roadrunner.dev/) and [Swoole](https://www.swoole.co.uk/)." +msgstr "" + +#. type: Title ## +#: ../../guide/en/tutorial/using-with-event-loop.md +#, no-wrap +msgid "Event loop implications" +msgstr "" + +#. type: Plain text +#: ../../guide/en/tutorial/using-with-event-loop.md +msgid "Event loop worker basically looks like the following:" +msgstr "" + +#. type: Fenced code block (php) +#: ../../guide/en/tutorial/using-with-event-loop.md +#, no-wrap +msgid "" +"initializeContext();\n" +"while ($request = getRequest()) {\n" +" $response = process($request);\n" +" emit($response);\n" +"}\n" +msgstr "" + +#. type: Plain text +#: ../../guide/en/tutorial/using-with-event-loop.md +msgid "Usually, there are multiple workers processing requests at the same time as with traditional php-fpm." +msgstr "" + +#. type: Plain text +#: ../../guide/en/tutorial/using-with-event-loop.md +msgid "That means that there's more to consider when developing applications." +msgstr "" + +#. type: Title ### +#: ../../guide/en/tutorial/using-with-event-loop.md +#, no-wrap +msgid "Processing is blocking" +msgstr "" + +#. type: Plain text +#: ../../guide/en/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 "" + +#. type: Title ### +#: ../../guide/en/tutorial/using-with-event-loop.md +#, no-wrap +msgid "Services and state" +msgstr "" + +#. type: Plain text +#: ../../guide/en/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 "" + +#. type: Plain text +#: ../../guide/en/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 "" + +#. type: Fenced code block (php) +#: ../../guide/en/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 "" + +#. type: Title ## +#: ../../guide/en/tutorial/using-with-event-loop.md +#, fuzzy, no-wrap +#| msgid "Introduction" +msgid "Integrations" +msgstr "Introduzione" + +#. type: Bullet: '- ' +#: ../../guide/en/tutorial/using-with-event-loop.md +#, fuzzy +#| msgid "[Using Yii with RoadRunner](tutorial/using-yii-with-roadrunner.md)" +msgid "[RoadRunner](using-yii-with-roadrunner.md)" +msgstr "[Usare Yii con RoadRunner](tutorial/using-yii-with-roadrunner.md)" + +#. type: Bullet: '- ' +#: ../../guide/en/tutorial/using-with-event-loop.md +#, fuzzy +#| msgid "[Using Yii with Swoole](tutorial/using-yii-with-swoole.md)" +msgid "[Swoole](using-yii-with-swoole.md)" +msgstr "[Usare Yii con Swoole](tutorial/using-yii-with-swoole.md)" diff --git a/_translations/po/it/guide_tutorial_using-yii-with-roadrunner.md.po b/_translations/po/it/guide_tutorial_using-yii-with-roadrunner.md.po new file mode 100644 index 00000000..ca053181 --- /dev/null +++ b/_translations/po/it/guide_tutorial_using-yii-with-roadrunner.md.po @@ -0,0 +1,189 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\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 "" + +#. 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 "" + +#. type: Title # +#: ../src/en/guide/tutorial/using-yii-with-roadrunner.md +#, no-wrap +msgid "Using Yii with RoadRunner" +msgstr "" + +#. type: Plain text +#: ../src/en/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 "" + +#. type: Plain text +#: ../src/en/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 "" + +#. type: Fenced code block +#: ../src/en/guide/tutorial/using-yii-with-roadrunner.md +#, no-wrap +msgid "composer require yiisoft/yii-runner-roadrunner\n" +msgstr "" + +#. type: Plain text +#: ../src/en/guide/tutorial/using-yii-with-roadrunner.md +msgid "After installation is done, run" +msgstr "" + +#. type: Fenced code block +#: ../src/en/guide/tutorial/using-yii-with-roadrunner.md +#, no-wrap +msgid "./vendor/bin/rr get\n" +msgstr "" + +#. type: Plain text +#: ../src/en/guide/tutorial/using-yii-with-roadrunner.md +msgid "That would download ready to use RoadRunner server `rr` binary." +msgstr "" + +#. type: Plain text +#: ../src/en/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 "" + +#. type: Fenced code block (yaml) +#: ../src/en/guide/tutorial/using-yii-with-roadrunner.md +#, no-wrap +msgid "" +"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" +" num_workers: 4\n" +" max_jobs: 64\n" +" middleware: [\"static\", \"headers\"]\n" +" static:\n" +" dir: \"public\"\n" +" forbid: [\".php\", \".htaccess\"]\n" +" headers:\n" +" response:\n" +" \"Cache-Control\": \"no-cache\"\n" +"\n" +"reload:\n" +" interval: 1s\n" +" patterns: [ \".php\" ]\n" +" services:\n" +" http:\n" +" recursive: true\n" +" dirs: [ \".\" ]\n" +"\n" +"logs:\n" +" mode: production\n" +" level: warn\n" +msgstr "" + +#. type: Plain text +#: ../src/en/guide/tutorial/using-yii-with-roadrunner.md +msgid "We're specifying that entry script is `worker.php`, there should be three workers on port 8080, `public` directory files are static ones except `.php` and `.htaccess`. Also, we're sending an additional header." +msgstr "" + +#. type: Plain text +#: ../src/en/guide/tutorial/using-yii-with-roadrunner.md +msgid "Create `/worker.php`:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/en/guide/tutorial/using-yii-with-roadrunner.md +#, no-wrap +msgid "" +"run();\n" +msgstr "" + +#. type: Title ## +#: ../src/en/guide/tutorial/using-yii-with-roadrunner.md +#: ../src/en/guide/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "Starting a server" +msgstr "" + +#. type: Plain text +#: ../src/en/guide/tutorial/using-yii-with-roadrunner.md +#: ../src/en/guide/tutorial/using-yii-with-swoole.md +msgid "To start a server, execute the following command:" +msgstr "" + +#. type: Fenced code block +#: ../src/en/guide/tutorial/using-yii-with-roadrunner.md +#, no-wrap +msgid "./rr serve -d\n" +msgstr "" + +#. type: Title ## +#: ../src/en/guide/tutorial/using-yii-with-roadrunner.md +#, no-wrap +msgid "On worker scope" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/guide/tutorial/using-yii-with-roadrunner.md +msgid "Each worker's scope is isolated from other workers. Memory isn't shared." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/guide/tutorial/using-yii-with-roadrunner.md +msgid "A single worker serves multiple requests where the scope is shared." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/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 "" diff --git a/_translations/po/it/guide_tutorial_using-yii-with-swoole.md.po b/_translations/po/it/guide_tutorial_using-yii-with-swoole.md.po new file mode 100644 index 00000000..15221ccc --- /dev/null +++ b/_translations/po/it/guide_tutorial_using-yii-with-swoole.md.po @@ -0,0 +1,197 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title ## +#: ../../guide/en/tutorial/using-yii-with-roadrunner.md +#: ../../guide/en/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "Installation" +msgstr "" + +#. type: Title ## +#: ../../guide/en/tutorial/using-yii-with-roadrunner.md +#: ../../guide/en/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "Starting a server" +msgstr "" + +#. type: Plain text +#: ../../guide/en/tutorial/using-yii-with-roadrunner.md +#: ../../guide/en/tutorial/using-yii-with-swoole.md +msgid "To start a server, execute the following command:" +msgstr "" + +#. type: Title # +#: ../../guide/en/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "Using Yii with Swoole" +msgstr "" + +#. type: Plain text +#: ../../guide/en/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "" +"[Swoole](https://www.swoole.co.uk/) is a PHP network framework distributed as a PECL extension. It allows you built-in async,\n" +"multiple threads I/O modules. Developers can use sync or async, coroutine API to write the applications.\n" +msgstr "" + +#. type: Plain text +#: ../../guide/en/tutorial/using-yii-with-swoole.md +msgid "In the context of Yii, it allows running request handlers 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 "" + +#. type: Plain text +#: ../../guide/en/tutorial/using-yii-with-swoole.md +msgid "Swoole works on Linux and macOS and can be installed via pecl:" +msgstr "" + +#. type: Fenced code block (bash) +#: ../../guide/en/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "pecl install swoole\n" +msgstr "" + +#. type: Title ## +#: ../../guide/en/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "Putting up a server" +msgstr "" + +#. type: Plain text +#: ../../guide/en/tutorial/using-yii-with-swoole.md +msgid "Since Swoole doesn't have built-in PSR-7 support, you need a package fixing so:" +msgstr "" + +#. type: Fenced code block (php) +#: ../../guide/en/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "composer require ilexn/swoole-convent-psr7\n" +msgstr "" + +#. type: Plain text +#: ../../guide/en/tutorial/using-yii-with-swoole.md +msgid "Create an entry script, `server.php`:" +msgstr "" + +#. type: Fenced code block (php) +#: ../../guide/en/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "" +"withDefinitions($config->get('web'))\n" +" ->withProviders($config->get('providers-web'));\n" +"$container = new Container($containerConfig);\n" +"\n" +"$bootstrapList = $config->get('bootstrap-web');\n" +"foreach ($bootstrapList as $callback) {\n" +" if (!(is_callable($callback))) {\n" +" $type = is_object($callback) ? get_class($callback) : gettype($callback);\n" +"\n" +" throw new \\RuntimeException(\"Bootstrap callback must be callable, $type given.\");\n" +" }\n" +" $callback($container);\n" +"}\n" +"\n" +"$application = $container->get(Application::class);\n" +"\n" +"$serverRequestFactory = new \\Ilex\\SwoolePsr7\\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 Swoole\\HTTP\\Server('0.0.0.0', 9501);\n" +"\n" +"$server->on('start', static function (Swoole\\Http\\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 (Swoole\\Http\\Request $request, Swoole\\Http\\Response $response) use ($serverRequestFactory, $application, $container) {\n" +" $psr7Response = null;\n" +" try {\n" +" $requestContainer = clone $container;\n" +" $psr7Request = $serverRequestFactory->createFromSwoole($request);\n" +" $psr7Response = $application->handle($psr7Request);\n" +" \n" +" $converter = new \\Ilex\\SwoolePsr7\\SwooleResponseConverter($response);\n" +" $converter->send($psr7Response);\n" +" } catch (\\Throwable $t) {\n" +" // TODO: render it properly\n" +" $response->end($t->getMessage());\n" +" } finally {\n" +" $application->afterEmit($psr7Response ?? null);\n" +" $container->get(\\Yiisoft\\Di\\StateResetter::class)->reset();\n" +" $container = $requestContainer; \n" +" }\n" +"});\n" +"\n" +"$server->on('shutdown', static function (Swoole\\Http\\Server $server) use ($application) {\n" +" $application->shutdown();\n" +"});\n" +"\n" +"$server->start();\n" +msgstr "" + +#. type: Fenced code block +#: ../../guide/en/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "php server.php\n" +msgstr "" + +#. type: Title ## +#: ../../guide/en/tutorial/using-yii-with-swoole.md +#, no-wrap +msgid "On scope" +msgstr "" + +#. type: Plain text +#: ../../guide/en/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 "" diff --git a/_translations/po/it/guide_views_asset.md.po b/_translations/po/it/guide_views_asset.md.po new file mode 100644 index 00000000..6508e687 --- /dev/null +++ b/_translations/po/it/guide_views_asset.md.po @@ -0,0 +1,992 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title ## +#: ../src/cookbook/deployment/docker-swarm.md ../src/guide/views/asset.md +#, fuzzy, no-wrap +msgid "Troubleshooting" +msgstr "Testing" + +#. 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 "" + +#. type: Title # +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Assets" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/views/asset.md +msgid "The asset management functionality is provided by the `yiisoft/assets` package:" +msgstr "" + +#. type: Fenced code block (bash) +#: ../src/guide/views/asset.md +#, no-wrap +msgid "composer require yiisoft/assets\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/asset.md +msgid "This package is included by default in the `yiisoft/app` application template." +msgstr "" + +#. type: Title ## +#: ../src/guide/views/asset.md ../src/guide/views/view.md +#: ../src/guide/views/widget.md +#, fuzzy, no-wrap +msgid "Basic Concepts" +msgstr "Concetti chiave" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Asset Bundles" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Asset Manager" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Creating Asset Bundles" +msgstr "" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Basic Asset Bundle" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/asset.md +msgid "Here's a simple asset bundle definition:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Using Asset Bundles" +msgstr "" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "In Controllers" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/asset.md +msgid "Register asset bundles in your controllers or views:" +msgstr "" + +#. 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->register([\n" +" MainAsset::class,\n" +" AdminAsset::class,\n" +" ]);\n" +" \n" +" return $this->viewRenderer->render('admin/dashboard');\n" +" }\n" +"}\n" +msgstr "" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, fuzzy, no-wrap +#| msgid "Views" +msgid "In Views" +msgstr "Viste" + +#. type: Plain text +#: ../src/guide/views/asset.md +msgid "You can also register assets directly in views:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/views/asset.md +#, no-wrap +msgid "" +"register(ProductAsset::class);\n" +"?>\n" +"\n" +"
\n" +"

\n" +" \n" +"
\n" +msgstr "" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "With WebView Integration" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/asset.md +msgid "The recommended approach is to integrate with WebView for automatic asset rendering:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Asset Publishing" +msgstr "" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Source Path Publishing" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Third-party Library Assets" +msgstr "" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "jQuery Asset Bundle" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/views/asset.md +#, no-wrap +msgid "" +" 'sha256-...',\n" +" 'crossorigin' => 'anonymous',\n" +" ];\n" +"}\n" +msgstr "" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Bootstrap Asset Bundle" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/views/asset.md +#, no-wrap +msgid "" +" 'sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p',\n" +" 'crossorigin' => 'anonymous',\n" +" ];\n" +"}\n" +msgstr "" + +#. type: Title ## +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Asset Configuration" +msgstr "" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, fuzzy, no-wrap +#| msgid "Application structure" +msgid "Application Configuration" +msgstr "Struttura applicativa" + +#. type: Plain text +#: ../src/guide/views/asset.md +msgid "Configure asset management in your application configuration:" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/asset.md +#, no-wrap +msgid "**config/web/params.php**\n" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Environment-specific Assets" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/asset.md +msgid "Configure different assets for different environments:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Asset Optimization" +msgstr "" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Asset Combination" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/asset.md +msgid "Combine multiple CSS or JavaScript files into single files:" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Asset Compression" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/asset.md +msgid "Configure asset compression for production:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/views/asset.md +#, fuzzy, no-wrap +#| msgid "Working with databases" +msgid "Working with Asset Converter" +msgstr "Lavorare con i database" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "SCSS/SASS Compilation" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '1. ' +#: ../src/guide/views/asset.md +msgid "**Organize by functionality**: Group related assets into logical bundles" +msgstr "" + +#. type: Bullet: '2. ' +#: ../src/guide/views/asset.md +msgid "**Manage dependencies**: Properly declare dependencies between bundles" +msgstr "" + +#. type: Bullet: '3. ' +#: ../src/guide/views/asset.md +msgid "**Use meaningful names**: Name your asset bundles clearly" +msgstr "" + +#. type: Bullet: '4. ' +#: ../src/guide/views/asset.md +msgid "**Environment optimization**: Use minified assets in production" +msgstr "" + +#. type: Bullet: '5. ' +#: ../src/guide/views/asset.md +msgid "**CDN consideration**: Use CDN for popular libraries when appropriate" +msgstr "" + +#. type: Bullet: '6. ' +#: ../src/guide/views/asset.md +msgid "**Version your assets**: Include version numbers in filenames for cache busting" +msgstr "" + +#. type: Bullet: '7. ' +#: ../src/guide/views/asset.md +msgid "**Minimize HTTP requests**: Combine related assets when possible" +msgstr "" + +#. type: Bullet: '8. ' +#: ../src/guide/views/asset.md +msgid "**Optimize file sizes**: Compress and minify assets for production" +msgstr "" + +#. type: Title ### +#: ../src/guide/views/asset.md +#, no-wrap +msgid "Common Issues" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" diff --git a/_translations/po/it/guide_views_script-style-meta.md.po b/_translations/po/it/guide_views_script-style-meta.md.po new file mode 100644 index 00000000..ce0ff227 --- /dev/null +++ b/_translations/po/it/guide_views_script-style-meta.md.po @@ -0,0 +1,785 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title ## +#: ../src/guide/structure/overview.md ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Overview" +msgstr "" + +#. type: Title ## +#: ../src/guide/views/asset.md ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Practical Examples" +msgstr "" + +#. 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 "" + +#. type: Title # +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Scripts, styles and meta tags" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/guide/views/script-style-meta.md +msgid "Register CSS files and inline styles" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/views/script-style-meta.md +msgid "Register JavaScript files and inline scripts" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/views/script-style-meta.md +msgid "Manage HTML meta tags and link tags" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/views/script-style-meta.md +msgid "Control the position where resources are rendered" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/guide/views/script-style-meta.md +msgid "Handle dependencies between resources" +msgstr "" + +#. type: Title ## +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "CSS management" +msgstr "" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Registering CSS Files" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "You can register CSS files to be included in your HTML pages:" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Registering Inline CSS" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "For inline CSS styles, use the `registerCss()` method:" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "CSS from Files" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "You can also register CSS content from external files:" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Using Style Tags" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "For more control, you can use HTML style tags directly:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "JavaScript management" +msgstr "" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Registering JavaScript Files" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "Include external JavaScript files using `registerJsFile()`:" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Registering Inline JavaScript" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "Add inline JavaScript code with `registerJs()`:" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "JavaScript Variables" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "Pass PHP data to JavaScript using `registerJsVar()`:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "This generates JavaScript code like:" +msgstr "" + +#. type: Fenced code block (html) +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "" +"\n" +msgstr "" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Using Script Tags" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "For more control over script tags:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Position Constants" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "Resources can be positioned at different locations in the HTML document:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "Example layout showing where each position is rendered:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Meta tags" +msgstr "" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Basic Meta Tags" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "Register meta tags for SEO and page information:" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Using Meta Tag Objects" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "For more control, use the `Html::meta()` helper:" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Preventing Duplicate Meta Tags" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "Use keys to prevent duplicate meta tags:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Link tags" +msgstr "" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Basic Link Tags" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "Register various types of link tags:" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Using Link Tag Objects" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Complete Page Setup" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/script-style-meta.md +#, no-wrap +msgid "Conditional Resource Loading" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "Load resources based on conditions:" +msgstr "" + +#. 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 "" + +#. type: Bullet: '1. ' +#: ../src/guide/views/script-style-meta.md +msgid "**Use appropriate positions**: Place CSS in `POSITION_HEAD`, JavaScript at `POSITION_END`" +msgstr "" + +#. type: Bullet: '2. ' +#: ../src/guide/views/script-style-meta.md +msgid "**Minimize inline resources**: Prefer external files for better caching" +msgstr "" + +#. type: Bullet: '3. ' +#: ../src/guide/views/script-style-meta.md +msgid "**Use keys for duplicates**: Prevent duplicate resources with meaningful keys" +msgstr "" + +#. type: Bullet: '4. ' +#: ../src/guide/views/script-style-meta.md +msgid "**Optimize loading**: Use `async` and `defer` attributes for non-critical JavaScript" +msgstr "" + +#. type: Bullet: '5. ' +#: ../src/guide/views/script-style-meta.md +msgid "**Group related resources**: Keep related CSS and JS files together" +msgstr "" + +#. type: Bullet: '6. ' +#: ../src/guide/views/script-style-meta.md +msgid "**Use CDNs wisely**: Balance performance with reliability" +msgstr "" + +#. type: Bullet: '7. ' +#: ../src/guide/views/script-style-meta.md +msgid "**Validate meta tags**: Ensure proper SEO meta tags are set" +msgstr "" + +#. type: Bullet: '8. ' +#: ../src/guide/views/script-style-meta.md +msgid "**Consider security**: Be careful with inline scripts and CSP policies" +msgstr "" + +#. type: Title ## +#: ../src/guide/views/script-style-meta.md +#, fuzzy, no-wrap +#| msgid "Working with databases" +msgid "Working with Asset Bundles" +msgstr "Lavorare con i database" + +#. type: Plain text +#: ../src/guide/views/script-style-meta.md +msgid "For more complex asset management, consider using asset bundles:" +msgstr "" + +#. 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 "" diff --git a/_translations/po/it/guide_views_template-engines.md.po b/_translations/po/it/guide_views_template-engines.md.po new file mode 100644 index 00000000..3cc3f0f5 --- /dev/null +++ b/_translations/po/it/guide_views_template-engines.md.po @@ -0,0 +1,364 @@ +# Italian 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-25 21:55+0000\n" +"PO-Revision-Date: 2025-12-25 21:55+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\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 "" + +#. type: Title # +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "Template engines" +msgstr "" + +#. 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 or create your own custom renderers." +msgstr "" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +msgid "PHP templates were described in the \"[View](view.md)\" guide section." +msgstr "" + +#. type: Title ## +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "Twig Template Engine" +msgstr "" + +#. 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 "" + +#. type: Fenced code block (bash) +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "composer require yiisoft/view-twig\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +msgid "Now you can use `.twig` templates. For example, `views/site/about.twig`:" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "Twig Features" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "**Automatic Escaping**: Twig automatically escapes variables for HTML context:\n" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "**Template Inheritance**: Twig supports template inheritance:\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "**views/layout/main.twig**\n" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "**views/site/about.twig**\n" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "Rendering Twig Templates" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +msgid "Use Twig templates the same way as PHP templates:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "Custom Template Engines" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +msgid "You can create custom template engines by implementing the `TemplateRendererInterface`:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +msgid "Register your custom renderer:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +msgid "Now you can use `.md` template files:" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "**views/content/help.md**\n" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/views/template-engines.md +#, no-wrap +msgid "Choosing the Right Template Engine" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '1. ' +#: ../src/guide/views/template-engines.md +msgid "**Keep templates simple**: Move complex logic to controllers or services" +msgstr "" + +#. type: Bullet: '2. ' +#: ../src/guide/views/template-engines.md +msgid "**Always escape output**: Prevent XSS attacks by properly escaping variables" +msgstr "" + +#. type: Bullet: '3. ' +#: ../src/guide/views/template-engines.md +msgid "**Use meaningful names**: Name your templates and variables clearly" +msgstr "" + +#. type: Bullet: '4. ' +#: ../src/guide/views/template-engines.md +msgid "**Organize templates**: Group related templates in subdirectories" +msgstr "" + +#. type: Bullet: '5. ' +#: ../src/guide/views/template-engines.md +msgid "**Document variables**: Always add type hints for better IDE support" +msgstr "" + +#. type: Bullet: '6. ' +#: ../src/guide/views/template-engines.md +msgid "**Avoid business logic**: Keep business logic in models and services" +msgstr "" diff --git a/_translations/po/it/guide_views_view-injections.md.po b/_translations/po/it/guide_views_view-injections.md.po new file mode 100644 index 00000000..76166068 --- /dev/null +++ b/_translations/po/it/guide_views_view-injections.md.po @@ -0,0 +1,180 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\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 "" + +#. type: Title # +#: ../src/guide/views/view-injections.md +#, no-wrap +msgid "View injections" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/views/view-injections.md +msgid "In config `params.php`:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/views/view-injections.md +#, no-wrap +msgid "New injections" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/views/view-injections.md +msgid "Add your new Injection to `params.php`:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/views/view-injections.md +#, no-wrap +msgid "Using Separate Injections for Different Layouts" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/views/view-injections.md +msgid "Create your custom ViewInjection for a specific layout:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" diff --git a/_translations/po/it/guide_views_view.md.po b/_translations/po/it/guide_views_view.md.po new file mode 100644 index 00000000..50583991 --- /dev/null +++ b/_translations/po/it/guide_views_view.md.po @@ -0,0 +1,493 @@ +# Italian 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-26 18:18+0000\n" +"PO-Revision-Date: 2025-12-26 18:18+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\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 "" + +#. type: Title # +#: ../src/guide/index.md ../src/guide/views/view.md +#, no-wrap +msgid "Views" +msgstr "Viste" + +#. 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 +#, fuzzy, no-wrap +msgid "Basic Concepts" +msgstr "Concetti chiave" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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)." +msgstr "" + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "For basic view functionality, you need the `yiisoft/view` package:" +msgstr "" + +#. type: Fenced code block (sh) +#: ../src/guide/views/view.md +#, no-wrap +msgid "composer require yiisoft/view\n" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 `ViewRenderer`. For example, `src/Web/Echo/Action.php`:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/views/view.md +#, fuzzy, no-wrap +#| msgid "Working with databases" +msgid "Working with layouts" +msgstr "Lavorare con i database" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/view.md +#, no-wrap +msgid "Rendering without layout" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/views/view.md +#, no-wrap +msgid "Nested Views and Partials" +msgstr "" + +#. type: Title ### +#: ../src/guide/views/view.md +#, no-wrap +msgid "Rendering Sub-views" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/views/view.md +#, no-wrap +msgid "**src/Web/Post/_item.php**\n" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/guide/views/view.md +#, no-wrap +msgid "" +"\n" +"
\n" +"

getTitle()) ?>

\n" +"

getExcerpt()) ?>

\n" +" \n" +"
\n" +msgstr "" + +#. type: Title ### +#: ../src/guide/views/view.md +#, no-wrap +msgid "Using Blocks" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/views/view.md +#, no-wrap +msgid "Rendering as String" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/views/view.md +#, fuzzy, no-wrap +#| msgid "Views" +msgid "View Events" +msgstr "Viste" + +#. type: Plain text +#: ../src/guide/views/view.md +msgid "The view system triggers events during the rendering process that you can listen to:" +msgstr "" + +#. 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 "" diff --git a/_translations/po/it/guide_views_widget.md.po b/_translations/po/it/guide_views_widget.md.po new file mode 100644 index 00000000..7c1ad56c --- /dev/null +++ b/_translations/po/it/guide_views_widget.md.po @@ -0,0 +1,1035 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\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 "" + +#. type: Title ## +#: ../src/guide/views/asset.md ../src/guide/views/view.md +#: ../src/guide/views/widget.md +#, fuzzy, no-wrap +msgid "Basic Concepts" +msgstr "Concetti chiave" + +#. 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 "" + +#. type: Title # +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Widgets" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "The widget functionality is provided by the `yiisoft/widget` package:" +msgstr "" + +#. type: Fenced code block (bash) +#: ../src/guide/views/widget.md +#, no-wrap +msgid "composer require yiisoft/widget\n" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "For ready-made widgets (like forms, navigation, etc.), you can also install:" +msgstr "" + +#. type: Fenced code block (bash) +#: ../src/guide/views/widget.md +#, no-wrap +msgid "composer require yiisoft/yii-widgets\n" +msgstr "" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Widget Class" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Widget Factory" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Widget Configuration" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Creating Custom Widgets" +msgstr "" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Simple Widget" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "Here's a basic widget that displays an alert message:" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Using the Widget" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Widget with Dependencies" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "Widgets can use dependency injection for services:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Widget Factory Setup" +msgstr "" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Bootstrap Configuration" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "Initialize the widget factory in your application bootstrap:" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/widget.md +#, no-wrap +msgid "**config/bootstrap.php**\n" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "DI Container Configuration" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/widget.md +#, no-wrap +msgid "**config/web/di.php**\n" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Advanced Widget Examples" +msgstr "" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Data List Widget" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "A widget that displays a list of items with pagination:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "Usage:" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Form Widget" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "A widget that simplifies form rendering:" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Breadcrumb Widget" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "A widget for navigation breadcrumbs:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Widget Best Practices" +msgstr "" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Configuration Pattern" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "Use immutable configuration methods:" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Validation" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "Validate widget configuration in the render method:" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "HTML Encoding" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "Always encode user data:" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Asset Management" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "Register widget-specific assets:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Using Widgets in Layouts" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "Widgets are particularly useful in layouts for common UI elements:" +msgstr "" + +#. type: Plain text +#: ../src/guide/views/widget.md +#, no-wrap +msgid "**views/layout/main.php**\n" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/views/widget.md +#, fuzzy, no-wrap +#| msgid "Testing" +msgid "Testing Widgets" +msgstr "Testing" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, fuzzy, no-wrap +#| msgid "Testing" +msgid "Unit Testing" +msgstr "Testing" + +#. type: Plain text +#: ../src/guide/views/widget.md +msgid "Test widget rendering logic:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Common Widget Patterns" +msgstr "" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Conditional Rendering" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Template-based Rendering" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/guide/views/widget.md +#, no-wrap +msgid "Event Integration" +msgstr "" + +#. 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 "" + +#. 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 "" diff --git a/_translations/po/it/index.md.po b/_translations/po/it/index.md.po new file mode 100644 index 00000000..98a14891 --- /dev/null +++ b/_translations/po/it/index.md.po @@ -0,0 +1,99 @@ +# Italian 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: \n" +"POT-Creation-Date: 2026-01-13 11:06+0000\n" +"PO-Revision-Date: 2026-01-17 21:03+0100\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.8\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 "Yii offre la massima funzionalità aggiungendo il minor overhead possibile." + +#. type: Yaml Front Matter Hash Value: features title +#: ../src/index.md +#, no-wrap +msgid "Fast" +msgstr "Veloce" + +#. 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 "Le impostazioni predefinite e gli strumenti integrati ti aiutano a scrivere codice solido e sicuro." + +#. type: Yaml Front Matter Hash Value: features title +#: ../src/index.md +#, no-wrap +msgid "Secure" +msgstr "Sicuro" + +#. 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 "Scrivi più codice in meno tempo con API semplici ma potenti e la generazione di codice." + +#. type: Yaml Front Matter Hash Value: features title +#: ../src/index.md +#, no-wrap +msgid "Efficient" +msgstr "Efficiente" + +#. type: Yaml Front Matter Hash Value: hero actions text +#: ../src/index.md +#, no-wrap +msgid "Get Started" +msgstr "Per iniziare" + +#. 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 "Un framework semplice, potente e veloce. Scopri la guida moderna e definitiva a Yii che hai sempre desiderato." + +#. type: Title ## +#: ../src/index.md ../src/internals/003-roadmap.md +#, no-wrap +msgid "Documentation" +msgstr "Documentazione" + +#. 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 "[La guida definitiva](guide/) — la guida completa che copre tutti gli aspetti del 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 "[Ricettario della comunità](cookbook/) — una raccolta di suggerimenti, trucchi e soluzioni forniti dalla comunità per le attività di sviluppo Yii più comuni." + +#. type: Bullet: '- ' +#: ../src/index.md +msgid "[Internals](internals/) — documentation for developers contributing to the Yii framework itself, including guidelines, workflows, and best practices." +msgstr "[Internals](internals/) — documentazione per gli sviluppatori che contribuiscono al framework Yii stesso, comprese linee guida, flussi di lavoro e best practice." diff --git a/_translations/po/it/internals_000-packages.md.po b/_translations/po/it/internals_000-packages.md.po new file mode 100644 index 00000000..b3d1fa96 --- /dev/null +++ b/_translations/po/it/internals_000-packages.md.po @@ -0,0 +1,237 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/en/internals/000-packages.md +msgid "For all packages, the GitHub repository name exactly matches the Packagist package name." +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/en/internals/000-packages.md +#, no-wrap +msgid "Yii-specific packages (framework and extensions)" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "named `yiisoft/yii-something` or more specific: `yii-type-something` e.g.:" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/en/internals/000-packages.md +msgid "modules: `yii-module-users`, `yii-module-pages`" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/en/internals/000-packages.md +msgid "themes: `yii-theme-adminlte`, `yii-theme-hyde`" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/en/internals/000-packages.md +msgid "widgets: `yii-widget-datepicker`" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "titled as \"Yii Framework ...\"" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "may have any dependencies and Yii-specific code" +msgstr "" + +#. type: Title ## +#: ../src/en/internals/000-packages.md +#, no-wrap +msgid "General purpose packages (libraries)" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "you can use these independently of Yii Framework" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "named as `yiisoft/something` without yii-prefix" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "titled as \"Yii ...\"" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "must not have dependencies on any Yii-specific packages" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "should have as fewer dependencies as possible" +msgstr "" + +#. type: Title ## +#: ../src/en/internals/000-packages.md +#, no-wrap +msgid "Configs and defaults" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/000-packages.md +msgid "The following applies to both Yii-specific packages and general purpose packages:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "Package may have `config` directory with Yii-specific defaults." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "Package may have \"config-plugin\" in \"extra\" section of `composer.json`." +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "You should namespace parameters with `vendor/package-name`:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/en/internals/000-packages.md +#, no-wrap +msgid "Versions" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/000-packages.md +msgid "All packages follow [SemVer](https://semver.org/) versioning:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "`x.*.*` - incompatible API changes." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "`*.x.*` - add functionality (backwards-compatible)." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "`*.*.x` - bug fixes (backwards-compatible)." +msgstr "" + +#. type: Plain text +#: ../src/en/internals/000-packages.md +msgid "The first stable version should be 1.0.0." +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/en/internals/000-packages.md +#, no-wrap +msgid "PHP versions support" +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "Package versions with active support MUST support all PHP versions that have active support." +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/en/internals/000-packages.md +msgid "Packages and application templates MIGHT have supported versions that work with unsupported PHP versions." +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/en/internals/000-packages.md +#, no-wrap +msgid "composer.json" +msgstr "" + +#. 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 "" diff --git a/_translations/po/it/internals_001-yii-values.md.po b/_translations/po/it/internals_001-yii-values.md.po new file mode 100644 index 00000000..09168dd0 --- /dev/null +++ b/_translations/po/it/internals_001-yii-values.md.po @@ -0,0 +1,245 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/en/internals/001-yii-values.md +#, no-wrap +msgid "001 — Yii goal and values" +msgstr "" + +#. type: Title ## +#: ../src/en/internals/001-yii-values.md +#, no-wrap +msgid "Goal" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/en/internals/001-yii-values.md +#, no-wrap +msgid "Values" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/en/internals/001-yii-values.md +#, no-wrap +msgid "Be practical" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/en/internals/001-yii-values.md +msgid "[High performance](#high-performance)" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/en/internals/001-yii-values.md +msgid "[Sensible defaults and flexibility](#sensible-defaults-and-flexibility)" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/en/internals/001-yii-values.md +#, fuzzy +#| msgid "[Best practices](security/best-practices.md)" +msgid "[Be practice-oriented](#be-practice-oriented)" +msgstr "[Migliori pratiche](security/best-practices.md)" + +#. type: Title ## +#: ../src/en/internals/001-yii-values.md +#, no-wrap +msgid "Be helpful" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/en/internals/001-yii-values.md +msgid "[Be simple](#be-simple)" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/en/internals/001-yii-values.md +msgid "[Be explicit](#be-explicit)" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/en/internals/001-yii-values.md +msgid "[Be consistent](#be-consistent)" +msgstr "" + +#. type: Title ### +#: ../src/en/internals/001-yii-values.md +#, no-wrap +msgid "High performance" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/en/internals/001-yii-values.md +#, no-wrap +msgid "Sensible defaults and flexibility" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/en/internals/001-yii-values.md +#, no-wrap +msgid "Be practice-oriented" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/001-yii-values.md +msgid "We prefer practice to theory. For example:" +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "Standard implementations should take practical use into account." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "Experience is at least as useful as theory in guiding design." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "Context is critical in determining appropriateness." +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/en/internals/001-yii-values.md +#, no-wrap +msgid "Be simple" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/001-yii-values.md +msgid "Solutions should be simple and expressive:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "We use as much complexity as needed and no more." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "We avoid ugly solutions unless there is no alternative." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "Fewer rules are better than more rules." +msgstr "" + +#. type: Title ### +#: ../src/en/internals/001-yii-values.md +#, no-wrap +msgid "Be Explicit" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "Loud fails are better than silent fails or masking errors." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "Explicit casts are better than PHP type juggling, type hints are good." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "No magic unless necessary." +msgstr "" + +#. type: Title ### +#: ../src/en/internals/001-yii-values.md +#, no-wrap +msgid "Be consistent" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/001-yii-values.md +msgid "We try to be consistent in:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "Code style" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "Naming" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "Design" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "Structure" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/001-yii-values.md +msgid "Values and goals" +msgstr "" diff --git a/_translations/po/it/internals_002-issue-workflow.md.po b/_translations/po/it/internals_002-issue-workflow.md.po new file mode 100644 index 00000000..190d82bc --- /dev/null +++ b/_translations/po/it/internals_002-issue-workflow.md.po @@ -0,0 +1,96 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/internals/002-issue-workflow.md +#, no-wrap +msgid "002 — Issue workflow" +msgstr "" + +#. type: Plain text +#: ../src/internals/002-issue-workflow.md +msgid "The process of handing incoming issues is the following:" +msgstr "" + +#. type: Plain text +#: ../src/internals/002-issue-workflow.md +msgid "![Issue workflow schema](/images/internals/002-issue-workflow.svg)" +msgstr "" + +#. type: Title ## +#: ../src/internals/002-issue-workflow.md +#, no-wrap +msgid "Roles" +msgstr "" + +#. type: Plain text +#: ../src/internals/002-issue-workflow.md +msgid "We've many roles:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/002-issue-workflow.md +msgid "Process managers - initially triage issues and manage labels." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/002-issue-workflow.md +msgid "Decision makers - participate in discussions moving them to resolutions." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/002-issue-workflow.md +msgid "Bug hunters - verifying bugs." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/002-issue-workflow.md +msgid "Contributors - create code for pull requests." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/002-issue-workflow.md +msgid "Code reviewers - review pull requests." +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/internals/002-issue-workflow.md +#, no-wrap +msgid "Labels" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/internals/002-issue-workflow.md +#, no-wrap +msgid "Milestones" +msgstr "" + +#. 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 "" diff --git a/_translations/po/it/internals_003-roadmap.md.po b/_translations/po/it/internals_003-roadmap.md.po new file mode 100644 index 00000000..4dab4dfe --- /dev/null +++ b/_translations/po/it/internals_003-roadmap.md.po @@ -0,0 +1,624 @@ +# Italian 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: 2025-12-24 08:02+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title ## +#: ../src/index.md ../src/internals/003-roadmap.md +#, no-wrap +msgid "Documentation" +msgstr "Documentazione" + +#. type: Title ## +#: ../src/cookbook/sentry-integration.md ../src/internals/003-roadmap.md +#, no-wrap +msgid "Console" +msgstr "" + +#. type: Title # +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "003 — Roadmap" +msgstr "" + +#. type: Plain text +#: ../src/internals/003-roadmap.md +msgid "We want Yii 3 to:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "Not limit a developer to choosing architecture. Allow anything from \"classic\" MVC to DDD." +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "Keep the most good things from Yii 2." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "Be more open to the global PHP community and infrastructure." +msgstr "" + +#. type: Title ## +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "PSRs compliance" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "PSR-3 Logger" +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Framework packages should depend on interface only." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Split drivers into packages." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Clean-up code." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +#, fuzzy +#| msgid "[Files](https://github.com/yiisoft/files/)" +msgid "[x] [Fix email target](https://github.com/yiisoft/log-target-email)." +msgstr "[File](https://github.com/yiisoft/files/)" + +#. type: Title ### +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "PSR-4 Autoloading" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Autoloading is fine already." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Document on how it works." +msgstr "" + +#. type: Title ### +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "PSR-7 HTTP message" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Remove our own implementation. At least for now." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Framework packages should depend on interfaces only." +msgstr "" + +#. type: Title ### +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "PSR-11 Container" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Finish refactoring." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Remove all framework-specific implementations from the package. Move to a framework." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +#, fuzzy +#| msgid "[Files](https://github.com/yiisoft/files/)" +msgid "[x] [Implement autoloader fallback](https://github.com/yiisoft/di/issues/88)" +msgstr "[File](https://github.com/yiisoft/files/)" + +#. type: Title ### +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "PSR-12 Code style" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Make sure the code follows it." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Automate fixing style before release." +msgstr "" + +#. type: Title ### +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "PSR-14 Event dispatcher" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +#, fuzzy +#| msgid "[VarDumper](https://github.com/yiisoft/var-dumper)" +msgid "[x] [Implement as a separate library](https://github.com/yiisoft/event-dispatcher)." +msgstr "[VarDumper](https://github.com/yiisoft/var-dumper)" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Use in other packages." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Polish." +msgstr "" + +#. type: Title ### +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "PSR-15 HTTP handlers" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Rewrite HTTP flow to PSR-7 request-response + formatting response via emitter." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Offer SAPI emitter out of the box." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Make it possible to use alternative emitters such as RoadRunner." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Support middleware." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Implement filters as middleware:" +msgstr "" + +#. type: Bullet: ' - ' +#: ../src/internals/003-roadmap.md +#, fuzzy +#| msgid "[Files](https://github.com/yiisoft/files/)" +msgid "[x] [Rate limiting](https://github.com/yiisoft/yii-web/issues/63)" +msgstr "[File](https://github.com/yiisoft/files/)" + +#. type: Bullet: ' - ' +#: ../src/internals/003-roadmap.md +#, fuzzy +#| msgid "[Files](https://github.com/yiisoft/files/)" +msgid "[x] [Authentication](https://github.com/yiisoft/yii-web/issues/114)" +msgstr "[File](https://github.com/yiisoft/files/)" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Re-implement router w/ middleware support for route groups." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Filters should be middlewares." +msgstr "" + +#. type: Title ### +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "PSR-16 Simple cache" +msgstr "" + +#. 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 "" + +#. type: Title ### +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "PSR-17 HTTP factories" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Use PSR factories." +msgstr "" + +#. type: Title ### +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "PSR-18 HTTP client" +msgstr "" + +#. type: Title ## +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "Stricter types" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Make sure type hinting is used everywhere." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Make sure types are as definitive as possible. Avoid varying types if possible." +msgstr "" + +#. type: Title ## +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "Single application template" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Drop basic/advanced." +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "Router" +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] DSL for configuration." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Ability to route to any callable." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Named routes." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Route groups w/ middleware support." +msgstr "" + +#. type: Title ## +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "Best practices and SOLID compliance of all classes/packages" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Make sure interfaces follow the \"interface segregation\" principle." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Don't use public properties." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Don't use `init()`." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Don't inherit from `BaseObject` or `Component`. Remove these." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] No globals." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] No static calls except helpers that are final." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Prefer throwing exceptions to fixing input." +msgstr "" + +#. type: Title ## +#: ../src/internals/003-roadmap.md +#, fuzzy, no-wrap +#| msgid "Development tools" +msgid "Development toolkit" +msgstr "Strumenti di sviluppo" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Release command line tool" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Development command line tool (symlinks packages into usable application)" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Separate web and console application" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Possibly eliminate base application (still needed)" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Create an interface for the console (using Symfony one)" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Implementation may be one of the popular ones (using Symfony one)" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Ensure application can add commands via config" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[ ] Follow best practices." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[ ] Don't use the \"MVC\" term." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[ ] Upgrading from Yii 2." +msgstr "" + +#. type: Title ## +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "RBAC" +msgstr "" + +#. type: Plain text +#: ../src/internals/003-roadmap.md +msgid "RBAC is implemented as [a framework-independent package](https://github.com/yiisoft/rbac)." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Make sure it follows best practices." +msgstr "" + +#. type: Title ## +#: ../src/internals/003-roadmap.md +#, fuzzy, no-wrap +#| msgid "Views" +msgid "View" +msgstr "Viste" + +#. type: Plain text +#: ../src/internals/003-roadmap.md +msgid "View is implemented as [framework-independent package](https://github.com/yiisoft/view)." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +#, fuzzy +#| msgid "[Strings](https://github.com/yiisoft/strings)" +msgid "[x] Finish refactoring ([see issues](https://github.com/yiisoft/view/issues))." +msgstr "[Stringhe](https://github.com/yiisoft/strings)" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Port widgets." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Rethink and implement active form widgets." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Implement caching widgets." +msgstr "" + +#. type: Title ## +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "Data abstractions and grid" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +#, fuzzy +#| msgid "[Strings](https://github.com/yiisoft/strings)" +msgid "[x] Finish [data abstractions](https://github.com/yiisoft/data)." +msgstr "[Stringhe](https://github.com/yiisoft/strings)" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "Validators" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +#, fuzzy +#| msgid "[Strings](https://github.com/yiisoft/strings)" +msgid "[x] Finish [the main package](https://github.com/yiisoft/validator) redesign" +msgstr "[Stringhe](https://github.com/yiisoft/strings)" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Port necessary validators" +msgstr "" + +#. type: Title ## +#: ../src/internals/003-roadmap.md +#, fuzzy, no-wrap +#| msgid "Debug toolbar and debugger" +msgid "Debug toolbar" +msgstr "Barra degli strumenti di debug e debugger" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Port debug toolbar." +msgstr "" + +#. type: Title ## +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "Gii" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Port Gii." +msgstr "" + +#. type: Title ## +#: ../src/internals/003-roadmap.md +#, no-wrap +msgid "Infrastructure" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +#, fuzzy +#| msgid "[Json](https://github.com/yiisoft/json)" +msgid "[x] Cover [config](https://github.com/yiisoft/config) with tests." +msgstr "[Json](https://github.com/yiisoft/json)" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +#, fuzzy +#| msgid "[Json](https://github.com/yiisoft/json)" +msgid "[x] Release stable [config](https://github.com/yiisoft/config)." +msgstr "[Json](https://github.com/yiisoft/json)" + +#. type: Title ## +#: ../src/internals/003-roadmap.md ../src/internals/022-config-groups.md +#, no-wrap +msgid "Others" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] [Decide on namespaces](https://forum.yiiframework.com/t/lowercase-or-camelcase-namespaces/124983/52)." +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +msgid "[x] Make validators independent of models to allow reusing them in handlers." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/003-roadmap.md +#, fuzzy +#| msgid "[Files](https://github.com/yiisoft/files/)" +msgid "[x] [Split IdentityInterface](https://github.com/yiisoft/yii2/issues/13825)." +msgstr "[File](https://github.com/yiisoft/files/)" diff --git a/_translations/po/it/internals_004-namespaces.md.po b/_translations/po/it/internals_004-namespaces.md.po new file mode 100644 index 00000000..dc960ed8 --- /dev/null +++ b/_translations/po/it/internals_004-namespaces.md.po @@ -0,0 +1,82 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\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 "" + +#. type: Title # +#: ../src/en/internals/004-namespaces.md +#, no-wrap +msgid "004 — Namespaces" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/004-namespaces.md +msgid "Package namespace rules are the following:" +msgstr "" + +#. type: Bullet: '1. ' +#: ../src/en/internals/004-namespaces.md +msgid "PascalCase is used for namespace parts." +msgstr "" + +#. type: Bullet: '2. ' +#: ../src/en/internals/004-namespaces.md +msgid "Root vendor namespace is `Yiisoft`." +msgstr "" + +#. type: Bullet: '3. ' +#: ../src/en/internals/004-namespaces.md +msgid "Package name parts are used in namespace." +msgstr "" + +#. type: Bullet: '4. ' +#: ../src/en/internals/004-namespaces.md +msgid "Adjective is added to a noun and is a single part." +msgstr "" + +#. type: Plain text +#: ../src/en/internals/004-namespaces.md +msgid "Some examples:" +msgstr "" + +#. 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 "" + +#. 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 "" diff --git a/_translations/po/it/internals_005-development-tool.md.po b/_translations/po/it/internals_005-development-tool.md.po new file mode 100644 index 00000000..a93a650f --- /dev/null +++ b/_translations/po/it/internals_005-development-tool.md.po @@ -0,0 +1,85 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/en/internals/005-development-tool.md +#, fuzzy, no-wrap +#| msgid "Development tools" +msgid "005 — Yii development tool" +msgstr "Strumenti di sviluppo" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" diff --git a/_translations/po/it/internals_006-git-commit-messages.md.po b/_translations/po/it/internals_006-git-commit-messages.md.po new file mode 100644 index 00000000..b4b22ea0 --- /dev/null +++ b/_translations/po/it/internals_006-git-commit-messages.md.po @@ -0,0 +1,76 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\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 "" + +#. type: Title # +#: ../src/en/internals/006-git-commit-messages.md +#, no-wrap +msgid "006 — Git commit messages" +msgstr "" + +#. type: Title ## +#: ../src/en/internals/006-git-commit-messages.md +#, no-wrap +msgid "Subject line" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/006-git-commit-messages.md +msgid "Use `#123` to reference issue by number" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/006-git-commit-messages.md +msgid "Use imperative mood that's `Fix`, not `Fixed`" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/006-git-commit-messages.md +msgid "Don't add a period at the end" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/006-git-commit-messages.md +msgid "Use `[skip ci]` if there is no need to run unit tests" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/006-git-commit-messages.md +msgid "Start with a capital letter" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/006-git-commit-messages.md +msgid "Limit to 50 characters" +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/en/internals/006-git-commit-messages.md +msgid "Limit line length to 72 characters" +msgstr "" diff --git a/_translations/po/it/internals_007-exceptions.md.po b/_translations/po/it/internals_007-exceptions.md.po new file mode 100644 index 00000000..11e1430e --- /dev/null +++ b/_translations/po/it/internals_007-exceptions.md.po @@ -0,0 +1,70 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\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 "" + +#. type: Title # +#: ../src/en/internals/007-exceptions.md +#, no-wrap +msgid "007 — Exceptions" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/007-exceptions.md +msgid "Throw exceptions instead of returning an error code." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/007-exceptions.md +msgid "Exception class name must be suffixed with `Exception`." +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/en/internals/007-exceptions.md +msgid "`\\InvalidArgumentException` must be used directly. There should be no exceptions inherited from it." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/007-exceptions.md +msgid "`\\InvalidArgumentException` must never be caught." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/007-exceptions.md +msgid "[International community discussion and poll](https://forum.yiiframework.com/t/naming-exceptions/126613/6)" +msgstr "" + +#. 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 "" diff --git a/_translations/po/it/internals_008-interfaces.md.po b/_translations/po/it/internals_008-interfaces.md.po new file mode 100644 index 00000000..6eb2d6ed --- /dev/null +++ b/_translations/po/it/internals_008-interfaces.md.po @@ -0,0 +1,50 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\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 "" + +#. type: Title # +#: ../src/en/internals/008-interfaces.md +#, no-wrap +msgid "008 — Interfaces" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/008-interfaces.md +msgid "Interface name should be suffixed with `Interface`." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/008-interfaces.md +msgid "[International community discussion and poll](https://forum.yiiframework.com/t/naming-interfaces/126612/5)" +msgstr "" + +#. 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 "" diff --git a/_translations/po/it/internals_009-design-decisions.md.po b/_translations/po/it/internals_009-design-decisions.md.po new file mode 100644 index 00000000..0735493c --- /dev/null +++ b/_translations/po/it/internals_009-design-decisions.md.po @@ -0,0 +1,196 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/en/internals/009-design-decisions.md +#, no-wrap +msgid "009 — Design Decisions" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/009-design-decisions.md +msgid "In this document, we list important design decisions taken during Yii3 development." +msgstr "" + +#. type: Title ## +#: ../src/en/internals/009-design-decisions.md +#, no-wrap +msgid "Remove magic properties" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/en/internals/009-design-decisions.md +#, no-wrap +msgid "Remove the service locator" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/en/internals/009-design-decisions.md +#, no-wrap +msgid "Extract general packages" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/en/internals/009-design-decisions.md +msgid "Increased usage and contribution" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/009-design-decisions.md +msgid "Yii team could delegate maintenance" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/009-design-decisions.md +msgid "Independent releases are possible" +msgstr "" + +#. type: Title ## +#: ../src/en/internals/009-design-decisions.md +#, no-wrap +msgid "Adopt PSRs" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/en/internals/009-design-decisions.md +#, no-wrap +msgid "Improve DI container" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/en/internals/009-design-decisions.md +#, no-wrap +msgid "Adopt strict types" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/009-design-decisions.md +msgid "Strict types were introduced because:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/009-design-decisions.md +msgid "PHP 7 is now mainstream" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/en/internals/009-design-decisions.md +#, no-wrap +msgid "Adopt SemVer" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/009-design-decisions.md +msgid "Yii 2 has its own version policy. Problems:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/009-design-decisions.md +msgid "It wasn't standard" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/009-design-decisions.md +msgid "Composer relies on SemVer" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/en/internals/009-design-decisions.md +#, no-wrap +msgid "Prevent validators mutating data" +msgstr "" + +#. 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 "" + +#. 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 "" diff --git a/_translations/po/it/internals_010-code-style.md.po b/_translations/po/it/internals_010-code-style.md.po new file mode 100644 index 00000000..7ce3e2b7 --- /dev/null +++ b/_translations/po/it/internals_010-code-style.md.po @@ -0,0 +1,449 @@ +# Italian 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 10:28+0000\n" +"PO-Revision-Date: 2025-12-27 10:28+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title ## +#: ../src/guide/databases/db-migrations.md ../src/internals/010-code-style.md +#, no-wrap +msgid "Strings" +msgstr "" + +#. type: Title # +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "010 — Code style" +msgstr "" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Code formatting used in Yii 3 packages is based on [PSR-1](https://www.php-fig.org/psr/psr-1/) and [PSR-12](https://www.php-fig.org/psr/psr-12/) with extra rules added on top of it." +msgstr "" + +#. type: Title ### +#: ../src/internals/010-code-style.md ../src/internals/017-tags.md +#: ../src/internals/018-widgets.md +#, no-wrap +msgid "Names" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "Use English only." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "Use camelCase notation, including abbreviations (e.g., `enableIdn`)." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "Use the shortest possible, but an explanatory name." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "Never trim or abbreviate a name." +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Types" +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "[Use types for properties](https://wiki.php.net/rfc/typed_properties_v2)." +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Comments" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Class comment should describe the purpose of the class." +msgstr "" + +#. type: Plain text +#: ../src/internals/010-code-style.md +#, fuzzy +#| msgid "[Yii DB](https://github.com/yiisoft/db/blob/master/docs/guide/en/README.md)" +msgid "[See PHPDoc](https://github.com/yiisoft/docs/blob/master/014-docs.md#phpdoc)." +msgstr "[Yii DB](https://github.com/yiisoft/db/blob/master/docs/guide/en/README.md)" + +#. type: Title ## +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Formatting" +msgstr "" + +#. type: Title ### +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "No alignment" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Chain calls" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Fenced code block (php) +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "$object = $object->withName('test');\n" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "When no variables involved, use `'Hello!'`" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "To get variables into string prefer `\"Hello, $username!\"`" +msgstr "" + +#. type: Title ## +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Classes and interfaces" +msgstr "" + +#. type: Title ### +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Final by default" +msgstr "" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Classes should be `final` by default." +msgstr "" + +#. type: Title ### +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Private by default" +msgstr "" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Constants, properties and methods should be private by default." +msgstr "" + +#. type: Title ### +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Composition over inheritance" +msgstr "" + +#. type: Plain text +#: ../src/internals/010-code-style.md +#, fuzzy +#| msgid "[Dependency injection container](concept/di-container.md)" +msgid "Prefer [composition to inheritance](guide/en/concept/di-container.md)." +msgstr "[Contenitore d’iniezione delle dipendenze](concept/di-container.md)" + +#. type: Title ### +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Property, constant and method order" +msgstr "" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Order should be the following:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "Constants" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "Properties" +msgstr "" + +#. type: Title ## +#: ../src/internals/010-code-style.md ../src/internals/017-tags.md +#: ../src/internals/018-widgets.md +#, no-wrap +msgid "Methods" +msgstr "" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Within each category, items should be sorted by visibility:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "public" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "protected" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "private" +msgstr "" + +#. type: Title ### +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Abstract classes" +msgstr "" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Abstract classes *shouldn't* be prefixed or postfixed with `Abstract`." +msgstr "" + +#. type: Title #### +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Immutable methods" +msgstr "" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Immutable method convention is the following:" +msgstr "" + +#. 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 "" + +#. type: Bullet: '1. ' +#: ../src/internals/010-code-style.md +msgid "Cloned object name is `$new`." +msgstr "" + +#. type: Bullet: '2. ' +#: ../src/internals/010-code-style.md +msgid "Return type is `self`." +msgstr "" + +#. type: Title #### +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Boolean check methods" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title #### +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Flags in methods " +msgstr "" + +#. 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 "" + +#. type: Fenced code block (php) +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "public function login(bool $refreshPage = true): void;\n" +msgstr "" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "It is better to be two methods:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Variables" +msgstr "" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Add an underscore (`_`) prefix for unused variables. For example:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Imports" +msgstr "" + +#. type: Plain text +#: ../src/internals/010-code-style.md +msgid "Prefer importing classes and functions to using fully qualified names:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/internals/010-code-style.md +#, no-wrap +msgid "Additional conventions" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "[Namespaces](004-namespaces.md)" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +#, fuzzy +#| msgid "[Actions](structure/action.md)" +msgid "[Exceptions](007-exceptions.md)" +msgstr "[Azioni](structure/action.md)" + +#. type: Bullet: '- ' +#: ../src/internals/010-code-style.md +msgid "[Interfaces](008-interfaces.md)" +msgstr "" diff --git a/_translations/po/it/internals_011-error-correction.md.po b/_translations/po/it/internals_011-error-correction.md.po new file mode 100644 index 00000000..5ba67675 --- /dev/null +++ b/_translations/po/it/internals_011-error-correction.md.po @@ -0,0 +1,28 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/en/internals/011-error-correction.md +#, no-wrap +msgid "011 — Error correction" +msgstr "" + +#. 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 "" diff --git a/_translations/po/it/internals_012-tests.md.po b/_translations/po/it/internals_012-tests.md.po new file mode 100644 index 00000000..e0e1bceb --- /dev/null +++ b/_translations/po/it/internals_012-tests.md.po @@ -0,0 +1,73 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/en/internals/012-tests.md +#, no-wrap +msgid "012 — Tests" +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/en/internals/012-tests.md +msgid "Test class should be marked as `final` by default." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/012-tests.md +msgid "`@test` annotation must not be used, prefix methods with `test`." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/012-tests.md +msgid "The test method name must reflect the purpose of the test." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/012-tests.md +msgid "\"should\" must not be used in the test method name." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/012-tests.md +msgid "If necessary, the test method phpdoc may describe the desired behavior." +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/en/internals/012-tests.md +msgid "There must be one test case per test method that's a single AAA." +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/en/internals/012-tests.md +msgid "Tests shouldn't rely on composer-config-plugin and DI container unless necessary." +msgstr "" diff --git a/_translations/po/it/internals_013-code-review.md.po b/_translations/po/it/internals_013-code-review.md.po new file mode 100644 index 00000000..18cfa5b1 --- /dev/null +++ b/_translations/po/it/internals_013-code-review.md.po @@ -0,0 +1,120 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/en/internals/013-code-review.md +#, no-wrap +msgid "013 — Code review" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/en/internals/013-code-review.md +#, no-wrap +msgid "Guidelines" +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/en/internals/013-code-review.md +msgid "Does the pull request make sense overall?" +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/en/internals/013-code-review.md +msgid "Read all lines of code in the pull request." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/013-code-review.md +msgid "Could it be done simpler?" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/013-code-review.md +msgid "Are there security issues?" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/013-code-review.md +msgid "Are there performance issues?" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/013-code-review.md +msgid "When leaving comments, be polite." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/013-code-review.md +msgid "Avoid code-formatting comments." +msgstr "" + +#. type: Title ## +#: ../src/en/internals/013-code-review.md +#, no-wrap +msgid "Mandatory parts" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/013-code-review.md +msgid "[ ] Tests that fail without code and pass with code." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/013-code-review.md +msgid "[ ] Type hints." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/013-code-review.md +msgid "[ ] `declare(strict_types=1)`." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/013-code-review.md +msgid "[ ] Documentation: phpdoc, yiisoft/docs." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/013-code-review.md +msgid "[ ] Changelog entry (if package is stable)." +msgstr "" diff --git a/_translations/po/it/internals_014-docs.md.po b/_translations/po/it/internals_014-docs.md.po new file mode 100644 index 00000000..6581ceb8 --- /dev/null +++ b/_translations/po/it/internals_014-docs.md.po @@ -0,0 +1,362 @@ +# Italian 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-09 11:54+0000\n" +"PO-Revision-Date: 2025-12-24 08:02+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/internals/014-docs.md +#, no-wrap +msgid "014 — Documentation" +msgstr "" + +#. type: Plain text +#: ../src/internals/014-docs.md +msgid "Documentation is one of the most important parts of Yii." +msgstr "" + +#. type: Title ## +#: ../src/internals/014-docs.md +#, fuzzy, no-wrap +#| msgid "Generating API documentation" +msgid "Package documentation" +msgstr "Generazione della documentazione API" + +#. 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 "" + +#. type: Plain text +#: ../src/internals/014-docs.md +msgid "Some indicators that it's time to create `docs`:" +msgstr "" + +#. type: Bullet: '1. ' +#: ../src/internals/014-docs.md +msgid "There is a need for translation." +msgstr "" + +#. type: Bullet: '2. ' +#: ../src/internals/014-docs.md +msgid "Many topics exist. Each of these is big by itself." +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/internals/014-docs.md +#, fuzzy, no-wrap +#| msgid "The definitive guide to Yii3" +msgid "Definitive guide" +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." +msgstr "" + +#. type: Plain text +#: ../src/internals/014-docs.md +msgid "The guide should follow [Micosoft style guide](https://learn.microsoft.com/en-us/style-guide/welcome/)." +msgstr "" + +#. type: Title ### +#: ../src/internals/014-docs.md +#, no-wrap +msgid "Translation" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/internals/014-docs.md +msgid "Translation algorithm:" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "Translate necessary strings and push the changes" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "Open a pull request to the main repository" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/internals/014-docs.md +msgid "If you have changed English and want to update translations:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "Pull updated branch after successful completion of workflow `Update docs translation` in GitHub Action" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "Update translation in `.po` files by `Poedit`" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "Push changes" +msgstr "" + +#. type: Title ## +#: ../src/internals/014-docs.md +#, no-wrap +msgid "Blocks" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/internals/014-docs.md +#, no-wrap +msgid "PHPDoc" +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Plain text +#: ../src/internals/014-docs.md +msgid "PHPDoc, if present, should describe the purpose of the element it's added for." +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/internals/014-docs.md +msgid "Example of incorrect code:" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/internals/014-docs.md +msgid "Example of a valid code:" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/internals/014-docs.md +#, no-wrap +msgid "Readme checklist" +msgstr "" + +#. type: Plain text +#: ../src/internals/014-docs.md +msgid "Each package readme should be placed into `README.md` and contain the following:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "[ ] Logo." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "[ ] Short description of the package. What does it do?" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "[ ] Quality badges (build, code coverage)." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "[ ] Screenshot (if applicable)." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "[ ] Requirements." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "[ ] Installation. Usually `composer require`." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "[ ] Getting started. One or two common usage examples are demonstrated." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "[ ] Configuration." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "[ ] Contributing. It should contain a link to guidelines." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "[ ] Running tests." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/014-docs.md +msgid "[ ] License." +msgstr "" diff --git a/_translations/po/it/internals_015-phpstorm.md.po b/_translations/po/it/internals_015-phpstorm.md.po new file mode 100644 index 00000000..0d330534 --- /dev/null +++ b/_translations/po/it/internals_015-phpstorm.md.po @@ -0,0 +1,135 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/en/internals/015-phpstorm.md +#, no-wrap +msgid "015 — PhpStorm metadata and attributes" +msgstr "" + +#. type: Title ## +#: ../src/en/internals/015-phpstorm.md +#, no-wrap +msgid "PhpStorm metadata" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/en/internals/015-phpstorm.md +msgid "We use the following set of coding styles for metadata." +msgstr "" + +#. type: Title ### +#: ../src/en/internals/015-phpstorm.md +#, no-wrap +msgid "Metadata location" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/015-phpstorm.md +msgid "Metadata should be placed in `/.phpstorm.meta.php` directory." +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/en/internals/015-phpstorm.md +#, no-wrap +msgid "Constants " +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/en/internals/015-phpstorm.md +#, no-wrap +msgid "PhpStorm attributes" +msgstr "" + +#. 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 "" + +#. type: Fenced code block (shell) +#: ../src/en/internals/015-phpstorm.md +#, no-wrap +msgid "composer require --dev jetbrains/phpstorm-attributes\n" +msgstr "" + +#. type: Title ### +#: ../src/en/internals/015-phpstorm.md +#, no-wrap +msgid "Using with ComposerRequireChecker" +msgstr "" + +#. 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 "" + +#. 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 "" diff --git a/_translations/po/it/internals_016-security-workflow.md.po b/_translations/po/it/internals_016-security-workflow.md.po new file mode 100644 index 00000000..280cd863 --- /dev/null +++ b/_translations/po/it/internals_016-security-workflow.md.po @@ -0,0 +1,139 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/en/internals/016-security-workflow.md +#, no-wrap +msgid "016 — Security workflow" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/016-security-workflow.md +msgid "Security issues are typically sent via [a security form](https://www.yiiframework.com/security)." +msgstr "" + +#. type: Plain text +#: ../src/en/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 "" + +#. type: Title ## +#: ../src/en/internals/016-security-workflow.md +#, no-wrap +msgid "Verify" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/016-security-workflow.md +msgid "Verify that the issue is valid. Request more information if needed." +msgstr "" + +#. type: Title ## +#: ../src/en/internals/016-security-workflow.md +#, no-wrap +msgid "Add security advisory" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/016-security-workflow.md +msgid "Create a draft GitHub security advisory." +msgstr "" + +#. type: Title ### +#: ../src/en/internals/016-security-workflow.md +#, no-wrap +msgid "Find out severity" +msgstr "" + +#. type: Bullet: '1. ' +#: ../src/en/internals/016-security-workflow.md +msgid "Get CVSS score using [NVD calculator](https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator)." +msgstr "" + +#. type: Bullet: '2. ' +#: ../src/en/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 "" + +#. type: Title ### +#: ../src/en/internals/016-security-workflow.md +#, no-wrap +msgid "Give credit to the reporter" +msgstr "" + +#. type: Plain text +#: ../src/en/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 "" + +#. type: Title ## +#: ../src/en/internals/016-security-workflow.md +#, no-wrap +msgid "Request a CVE number" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/016-security-workflow.md +msgid "When you're ready, request a CVE." +msgstr "" + +#. type: Title ## +#: ../src/en/internals/016-security-workflow.md +#, no-wrap +msgid "Prepare a patch" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/016-security-workflow.md +msgid "Prepare a pull request fixing the issue. GitHub allows doing it in a private fork." +msgstr "" + +#. type: Title ## +#: ../src/en/internals/016-security-workflow.md +#, no-wrap +msgid "Wait till the CVE number is allocated " +msgstr "" + +#. type: Plain text +#: ../src/en/internals/016-security-workflow.md +msgid "It usually takes several days." +msgstr "" + +#. type: Title ## +#: ../src/en/internals/016-security-workflow.md +#, no-wrap +msgid "Release" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/016-security-workflow.md +msgid "Merge the patch pull request right before tagging the next package release." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/016-security-workflow.md +msgid "Publish security advisory." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/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 "" diff --git a/_translations/po/it/internals_017-tags.md.po b/_translations/po/it/internals_017-tags.md.po new file mode 100644 index 00000000..1d8bd4c5 --- /dev/null +++ b/_translations/po/it/internals_017-tags.md.po @@ -0,0 +1,127 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title # +#: ../src/en/internals/017-tags.md +#, no-wrap +msgid "017 - Tags" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +#, no-wrap +msgid "Class names" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/017-tags.md +msgid "Tags aren't postfixed or prefixed unless it's an abstract base class." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/017-tags.md +msgid "If the tag represents a specification, use a name used in the specification." +msgstr "" + +#. type: Title ## +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +#, no-wrap +msgid "Inheritance" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +msgid "Inheritance is allowed with some restrictions:" +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +msgid "Hierarchy should be kept as linear as possible." +msgstr "" + +#. type: Plain text +#: ../src/en/internals/017-tags.md +msgid "Tags should:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +msgid "Have no state." +msgstr "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +#, no-wrap +msgid "Boolean flags" +msgstr "" + +#. 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 "" diff --git a/_translations/po/it/internals_018-widgets.md.po b/_translations/po/it/internals_018-widgets.md.po new file mode 100644 index 00000000..499c056c --- /dev/null +++ b/_translations/po/it/internals_018-widgets.md.po @@ -0,0 +1,117 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\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 "" + +#. 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 "" + +#. 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 "" + +#. type: Title ## +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +#, no-wrap +msgid "Class names" +msgstr "" + +#. type: Title ## +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +#, no-wrap +msgid "Inheritance" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +msgid "Inheritance is allowed with some restrictions:" +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +msgid "Hierarchy should be kept as linear as possible." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +msgid "Have no state." +msgstr "" + +#. 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 "" + +#. 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 "" + +#. type: Title ### +#: ../src/en/internals/017-tags.md ../src/en/internals/018-widgets.md +#, no-wrap +msgid "Boolean flags" +msgstr "" + +#. 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 "" + +#. type: Title # +#: ../src/en/internals/018-widgets.md +#, no-wrap +msgid "018 - Widgets" +msgstr "" + +#. 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 "" + +#. type: Plain text +#: ../src/en/internals/018-widgets.md +msgid "Widgets aren't postfixed or prefixed." +msgstr "" + +#. type: Plain text +#: ../src/en/internals/018-widgets.md +msgid "Widgets should:" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/018-widgets.md +msgid "Be immutable." +msgstr "" diff --git a/_translations/po/it/internals_019-view-code-style.md.po b/_translations/po/it/internals_019-view-code-style.md.po new file mode 100644 index 00000000..5b33bc98 --- /dev/null +++ b/_translations/po/it/internals_019-view-code-style.md.po @@ -0,0 +1,103 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/en/internals/019-view-code-style.md +#, no-wrap +msgid "019 — View code style" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/en/internals/019-view-code-style.md +#, no-wrap +msgid "Heading" +msgstr "" + +#. 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 "" + +#. type: Fenced code block (php) +#: ../src/en/internals/019-view-code-style.md +#, no-wrap +msgid "" +" \n" +"

getTitle()) ?>

\n" +"

getDescription()) ?>

\n" +"\n" +msgstr "" + +#. type: Title ## +#: ../src/en/internals/019-view-code-style.md +#, no-wrap +msgid "Short echo" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/019-view-code-style.md +msgid "Short echo is preferred:" +msgstr "" + +#. type: Fenced code block (php) +#: ../src/en/internals/019-view-code-style.md +#, no-wrap +msgid "\n" +msgstr "" + +#. type: Title ## +#: ../src/en/internals/019-view-code-style.md +#, no-wrap +msgid "Class methods" +msgstr "" + +#. 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 "" diff --git a/_translations/po/it/internals_020-package-release.md.po b/_translations/po/it/internals_020-package-release.md.po new file mode 100644 index 00000000..d7573706 --- /dev/null +++ b/_translations/po/it/internals_020-package-release.md.po @@ -0,0 +1,137 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/en/internals/020-package-release.md +#, no-wrap +msgid "020 — Package release" +msgstr "" + +#. type: Title ## +#: ../src/en/internals/020-package-release.md +#, no-wrap +msgid "Criteria" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/020-package-release.md +msgid "No critical issues." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/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 "" + +#. type: Bullet: '- ' +#: ../src/en/internals/020-package-release.md +msgid "All dependencies are stable." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/020-package-release.md +msgid "Close to 100% test coverage with, ideally, a 100% MSI score." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/020-package-release.md +msgid "README is alright." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/020-package-release.md +msgid "Everything is type-hinted unless special cases." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/020-package-release.md +msgid "Psalm analysis passes on at least level 2." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/020-package-release.md +msgid "phpdoc is alright." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/020-package-release.md +msgid "Public API is alright." +msgstr "" + +#. type: Title ## +#: ../src/en/internals/020-package-release.md +#, no-wrap +msgid "Release instruction" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/020-package-release.md +msgid "Release a package via [Yii Development Tool](005-development-tool.md)." +msgstr "" + +#. type: Plain text +#: ../src/en/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 "" + +#. type: Bullet: '2. ' +#: ../src/en/internals/020-package-release.md +msgid "Pull last changes from the `master` branch:" +msgstr "" + +#. type: Fenced code block (shell) +#: ../src/en/internals/020-package-release.md +#, no-wrap +msgid "" +"./yii-dev git/checkout master package-name\n" +"./yii-dev git/pull package-name\n" +msgstr "" + +#. type: Bullet: '3. ' +#: ../src/en/internals/020-package-release.md +msgid "Check the package for compliance with the criteria above." +msgstr "" + +#. type: Bullet: '4. ' +#: ../src/en/internals/020-package-release.md +msgid "Run `release/make` command:" +msgstr "" + +#. type: Fenced code block (shell) +#: ../src/en/internals/020-package-release.md +#, no-wrap +msgid "./yii-dev release/make package-name\n" +msgstr "" + +#. type: Bullet: '5. ' +#: ../src/en/internals/020-package-release.md +msgid "Select the version type (major, minor or path)." +msgstr "" + +#. type: Bullet: '6. ' +#: ../src/en/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 "" + +#. type: Bullet: '7. ' +#: ../src/en/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 "" diff --git a/_translations/po/it/internals_021-changelog-upgrade.md.po b/_translations/po/it/internals_021-changelog-upgrade.md.po new file mode 100644 index 00000000..0ab2cc06 --- /dev/null +++ b/_translations/po/it/internals_021-changelog-upgrade.md.po @@ -0,0 +1,131 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/en/internals/021-changelog-upgrade.md +#, no-wrap +msgid "021 — Changelog and upgrade" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/021-changelog-upgrade.md +msgid "For all released packages, we've a detailed changelog and upgrade guide." +msgstr "" + +#. type: Title ## +#: ../src/en/internals/021-changelog-upgrade.md +#, no-wrap +msgid "Changelog" +msgstr "" + +#. type: Plain text +#: ../src/en/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 "" + +#. type: Fenced code block (markdown) +#: ../src/en/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 "" + +#. type: Plain text +#: ../src/en/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 "" + +#. type: Bullet: '- ' +#: ../src/en/internals/021-changelog-upgrade.md +msgid "New — New features." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/021-changelog-upgrade.md +msgid "Chg — General changes." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/021-changelog-upgrade.md +msgid "Enh — Existing feature enhancements." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/021-changelog-upgrade.md +msgid "Bug — Bug fixes." +msgstr "" + +#. type: Plain text +#: ../src/en/internals/021-changelog-upgrade.md +msgid "In the changelog file lines should be ordered as New, Chg, Enh, Bug." +msgstr "" + +#. type: Plain text +#: ../src/en/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 "" + +#. type: Title ## +#: ../src/en/internals/021-changelog-upgrade.md +#, no-wrap +msgid "Upgrade" +msgstr "" + +#. type: Plain text +#: ../src/en/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 "" + +#. type: Plain text +#: ../src/en/internals/021-changelog-upgrade.md +msgid "The file name is `UPGRADE.md`. The format is the following:" +msgstr "" + +#. type: Fenced code block (markdown) +#: ../src/en/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 "" diff --git a/_translations/po/it/internals_022-config-groups.md.po b/_translations/po/it/internals_022-config-groups.md.po new file mode 100644 index 00000000..92c652a4 --- /dev/null +++ b/_translations/po/it/internals_022-config-groups.md.po @@ -0,0 +1,251 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\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 "" + +#. type: Title ## +#: ../src/en/guide/concept/configuration.md +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Parameters" +msgstr "" + +#. type: Title ## +#: ../src/en/internals/003-roadmap.md ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Others" +msgstr "" + +#. type: Title # +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "022 — Config groups" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Config group name postfixes" +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "\"console\" postfix applies to console" +msgstr "" + +#. 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 "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "\"web\" and \"console\" may override what's defined in \"common\"" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/022-config-groups.md +msgid "Application config parameters that are used in all configs." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`params` — common parameters" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`params-web` — web application parameters" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`params-console` — console application parameters" +msgstr "" + +#. type: Title ## +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Container" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/022-config-groups.md +#, fuzzy +#| msgid "[Strings](https://github.com/yiisoft/strings)" +msgid "Configuration for [yiisoft/di](https://github.com/yiisoft/di)." +msgstr "[Stringhe](https://github.com/yiisoft/strings)" + +#. type: Title ### +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Definitions" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di` — common container definitions" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-web` — web container definitions" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-console` — console container definitions" +msgstr "" + +#. type: Title ### +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Providers" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-providers` — common container providers" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-providers-web` — web container providers" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-providers-console` — console container providers" +msgstr "" + +#. type: Title ### +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Delegates" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-delegates` — common container delegates" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-delegates-web` — web container delegates" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-delegates-console` — console container delegates" +msgstr "" + +#. type: Title ### +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Tags" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-tags` — common container tags" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-tags-web` — web container tags" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`di-tags-console` — console container tags" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/022-config-groups.md +#, fuzzy +#| msgid "[Json](https://github.com/yiisoft/json)" +msgid "Configuration for [yiisoft/yii-event](https://github.com/yiisoft/yii-event)." +msgstr "[Json](https://github.com/yiisoft/json)" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`events` — common events" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`events-web` — web events" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`events-console` — console events" +msgstr "" + +#. type: Title ## +#: ../src/en/internals/022-config-groups.md +#, no-wrap +msgid "Bootstrap" +msgstr "" + +#. type: Plain text +#: ../src/en/internals/022-config-groups.md +msgid "Application bootstrapping for [yiisoft/yii-runner](https://github.com/yiisoft/yii-runner)." +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`bootstrap` — common bootstrap" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`bootstrap-web` — web bootstrap" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`bootstrap-console` — console bootstrap" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +#, fuzzy +#| msgid "[VarDumper](https://github.com/yiisoft/var-dumper)" +msgid "`routes` — [yiisoft/router](https://github.com/yiisoft/router) routes" +msgstr "[VarDumper](https://github.com/yiisoft/var-dumper)" + +#. type: Bullet: '- ' +#: ../src/en/internals/022-config-groups.md +msgid "`widgets` — [yiisoft/widget](https://github.com/yiisoft/widget) default widgets configuration" +msgstr "" diff --git a/_translations/po/it/internals_index.md.po b/_translations/po/it/internals_index.md.po new file mode 100644 index 00000000..25283c72 --- /dev/null +++ b/_translations/po/it/internals_index.md.po @@ -0,0 +1,149 @@ +# Italian 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: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. type: Title # +#: ../src/internals/index.md +#, no-wrap +msgid "Yii Framework Internals" +msgstr "" + +#. 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 "" + +#. type: Title ## +#: ../src/internals/index.md +#, no-wrap +msgid "Table of Contents" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[000 — Packages](000-packages.md) - Package structure and naming conventions" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[001 — Yii goal and values](001-yii-values.md) - Project goals and core values" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[002 — Issue workflow](002-issue-workflow.md) - How to handle issues" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[003 — Roadmap](003-roadmap.md) - Development roadmap and future plans" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[004 — Namespaces](004-namespaces.md) - Namespace conventions" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[005 — Yii development tool](005-development-tool.md) - Development tools for Yii packages" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[006 — Git commit messages](006-git-commit-messages.md) - Commit message format" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[007 — Exceptions](007-exceptions.md) - Exception handling guidelines" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[008 — Interfaces](008-interfaces.md) - Interface design principles" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[009 — Design Decisions](009-design-decisions.md) - Architectural and design decisions" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[010 — Code style](010-code-style.md) - PHP code style guidelines" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[011 — Error correction](011-error-correction.md) - Error handling and correction" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[012 — Tests](012-tests.md) - Testing guidelines and practices" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[013 — Code review](013-code-review.md) - Code review process and guidelines" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[014 — Documentation](014-docs.md) - Documentation writing guidelines" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[015 — PhpStorm metadata and attributes](015-phpstorm.md) - PhpStorm integration" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[016 — Security workflow](016-security-workflow.md) - Security issue handling" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[017 — Tags](017-tags.md) - Git tagging conventions" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[018 — Widgets](018-widgets.md) - Widget development guidelines" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[019 — View code style](019-view-code-style.md) - Code style for view templates" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[020 — Package release](020-package-release.md) - Release process for packages" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[021 — Changelog and upgrade](021-changelog-upgrade.md) - Maintaining changelogs and upgrade notes" +msgstr "" + +#. type: Bullet: '- ' +#: ../src/internals/index.md +msgid "[022 — Config groups](022-config-groups.md) - Configuration group organization" +msgstr "" diff --git a/_translations/po4a-base.conf b/_translations/po4a-base.conf index 8c92a99c..4a746522 100644 --- a/_translations/po4a-base.conf +++ b/_translations/po4a-base.conf @@ -1,4 +1,4 @@ -[po4a_langs] ru id es +[po4a_langs] ru id it es [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 9f53fb90..56b3328b 100644 --- a/_translations/po4a.conf +++ b/_translations/po4a.conf @@ -1,4 +1,4 @@ -[po4a_langs] ru id es +[po4a_langs] ru id it es [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/src/.vitepress/config.js b/src/.vitepress/config.js index b7bb14bc..b5267ae4 100644 --- a/src/.vitepress/config.js +++ b/src/.vitepress/config.js @@ -611,6 +611,222 @@ export default { } } }, + it: { + title: 'Documentazione Yii3', + label: 'Italiano', + lang: 'it', + themeConfig: { + nav: [ + {text: 'Guida', link: '/it/guide/'}, + {text: 'Ricettario', link: '/it/cookbook/'}, + {text: 'Interni', link: '/it/internals/'}, + {text: 'Sito', link: 'https://www.yiiframework.com'} + ], + sidebar: { + '/it/guide/': [ + { + text: 'Introduzione', + items: [ + {text: 'Informazioni su Yii', link: '/it/guide/intro/what-is-yii'}, + {text: 'Aggiornamento dalla versione 2', link: '/it/guide/intro/upgrade-from-v2'} + ] + }, + { + text: 'Per iniziare', + items: [ + {text: 'Requisiti', link: '/it/guide/start/prerequisites'}, + {text: 'Creazione di un progetto', link: '/it/guide/start/creating-project'}, + {text: 'Dire ciao', link: '/it/guide/start/hello'}, + {text: 'Lavorare con i moduli', link: '/it/guide/start/forms'}, + {text: 'Lavorare con i database', link: '/it/guide/start/databases'}, + {text: 'Generazione di codice con Gii', link: '/it/guide/start/gii'}, + {text: 'Prossimi passi', link: '/it/guide/start/looking-ahead'}, + {text: 'Flusso applicativo', link: '/it/guide/start/workflow'} + ] + }, + { + text: 'Concetti chiave', + items: [ + {text: 'Alias', link: '/it/guide/concept/aliases'}, + {text: 'Autoloading', link: '/it/guide/concept/autoloading'}, + {text: 'Configurazione', link: '/it/guide/concept/configuration'}, + {text: 'Contenitore DI', link: '/it/guide/concept/di-container'}, + {text: 'Eventi', link: '/it/guide/concept/events'}, + {text: 'Immutabilità', link: '/it/guide/concept/immutability'} + ] + }, + { + text: 'Struttura applicativa', + items: [ + {text: 'Panoramica', link: '/it/guide/structure/overview'}, + {text: 'Script di ingresso', link: '/it/guide/structure/entry-script'}, + {text: 'Applicazione', link: '/it/guide/structure/application'}, + {text: 'Gestori di richieste', link: '/it/guide/structure/handler'}, + {text: 'Azioni', link: '/it/guide/structure/action'}, + {text: 'Middleware', link: '/it/guide/structure/middleware'}, + {text: 'Dominio', link: '/it/guide/structure/domain'}, + {text: 'Servizio', link: '/it/guide/structure/service'}, + {text: 'Pacchetto', link: '/it/guide/structure/package'} + ] + }, + { + text: 'Gestione delle richieste', + items: [ + {text: 'Routing', link: '/it/guide/runtime/routing'}, + {text: 'Richieste', link: '/it/guide/runtime/request'}, + {text: 'Risposte', link: '/it/guide/runtime/response'}, + {text: 'Sessioni', link: '/it/guide/runtime/sessions'}, + {text: 'Cookie', link: '/it/guide/runtime/cookies'}, + {text: 'Gestione degli errori', link: '/it/guide/runtime/handling-errors'}, + {text: 'Logging', link: '/it/guide/runtime/logging'} + ] + }, + { + text: 'Sicurezza', + items: [ + {text: 'Panoramica', link: '/it/guide/security/overview'}, + {text: 'Autenticazione', link: '/it/guide/security/authentication'}, + {text: 'Autorizzazioni', link: '/it/guide/security/authorization'}, + {text: 'Lavorare con le password', link: '/it/guide/security/passwords'}, + {text: 'Crittografia', link: '/it/guide/security/cryptography'}, + {text: 'Richieste attendibili', link: '/it/guide/security/trusted-request'}, + {text: 'Migliori prassi', link: '/it/guide/security/best-practices'} + ] + }, + { + text: 'Caching', + items: [ + {text: 'Panoramica', link: '/it/guide/caching/overview'}, + {text: 'Caching dei dati', link: '/it/guide/caching/data'} + ] + }, + { + text: 'Lavorare con i database', + items: [ + {text: 'Migrazioni del database', link: '/it/guide/databases/db-migrations'} + ] + }, + { + text: 'Viste', + items: [ + {text: 'Viste', link: '/it/guide/views/view'}, + {text: 'Risorse', link: '/it/guide/views/asset'}, + {text: 'Script, stili e meta tag', link: '/it/guide/views/script-style-meta'}, + {text: 'Motori di template', link: '/it/guide/views/template-engines'}, + {text: 'Iniezione di parametri nella vista', link: '/it/guide/views/view-injections'}, + {text: 'Widget', link: '/it/guide/views/widget'} + ] + }, + { + text: 'Tutorial', + items: [ + {text: 'Applicazioni console', link: '/it/guide/tutorial/console-applications'}, + {text: 'Mailing', link: '/it/guide/tutorial/mailing'}, + {text: 'Motori di template', link: '/it/guide/tutorial/performance-tuning'}, + {text: 'Usare Yii con event loop', link: '/it/guide/tutorial/using-with-event-loop'}, + { + text: 'Usare Yii con RoadRunner', + link: '/it/guide/tutorial/using-yii-with-roadrunner' + }, + {text: 'Usare Yii con Swoole', link: '/it/guide/tutorial/using-yii-with-swoole'} + ] + }, + { + text: 'Glossario', + link: '/it/guide/glossary' + } + ], + '/it/cookbook/': [ + { + text: 'Ricettario', + items: [ + {text: 'Prefazione', link: '/it/cookbook/preface'}, + {text: 'Effettuare richieste HTTP', link: '/it/cookbook/making-http-requests'}, + { + text: 'Disattivazione della protezione CSRF', + link: '/it/cookbook/disabling-csrf-protection' + }, + {text: 'Integrazione Sentry', link: '/it/cookbook/sentry-integration'} + ] + }, + { + text: 'Configurazione dei server Web', + collapsed: false, + items: [ + {text: 'Generale', link: '/it/cookbook/configuring-webservers/general'}, + {text: 'Apache', link: '/it/cookbook/configuring-webservers/apache'}, + {text: 'Nginx', link: '/it/cookbook/configuring-webservers/nginx'}, + {text: 'Nginx Unit', link: '/it/cookbook/configuring-webservers/nginx-unit'}, + {text: 'IIS', link: '/it/cookbook/configuring-webservers/iis'}, + {text: 'Lighttpd', link: '/it/cookbook/configuring-webservers/lighttpd'} + ] + }, + { + text: 'Organizzare il codice', + items: [ + { + text: 'Sezioni verticali', + link: '/it/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices' + } + ] + }, + { + text: 'Distribuzione', + items: [ + {text: 'Docker Swarm', link: '/it/cookbook/deployment/docker-swarm'} + ] + } + ], + '/it/internals/': [ + { + text: 'Internals', + items: [ + {text: 'Pacchetti', link: '/it/internals/000-packages'}, + {text: 'I valori di Yii', link: '/it/internals/001-yii-values'}, + {text: 'Flusso di lavoro dei problemi', link: '/it/internals/002-issue-workflow'}, + {text: 'Roadmap', link: '/it/internals/003-roadmap'}, + {text: 'Namespace', link: '/it/internals/004-namespaces'}, + {text: 'Strumenti di sviluppo', link: '/it/internals/005-development-tool'}, + {text: 'Messaggi di commit Git', link: '/it/internals/006-git-commit-messages'}, + {text: 'Eccezioni', link: '/it/internals/007-exceptions'}, + {text: 'Interfacce', link: '/it/internals/008-interfaces'}, + {text: 'Decisioni di progettazione', link: '/it/internals/009-design-decisions'}, + {text: 'Stile del codice', link: '/it/internals/010-code-style'}, + {text: 'Correzione degli errori', link: '/it/internals/011-error-correction'}, + {text: 'Test', link: '/it/internals/012-tests'}, + {text: 'Revisione del codice', link: '/it/internals/013-code-review'}, + {text: 'Documentazione', link: '/it/internals/014-docs'}, + {text: 'PHPStorm', link: '/it/internals/015-phpstorm'}, + { + text: 'Flusso di lavoro della sicurezza', + link: '/it/internals/016-security-workflow' + }, + {text: 'Tag', link: '/it/internals/017-tags'}, + {text: 'Widget', link: '/it/internals/018-widgets'}, + {text: 'Stile del codice nelle viste', link: '/it/internals/019-view-code-style'}, + {text: 'Rilascio dei pacchetti', link: '/it/internals/020-package-release'}, + { + text: 'Registro delle modifiche e aggiornamenti', + link: '/it/internals/021-changelog-upgrade' + }, + {text: 'Gruppi di configurazione', link: '/it/internals/022-config-groups'} + ] + } + ] + }, + footer: { + message: 'Rilasciato sotto licenza BSD-3-Clause.', + copyright: `Copyright © 2008-${currentYear} Yii` + }, + docFooter: { + prev: 'Pagina precedente', + next: 'Pagina successiva', + }, + outline: { + label: 'In questa pagina' + }, + } + }, ru: { label: 'Русский', lang: 'ru', diff --git a/src/it/cookbook/configuring-webservers/apache.md b/src/it/cookbook/configuring-webservers/apache.md new file mode 100644 index 00000000..ec1c81a2 --- /dev/null +++ b/src/it/cookbook/configuring-webservers/apache.md @@ -0,0 +1,55 @@ +# Configuring web servers: Apache + +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`. + +```apache +# Set document root to be "app/public" +DocumentRoot "path/to/app/public" + + + # use mod_rewrite for pretty URL support + RewriteEngine on + + # if $showScriptName is false in UrlManager, do not allow accessing URLs with script name + RewriteRule ^index.php/ - [L,R=404] + + # If a directory or a file exists, use the request directly + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_FILENAME} !-d + + # Otherwise forward the request to index.php + RewriteRule . index.php + + SetEnv APP_ENV dev + + # ...other settings... + +``` + +In case you have `AllowOverride All` you can add `.htaccess` file with the +following configuration instead of using `httpd.conf`: + +```apache +# use mod_rewrite for pretty URL support +RewriteEngine on + +# if $showScriptName is false in UrlManager, do not allow accessing URLs with script name +RewriteRule ^index.php/ - [L,R=404] + +# If a directory or a file exists, use the request directly +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d + +# Otherwise forward the request to index.php +RewriteRule . index.php + +SetEnv APP_ENV dev + +# ...other settings... +``` + +In the above, note the usage of `SetEnv`. Since the Yii3 application +template is using environment variables, this is a possible place to set +them. In production environment remember to set `APP_ENV` to `prod`. diff --git a/src/it/cookbook/configuring-webservers/general.md b/src/it/cookbook/configuring-webservers/general.md new file mode 100644 index 00000000..bec3a60f --- /dev/null +++ b/src/it/cookbook/configuring-webservers/general.md @@ -0,0 +1,17 @@ +# Configuring web servers: General + +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. + +> [!IMPORTANT] +> If you're running your Yii application behind a reverse proxy, you might need to configure +> [Trusted proxies and headers](../../guide/security/trusted-request.md). + +## Specific server configurations + +- [Nginx](nginx.md) +- [Apache](apache.md) +- [Lighttpd](lighttpd.md) +- [Nginx Unit](nginx-unit.md) +- [IIS](iis.md) diff --git a/src/it/cookbook/configuring-webservers/iis.md b/src/it/cookbook/configuring-webservers/iis.md new file mode 100644 index 00000000..718ba6e5 --- /dev/null +++ b/src/it/cookbook/configuring-webservers/iis.md @@ -0,0 +1,38 @@ +# Configuring web servers: IIS + +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: + +```xml + + + + + + + + + + + + + + + + + + +``` + +Also, the following list of Microsoft's official resources could be useful +to configure PHP on IIS: + +1. [How to set up your first IIS + website](https://support.microsoft.com/en-us/help/323972/how-to-set-up-your-first-iis-web-site) +2. [Configure a PHP Website on + IIS](https://docs.microsoft.com/en-us/iis/application-frameworks/scenario-build-a-php-website-on-iis/configure-a-php-website-on-iis) diff --git a/src/it/cookbook/configuring-webservers/lighttpd.md b/src/it/cookbook/configuring-webservers/lighttpd.md new file mode 100644 index 00000000..551300c6 --- /dev/null +++ b/src/it/cookbook/configuring-webservers/lighttpd.md @@ -0,0 +1,7 @@ +# Configuring web servers: lighttpd + +To use [lighttpd](https://www.lighttpd.net/) >= 1.4.24, put `index.php` in the web root and add the following to the configuration: + +``` +url.rewrite-if-not-file = ("(.*)" => "/index.php/$0") +``` diff --git a/src/it/cookbook/configuring-webservers/nginx-unit.md b/src/it/cookbook/configuring-webservers/nginx-unit.md new file mode 100644 index 00000000..82beb7ab --- /dev/null +++ b/src/it/cookbook/configuring-webservers/nginx-unit.md @@ -0,0 +1,67 @@ +# Configuring web servers: NGINX Unit + +Run Yii-based apps using [NGINX Unit](https://unit.nginx.org/) with a PHP +language module. Here is a sample configuration. + +```json +{ + "listeners": { + "*:80": { + "pass": "routes/yii" + } + }, + + "routes": { + "yii": [ + { + "match": { + "uri": [ + "!/assets/*", + "*.php", + "*.php/*" + ] + }, + + "action": { + "pass": "applications/yii/direct" + } + }, + { + "action": { + "share": "/path/to/app/public/", + "fallback": { + "pass": "applications/yii/index" + } + } + } + ] + }, + + "applications": { + "yii": { + "type": "php", + "user": "www-data", + "environment": { + "APP_ENV": "dev" + }, + "targets": { + "direct": { + "root": "/path/to/app/public/" + }, + + "index": { + "root": "/path/to/app/public/", + "script": "index.php" + } + } + } + } +} +``` + +You can also [set up](https://unit.nginx.org/configuration/#php) your PHP +environment or supply a custom `php.ini` in the same configuration. + +In the above, note the usage of `environment`. Since the Yii3 application +template is using environment variables, this is a possible place to set +them. In production environment remember to set `APP_ENV` to `prod`. diff --git a/src/it/cookbook/configuring-webservers/nginx.md b/src/it/cookbook/configuring-webservers/nginx.md new file mode 100644 index 00000000..0e619aeb --- /dev/null +++ b/src/it/cookbook/configuring-webservers/nginx.md @@ -0,0 +1,63 @@ +# Configuring web servers: Nginx + +To use [Nginx](https://wiki.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. + +```nginx +server { + charset utf-8; + client_max_body_size 128M; + + listen 80; ## listen for ipv4 + #listen [::]:80 default_server ipv6only=on; ## listen for 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 / { + # Redirect everything that isn't a real file to index.php + try_files $uri $uri/ /index.php$is_args$args; + } + + # uncomment to avoid processing of calls to non-existing static files by Yii + #location ~ \.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ { + # try_files $uri =404; + #} + #error_page 404 /404.html; + + # deny accessing php files for the /assets directory + 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; + } +} +``` + +When you use this configuration, also set `cgi.fix_pathinfo=0` in the +`php.ini` file to avoid many unnecessary system `stat()` calls. + +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. + +In the above, note the usage of `fastcgi_param APP_ENV`. Since the Yii3 +application template is using environment variables, this is a possible +place to set them. In production environment remember to set `APP_ENV` to +`prod`. diff --git a/src/it/cookbook/deployment/docker-swarm-caddy.md b/src/it/cookbook/deployment/docker-swarm-caddy.md new file mode 100644 index 00000000..09d1df94 --- /dev/null +++ b/src/it/cookbook/deployment/docker-swarm-caddy.md @@ -0,0 +1,590 @@ +# Deploying Yii applications to Docker Swarm and Caddy + +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/)). + +```mermaid +graph LR + A[Internet] --> B[Reverse Proxy: Caddy] + B --> C[app1.example.com] + B --> D[app2.example.com] + + subgraph Docker Swarm Cluster + B + C + D + end +``` + +## Prerequisites + +- A server with a fresh installation of a Linux distribution (Ubuntu 22.04 + LTS or later recommended) +- A domain name pointing to your server's IP address +- SSH access to your server +- Basic knowledge of Docker and command-line tools + +## Server preparation + +### Install Docker + +For installation instructions, see the [official Docker +documentation](https://docs.docker.com/engine/install/ubuntu/). + +### Initialize Docker Swarm + +Initialize your server as a Docker Swarm manager: + +```bash +docker swarm init --advertise-addr +``` + +Replace `` with your server's public IP address. + +### Set up the reverse proxy network + +Create a dedicated overlay network for reverse proxy to communicate with +your services: + +```bash +docker network create --driver=overlay reverse_proxy_public +``` + +## Setting up Caddy as reverse proxy + +To deploy Caddy as reverse proxy create a file `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 +``` + +Deploy Caddy: + +```bash +docker stack deploy -c caddy-stack.yml caddy +``` + +Caddy automatically discovers services with Caddy labels and sets up HTTPS +using Let's Encrypt. Yii3 application templates are using Caddy labels by +default: + +```yaml +deploy: + labels: + - caddy: ${PROD_HOST:-app.example.com} + - caddy.reverse_proxy: "{{upstreams 80}}" +``` + +> [!IMPORTANT] +> Make sure your domain DNS records are configured and pointing to your server before deploying services with +> Caddy labels, as Let's Encrypt requires domain validation. + +## Setting up a container registry + +You need a container registry to store your Docker images. Choose one of the +following options. + +### Option 1: Using Forgejo + +To deploy Forgejo create a file `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 +``` + +Deploy Forgejo: + +```bash +docker stack deploy -c forgejo-stack.yml forgejo +``` + +Replace `git.example.com` with your desired subdomain. + +After deployment, access Forgejo at `https://git.example.com` and complete +the initial setup. Make sure to enable the container registry in the +settings. + +### Option 2: Using Gitea + +To deploy Gitea create a file `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 +``` + +Deploy Gitea: + +```bash +docker stack deploy -c gitea-stack.yml gitea +``` + +Replace `git.example.com` with your desired subdomain. + +After deployment, access Gitea at `https://git.example.com` and complete the +initial setup. Make sure to enable the container registry in the settings. + +## Configuring your Yii application + +### Update the Makefile configuration + +The [Yii application template](https://github.com/yiisoft/app) includes a +Makefile with deployment commands. Update the `docker/.env` file in your +project: + +```bash +STACK_NAME=myapp + +# +# Production +# + +PROD_HOST=app.example.com +PROD_SSH="ssh://user@your-server-ip" + +IMAGE=git.example.com/username/myapp +IMAGE_TAG=latest +``` + +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 + +### Configure the production environment + +Update `docker/prod/.env` with your production environment variables: + +```bash +APP_ENV=prod +YII_DEBUG=false +YII_ENV=prod + +# Database configuration +DB_HOST=db +DB_NAME=myapp +DB_USER=myapp +DB_PASSWORD=secure_password_here + +# Add other environment-specific variables +``` + +> [!WARNING] +> Never commit sensitive credentials to version control. Use `docker/prod/override.env` for sensitive values and add it to `.gitignore`. + +### Review the production Docker Compose configuration + +The default `docker/prod/compose.yml` includes: + +```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}}" +``` + +This configuration: +- Runs 2 replicas for high availability +- Uses a rolling update strategy with automatic rollback on failure +- Configures `labels` for automatic HTTPS on the reverse proxy +- Disables obtaining of HTTPs certificates on the container itself + since proxy communicates with the container via HTTP. That is `auto_https off`. + +If you need a database, add it to the stack: + +```yaml +services: + app: + # ... existing configuration ... + + db: + image: postgres:15-alpine + environment: + POSTGRES_DB: myapp + POSTGRES_USER: myapp + POSTGRES_PASSWORD_FILE: /run/secrets/db_password + volumes: + - db_data:/var/lib/postgresql/data + networks: + - reverse_proxy_public + deploy: + placement: + constraints: + - node.role == manager + secrets: + - db_password + +volumes: + runtime: + db_data: + +secrets: + db_password: + external: true +``` + +Create the database password secret on the server: + +```bash +echo "your_secure_password" | docker secret create db_password - +``` + +## Building and pushing the image + +### Set up Docker login on your local machine + +Configure Docker to authenticate with your container registry: + +```bash +docker login git.example.com +``` + +Enter your username and password when prompted. + +### Build the production image + +Use the Makefile to build your production image: + +```bash +make prod-build +``` + +This runs the command defined in the Makefile: + +```bash +docker build --file docker/Dockerfile --target prod --pull -t ${IMAGE}:${IMAGE_TAG} . +``` + +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`) + +### Push the image to the registry + +Push your built image to the container registry: + +```bash +make prod-push +``` + +This executes: + +```bash +docker push ${IMAGE}:${IMAGE_TAG} +``` + +## Deploying to Docker Swarm + +### Configure SSH access + +Set up SSH key-based authentication to your server: + +```bash +# Generate SSH key (if you don't have one) +ssh-keygen -t ed25519 -C "your_email@example.com" + +# Copy the key to your server +ssh-copy-id user@your-server-ip + +# Add the SSH host to your SSH config (~/.ssh/config) +cat >> ~/.ssh/config << EOF +Host docker-web + HostName your-server-ip + User user + IdentityFile ~/.ssh/id_ed25519 +EOF +``` + +### Set up Docker context + +Create a Docker context for remote deployment: + +```bash +docker context create swarm-prod --docker "host=ssh://docker-web" +``` + +Alternatively, configure the `DOCKER_HOST` environment variable: + +```bash +export DOCKER_HOST=ssh://docker-web +``` + +### Deploy the application + +Deploy your application stack to Docker Swarm: + +```bash +make prod-deploy +``` + +This executes: + +```bash +docker -H ${PROD_SSH} stack deploy --prune --detach=false --with-registry-auth -c docker/compose.yml -c docker/prod/compose.yml ${STACK_NAME} +``` + +The `--with-registry-auth` flag ensures the Swarm nodes can pull images from +your private registry. + +### Verify the deployment + +Check the status of your services: + +```bash +docker -H ssh://docker-web service ls +docker -H ssh://docker-web service ps ${STACK_NAME}_app +``` + +View logs: + +```bash +docker -H ssh://docker-web service logs ${STACK_NAME}_app +``` + +## Monitoring and maintenance + +### View service logs + +```bash +# View all logs +docker -H ssh://docker-web service logs -f ${STACK_NAME}_app + +# View logs from the last 100 lines +docker -H ssh://docker-web service logs --tail 100 ${STACK_NAME}_app + +# View logs with timestamps +docker -H ssh://docker-web service logs -t ${STACK_NAME}_app +``` + +### Scale the application + +Adjust the number of replicas: + +```bash +docker -H ssh://docker-web service scale ${STACK_NAME}_app=3 +``` + +Or update the `replicas` value in `docker/prod/compose.yml` and redeploy. + +### Resource limits + +Add resource limits to prevent containers from consuming all server +resources. Update `docker/prod/compose.yml`: + +```yaml +services: + app: + # ... existing configuration ... + deploy: + resources: + limits: + cpus: '0.5' + memory: 512M + reservations: + cpus: '0.25' + memory: 256M +``` + +## Security considerations + +### Use Docker secrets for sensitive data + +Instead of environment variables, use Docker secrets for sensitive +information: + +```bash +# Create secrets +echo "database_password" | docker secret create db_password - +echo "api_key" | docker secret create api_key - +``` + +Update `docker/prod/compose.yml`: + +```yaml +services: + app: + secrets: + - db_password + - api_key + +secrets: + db_password: + external: true + api_key: + external: true +``` + +Access secrets in your application at `/run/secrets/secret_name`. + +### Set up a firewall + +Configure UFW (Uncomplicated Firewall) on your server: + +```bash +# Allow SSH +sudo ufw allow 22/tcp + +# Allow HTTP and HTTPS +sudo ufw allow 80/tcp +sudo ufw allow 443/tcp + +# Allow Docker Swarm ports (if you plan to add more nodes) +sudo ufw allow 2377/tcp +sudo ufw allow 7946/tcp +sudo ufw allow 7946/udp +sudo ufw allow 4789/udp + +# Enable the firewall +sudo ufw enable +``` + +### Keep the system updated + +Regularly update your server and Docker: + +```bash +# Update system packages +sudo apt-get update && sudo apt-get upgrade -y + +# Update Docker images +docker -H ssh://docker-web service update --image ${IMAGE}:${IMAGE_TAG} ${STACK_NAME}_app +``` + +## Troubleshooting + +### Service won't start + +Check service events and logs: + +```bash +docker -H ssh://docker-web service ps ${STACK_NAME}_app --no-trunc +docker -H ssh://docker-web service logs ${STACK_NAME}_app +``` + +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` + +### SSL certificate issues + +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` + +### Container registry connection issues + +Test registry connectivity: + +```bash +# From your local machine +docker pull git.example.com/username/myapp:latest + +# From the server +docker -H ssh://docker-web pull git.example.com/username/myapp:latest +``` + +## Summary + +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 + +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 + +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) diff --git a/src/it/cookbook/deployment/docker-swarm-traefik.md b/src/it/cookbook/deployment/docker-swarm-traefik.md new file mode 100644 index 00000000..f6f0acfd --- /dev/null +++ b/src/it/cookbook/deployment/docker-swarm-traefik.md @@ -0,0 +1,600 @@ +# Deploying Yii applications to Docker Swarm and Traefik + +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/)). + +```mermaid +graph LR + A[Internet] --> B[Reverse Proxy: Traefik] + B --> C[app1.example.com] + B --> D[app2.example.com] + + subgraph Docker Swarm Cluster + B + C + D + end +``` + +## Prerequisites + +- A server with a fresh installation of a Linux distribution (Ubuntu 22.04 + LTS or later recommended) +- A domain name pointing to your server's IP address +- SSH access to your server +- Basic knowledge of Docker and command-line tools + +## Server preparation + +### Install Docker + +For installation instructions, see the [official Docker +documentation](https://docs.docker.com/engine/install/ubuntu/). + +### Initialize Docker Swarm + +Initialize your server as a Docker Swarm manager: + +```bash +docker swarm init --advertise-addr +``` + +Replace `` with your server's public IP address. + +### Set up the reverse proxy network + +Create a dedicated overlay network for reverse proxy to communicate with +your services: + +```bash +docker network create --driver=overlay reverse_proxy_public +``` + +## Setting up Traefik as reverse proxy + +To deploy Traefik as reverse proxy create a file `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 +``` + +Deploy Traefik: + +```bash +docker stack deploy -c traefik-stack.yml traefik +``` + +## Setting up a container registry + +You need a container registry to store your Docker images. Choose one of the +following options. + +### Option 1: Using Forgejo + +To deploy Forgejo create a file `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 +``` + +Deploy Forgejo: + +```bash +docker stack deploy -c forgejo-stack.yml forgejo +``` + +Replace `git.example.com` with your desired subdomain. + +After deployment, access Forgejo at `https://git.example.com` and complete +the initial setup. Make sure to enable the container registry in the +settings. + +### Option 2: Using Gitea + +To deploy Gitea create a file `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 +``` + +Deploy Gitea: + +```bash +docker stack deploy -c gitea-stack.yml gitea +``` + +Replace `git.example.com` with your desired subdomain. + +After deployment, access Gitea at `https://git.example.com` and complete the +initial setup. Make sure to enable the container registry in the settings. + +## Configuring your Yii application + +### Update the Makefile configuration + +The [Yii application template](https://github.com/yiisoft/app) includes a +Makefile with deployment commands. Update the `docker/.env` file in your +project: + +```bash +STACK_NAME=myapp + +# +# Production +# + +PROD_HOST=app.example.com +PROD_SSH="ssh://user@your-server-ip" + +IMAGE=git.example.com/username/myapp +IMAGE_TAG=latest +``` + +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 + +### Configure the production environment + +Update `docker/prod/.env` with your production environment variables: + +```bash +APP_ENV=prod +YII_DEBUG=false +YII_ENV=prod + +# Database configuration +DB_HOST=db +DB_NAME=myapp +DB_USER=myapp +DB_PASSWORD=secure_password_here + +# Add other environment-specific variables +``` + +> [!WARNING] +> Never commit sensitive credentials to version control. Use `docker/prod/override.env` for sensitive values and add it to `.gitignore`. + +### Review the production Docker Compose configuration + +When using Traefik, you'll need to modify the Yii application's +`docker/prod/compose.yml` to use Traefik labels instead of Caddy labels: + +```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" +``` + +This configuration: +- Runs 2 replicas for high availability +- Uses a rolling update strategy with automatic rollback on failure +- Configures `labels` for automatic HTTPS on the reverse proxy +- Disables obtaining of HTTPs certificates on the container itself + since proxy communicates with the container via HTTP. That is `auto_https off`. + +If you need a database, add it to the stack: + +```yaml +services: + app: + # ... existing configuration ... + + db: + image: postgres:15-alpine + environment: + POSTGRES_DB: myapp + POSTGRES_USER: myapp + POSTGRES_PASSWORD_FILE: /run/secrets/db_password + volumes: + - db_data:/var/lib/postgresql/data + networks: + - reverse_proxy_public + deploy: + placement: + constraints: + - node.role == manager + secrets: + - db_password + +volumes: + runtime: + db_data: + +secrets: + db_password: + external: true +``` + +Create the database password secret on the server: + +```bash +echo "your_secure_password" | docker secret create db_password - +``` + +## Building and pushing the image + +### Set up Docker login on your local machine + +Configure Docker to authenticate with your container registry: + +```bash +docker login git.example.com +``` + +Enter your username and password when prompted. + +### Build the production image + +Use the Makefile to build your production image: + +```bash +make prod-build +``` + +This runs the command defined in the Makefile: + +```bash +docker build --file docker/Dockerfile --target prod --pull -t ${IMAGE}:${IMAGE_TAG} . +``` + +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`) + +### Push the image to the registry + +Push your built image to the container registry: + +```bash +make prod-push +``` + +This executes: + +```bash +docker push ${IMAGE}:${IMAGE_TAG} +``` + +## Deploying to Docker Swarm + +### Configure SSH access + +Set up SSH key-based authentication to your server: + +```bash +# Generate SSH key (if you don't have one) +ssh-keygen -t ed25519 -C "your_email@example.com" + +# Copy the key to your server +ssh-copy-id user@your-server-ip + +# Add the SSH host to your SSH config (~/.ssh/config) +cat >> ~/.ssh/config << EOF +Host docker-web + HostName your-server-ip + User user + IdentityFile ~/.ssh/id_ed25519 +EOF +``` + +### Set up Docker context + +Create a Docker context for remote deployment: + +```bash +docker context create swarm-prod --docker "host=ssh://docker-web" +``` + +Alternatively, configure the `DOCKER_HOST` environment variable: + +```bash +export DOCKER_HOST=ssh://docker-web +``` + +### Deploy the application + +Deploy your application stack to Docker Swarm: + +```bash +make prod-deploy +``` + +This executes: + +```bash +docker -H ${PROD_SSH} stack deploy --prune --detach=false --with-registry-auth -c docker/compose.yml -c docker/prod/compose.yml ${STACK_NAME} +``` + +The `--with-registry-auth` flag ensures the Swarm nodes can pull images from +your private registry. + +### Verify the deployment + +Check the status of your services: + +```bash +docker -H ssh://docker-web service ls +docker -H ssh://docker-web service ps ${STACK_NAME}_app +``` + +View logs: + +```bash +docker -H ssh://docker-web service logs ${STACK_NAME}_app +``` + +## Monitoring and maintenance + +### View service logs + +```bash +# View all logs +docker -H ssh://docker-web service logs -f ${STACK_NAME}_app + +# View logs from the last 100 lines +docker -H ssh://docker-web service logs --tail 100 ${STACK_NAME}_app + +# View logs with timestamps +docker -H ssh://docker-web service logs -t ${STACK_NAME}_app +``` + +### Scale the application + +Adjust the number of replicas: + +```bash +docker -H ssh://docker-web service scale ${STACK_NAME}_app=3 +``` + +Or update the `replicas` value in `docker/prod/compose.yml` and redeploy. + +### Resource limits + +Add resource limits to prevent containers from consuming all server +resources. Update `docker/prod/compose.yml`: + +```yaml +services: + app: + # ... existing configuration ... + deploy: + resources: + limits: + cpus: '0.5' + memory: 512M + reservations: + cpus: '0.25' + memory: 256M +``` + +## Security considerations + +### Use Docker secrets for sensitive data + +Instead of environment variables, use Docker secrets for sensitive +information: + +```bash +# Create secrets +echo "database_password" | docker secret create db_password - +echo "api_key" | docker secret create api_key - +``` + +Update `docker/prod/compose.yml`: + +```yaml +services: + app: + secrets: + - db_password + - api_key + +secrets: + db_password: + external: true + api_key: + external: true +``` + +Access secrets in your application at `/run/secrets/secret_name`. + +### Set up a firewall + +Configure UFW (Uncomplicated Firewall) on your server: + +```bash +# Allow SSH +sudo ufw allow 22/tcp + +# Allow HTTP and HTTPS +sudo ufw allow 80/tcp +sudo ufw allow 443/tcp + +# Allow Docker Swarm ports (if you plan to add more nodes) +sudo ufw allow 2377/tcp +sudo ufw allow 7946/tcp +sudo ufw allow 7946/udp +sudo ufw allow 4789/udp + +# Enable the firewall +sudo ufw enable +``` + +### Keep the system updated + +Regularly update your server and Docker: + +```bash +# Update system packages +sudo apt-get update && sudo apt-get upgrade -y + +# Update Docker images +docker -H ssh://docker-web service update --image ${IMAGE}:${IMAGE_TAG} ${STACK_NAME}_app +``` + +## Troubleshooting + +### Service won't start + +Check service events and logs: + +```bash +docker -H ssh://docker-web service ps ${STACK_NAME}_app --no-trunc +docker -H ssh://docker-web service logs ${STACK_NAME}_app +``` + +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` + +### SSL certificate issues + +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` + +### Container registry connection issues + +Test registry connectivity: + +```bash +# From your local machine +docker pull git.example.com/username/myapp:latest + +# From the server +docker -H ssh://docker-web pull git.example.com/username/myapp:latest +``` + +## Summary + +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 + +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 + +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/) diff --git a/src/it/cookbook/deployment/docker-swarm.md b/src/it/cookbook/deployment/docker-swarm.md new file mode 100644 index 00000000..242ee4d3 --- /dev/null +++ b/src/it/cookbook/deployment/docker-swarm.md @@ -0,0 +1,4 @@ +# Deploying Yii applications to Docker Swarm + +- [Using Caddy](docker-swarm-caddy.md) +- [Using Traefik](docker-swarm-traefik.md) diff --git a/src/it/cookbook/disabling-csrf-protection.md b/src/it/cookbook/disabling-csrf-protection.md new file mode 100644 index 00000000..9fa9f5fe --- /dev/null +++ b/src/it/cookbook/disabling-csrf-protection.md @@ -0,0 +1,153 @@ +# Disabling CSRF protection + +## What is CSRF protection? + +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\Csrf` middleware. + +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. + +## When to disable CSRF protection + +While CSRF protection should generally remain enabled for web applications, +there are specific scenarios where you might need to disable it: + +### When external systems cannot provide CSRF tokens + +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: + +- **Third-party integrations**: External services cannot provide valid CSRF + tokens +- **Mobile applications**: Native mobile apps typically don't use cookies or + sessions in the same way as web browsers +- **Server-to-server communication**: API endpoints designed for + machine-to-machine communication +- **Payment processors**: PayPal, Stripe, and other payment systems send + webhook notifications +- **Version control systems**: GitHub, GitLab webhooks for CI/CD pipelines +- **Social media platforms**: Twitter, Facebook webhook notifications +- **Communication services**: Slack, Discord bot integrations + +## How to disable CSRF protection + +First, you need to remove CSRF middleware from your main application +middleware list in `config/web/di/application.php`: + +```php +return [ + Application::class => [ + '__construct()' => [ + 'dispatcher' => DynamicReference::to([ + 'class' => MiddlewareDispatcher::class, + 'withMiddlewares()' => [ + [ + ErrorCatcher::class, + SessionMiddleware::class, + CsrfTokenMiddleware::class, // <- Remove this line +``` + +Now, if you need to leave CSRF on for specific routes or route groups, you +can do so by adding the `CsrfMiddleware` middleware to the router +configuration in `config/common/routes.php`. For a group that would be the +following: + +```php +return [ + Group::create() + ->middleware(CsrfTokenMiddleware::class) + ->routes( +``` + +For a single route, you can add the middleware directly to the route: + +```php +Route::methods([Method::GET, Method::POST], '/say[/{test}]') + ->action(\App\Controller\Echo\Action::class) + ->name('echo/say') + ->middleware(CsrfTokenMiddleware::class) +``` + + +## Security considerations + +When disabling CSRF protection, keep these security considerations in mind: + +### Alternative authentication methods + +For API endpoints, implement proper authentication mechanisms: + +- **API keys**: Require API keys for authentication +- **Bearer tokens**: Use JWT or similar token-based authentication +- **OAuth 2.0**: Implement OAuth 2.0 for third-party access +- **IP whitelisting**: Restrict access to known IP addresses for webhooks + +### Request validation + +Implement additional validation for requests without CSRF protection: + +- **Signature verification**: Verify webhook signatures (e.g., GitHub's + X-Hub-Signature) +- **Timestamp validation**: Check request timestamps to prevent replay + attacks +- **Rate limiting**: Implement rate limiting to prevent abuse +- **Input validation**: Strictly validate all input parameters + +### Example: Webhook signature verification + +```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'); + } + + // Process webhook payload + // ... + } +} +``` + +## Best practices + +1. **Minimize exposure**: Only disable CSRF protection where absolutely + necessary +2. **Use HTTPS**: Always use HTTPS for API endpoints and webhooks +3. **Monitor logs**: Log all requests to API endpoints for security + monitoring +4. **Regular security audits**: Periodically review your API endpoints and + their security measures +5. **Documentation**: Clearly document which endpoints have CSRF protection + disabled and why + +## Conclusion + +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. + +Remember that disabling CSRF protection increases security risks, so careful +consideration and proper implementation of alternative security measures are +essential. diff --git a/src/it/cookbook/index.md b/src/it/cookbook/index.md new file mode 100644 index 00000000..614f8980 --- /dev/null +++ b/src/it/cookbook/index.md @@ -0,0 +1,24 @@ +# Yii3 community cookbook + +Yii3 Community Cookbook is an OpenSource book full of tips and tricks about +the [Yii3](https://www.yiiframework.com/) PHP framework. + +- The Yii community creates the cookbook. +- Yii core team members curate and edit it. + +Feel free to pull-request your own writings. Team members will review it, +give feedback and merge the best possible way. + +This book conforms to the [Terms of Yii +Documentation](https://www.yiiframework.com/license#docs). + +--- + +- [Preface](preface.md) +- [Structuring code by use-case with vertical + slices](organizing-code/structuring-by-use-case-with-vertical-slices.md) +- [Making HTTP requests](making-http-requests.md) +- [Disabling CSRF protection](disabling-csrf-protection.md) +- [Sentry integration](sentry-integration.md) +- [Configuring webservers](configuring-webservers/general.md) +- [Deploying to Docker Swarm](deployment/docker-swarm.md) diff --git a/src/it/cookbook/making-http-requests.md b/src/it/cookbook/making-http-requests.md new file mode 100644 index 00000000..192b03ff --- /dev/null +++ b/src/it/cookbook/making-http-requests.md @@ -0,0 +1,384 @@ +# Making HTTP requests + +When building modern applications, you often need to make HTTP requests to +external APIs. This article demonstrates how to make HTTP requests in Yii3 +applications using Guzzle with and [PSR +interfaces](https://www.php-fig.org/psr/). + +## What are PSR interfaces for HTTP + +The PHP-FIG (PHP Framework Interoperability Group) has defined several PSR +standards for HTTP handling: + +- **PSR-7**: HTTP message interfaces for requests and responses +- **PSR-17**: HTTP factory interfaces for creating PSR-7 message objects +- **PSR-18**: HTTP client interface for sending PSR-7 requests and returning + PSR-7 responses + +Using these interfaces ensures your code is framework-agnostic and follows +established PHP standards. + +## Installation + +Install the Guzzle HTTP client with PSR-18 support and PSR-17 factories: + +```shell +composer require guzzlehttp/guzzle +composer require guzzlehttp/psr7 +``` + +## Basic usage + +### Simple GET request + +Here's how to make a basic GET request using PSR-18 interfaces: + +```php +requestFactory->createRequest( + 'GET', + "https://example.com/users/{$userId}" + ); + + return $this->httpClient->sendRequest($request); + } +} +``` + +### POST request with JSON data + +Here's an example of making a POST request with JSON payload: + +```php +streamFactory->createStream($jsonData); + + $request = $this->requestFactory->createRequest('POST', 'https://example.com/users') + ->withHeader('Content-Type', 'application/json') + ->withHeader('Accept', 'application/json') + ->withBody($stream); + + return $this->httpClient->sendRequest($request); + } +} +``` + +## Configuration in Yii3 + +### Container configuration + +Configure the HTTP client and PSR factories in your DI container: + +```php + [ + 'class' => Client::class, + '__construct()' => [ + 'config' => [ + 'timeout' => 30, + 'connect_timeout' => 10, + ], + ], + ], + + // Configure PSR-17 factories - these will depend on your chosen PSR-7 implementation + RequestFactoryInterface::class => static function (): RequestFactoryInterface { + return new \GuzzleHttp\Psr7\HttpFactory(); + }, + ResponseFactoryInterface::class => static function (): ResponseFactoryInterface { + return new \GuzzleHttp\Psr7\HttpFactory(); + }, + StreamFactoryInterface::class => static function (): StreamFactoryInterface { + return new \GuzzleHttp\Psr7\HttpFactory(); + }, + UriFactoryInterface::class => static function (): UriFactoryInterface { + return new \GuzzleHttp\Psr7\HttpFactory(); + }, +]; +``` + +### Service with error handling + +Here's a more robust service example with proper error handling: + +```php +requestFactory->createRequest( + 'GET', + "https://api.openweathermap.org/data/2.5/weather?q={$city}&appid={$this->apiKey}&units=metric" + ); + + $response = $this->httpClient->sendRequest($request); + + if ($response->getStatusCode() !== 200) { + $this->logger->warning('Weather API returned non-200 status', [ + 'status_code' => $response->getStatusCode(), + 'city' => $city, + ]); + return null; + } + + $data = json_decode($response->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR); + return $data; + } catch (ClientExceptionInterface $e) { + $this->logger->error('HTTP client error when fetching weather data', [ + 'city' => $city, + 'error' => $e->getMessage(), + ]); + return null; + } catch (\JsonException $e) { + $this->logger->error('Failed to decode weather API response', [ + 'city' => $city, + 'error' => $e->getMessage(), + ]); + return null; + } + } +} +``` + +## Advanced usage + +### Using middlewares + +Guzzle supports middleware for cross-cutting concerns like authentication, +logging, or retrying: + +```php +push(Middleware::log( + $this->logger, + new \GuzzleHttp\MessageFormatter('HTTP {method} {uri} - {code} {phrase}') + )); + + // Add retry middleware + $stack->push(Middleware::retry( + function (int $retries, RequestInterface $request) { + return $retries < 3; + } + )); + + return new Client([ + 'handler' => $stack, + 'timeout' => 30, + ]); + } +} +``` + +### Async requests + +For better performance when making multiple requests, you can use +asynchronous requests: + +> **Note**: Async functionality is not part of PSR interfaces, so this code depends on Guzzle explicitly. + +```php + $userIds + * @return array + */ + public function fetchMultipleUsers(array $userIds): array + { + $promises = []; + + foreach ($userIds as $userId) { + $promises[$userId] = $this->httpClient->getAsync( + "https://example.com/users/{$userId}" + ); + } + + // Wait for all requests to complete + $responses = \GuzzleHttp\Promise\settle($promises)->wait(); + + $results = []; + foreach ($responses as $userId => $response) { + if ($response['state'] === PromiseInterface::FULFILLED) { + $results[$userId] = $response['value']; + } + } + + return $results; + } +} +``` + +## Testing HTTP clients + +When testing services that make HTTP requests, you can use Guzzle's +MockHandler: + +```php + 'London', + 'main' => ['temp' => 20.5], + ])), + ]); + + $handlerStack = HandlerStack::create($mockHandler); + $client = new Client(['handler' => $handlerStack]); + + $service = new WeatherService( + $client, + new \GuzzleHttp\Psr7\HttpFactory(), + new \GuzzleHttp\Psr7\HttpFactory(), + $this->createMock(\Psr\Log\LoggerInterface::class), + 'test-api-key' + ); + + $result = $service->getCurrentWeather('London'); + + $this->assertNotNull($result); + $this->assertSame('London', $result['name']); + $this->assertSame(20.5, $result['main']['temp']); + } +} +``` + +## Best practices + +1. **Use PSR interfaces**: Always type-hint against PSR interfaces rather + than concrete implementations for better testability and flexibility. + +2. **Handle errors gracefully**: Always wrap HTTP requests in try-catch + blocks and handle network failures appropriately. + +3. **Configure timeouts**: Set reasonable connection and request timeouts to + prevent hanging requests. + +4. **Log requests**: Use middleware or manual logging to track API calls for + debugging and monitoring. + +5. **Use dependency injection**: Inject HTTP clients and factories through + your DI container rather than creating them directly. + +6. **Mock in tests**: Use Guzzle's MockHandler or similar tools to test your + HTTP client code without making real network requests. + +By following these patterns and using PSR interfaces, you'll create +maintainable, testable, and interoperable HTTP client code in your Yii3 +applications. diff --git a/src/it/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md b/src/it/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md new file mode 100644 index 00000000..8ee871aa --- /dev/null +++ b/src/it/cookbook/organizing-code/structuring-by-use-case-with-vertical-slices.md @@ -0,0 +1,81 @@ +# Structuring code by use-case with vertical slices + +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. + +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. + +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. + +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. + +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. + +Here's an example directory structure for a PHP application organized using +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 +``` + +Each vertical slice has its own directory, which has code associated with +the use case. + +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`. + +## References + +- [Application structure overview](../../guide/structure/overview.md) diff --git a/src/it/cookbook/preface.md b/src/it/cookbook/preface.md new file mode 100644 index 00000000..1de34954 --- /dev/null +++ b/src/it/cookbook/preface.md @@ -0,0 +1,37 @@ +# Preface + +Yii è un framework PHP ad alte prestazioni basato su pacchetti per lo +sviluppo di applicazioni moderne. Il nome Yii (pronunciato “Yee” o “[ji:]”) +significa “semplice ed evolutivo” in cinese. Si può anche considerare come +l'acronimo di **Yes It Is**! + +Yii è un framework generico per la programmazione web. È possibile +utilizzarlo per sviluppare tutti i tipi di applicazioni web utilizzando +PHP. Grazie alla sua architettura e al sofisticato supporto della cache, è +particolarmente adatto allo sviluppo di applicazioni su larga scala come +portali, sistemi di gestione dei contenuti, e-commerce, API REST, ecc. + +With comprehensive documentation and an enthusiastic user community, Yii can +significantly reduce your development time in the long run. + +## What's the book about + +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. + +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. + +## Prerequisites + +- You should have Yii3 installed. +- You should be familiar with the framework basics and the official guide. + +## How to participate + +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). diff --git a/src/it/cookbook/sentry-integration.md b/src/it/cookbook/sentry-integration.md new file mode 100644 index 00000000..b2d4685f --- /dev/null +++ b/src/it/cookbook/sentry-integration.md @@ -0,0 +1,125 @@ +# Sentry integration + +## What is Sentry + +[Sentry](https://sentry.io/) is a tool for monitoring and debugging application stability and performance. +Sentry gives you access to the events that you send there from your application. + +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 + +You can find the full list of features on the official website: +https://sentry.io/welcome/ + +## Installation + +### Install the package + +Install the required package `yiisoft/yii-sentry` with the following +command: + +```shell +composer require yiisoft/yii-sentry --prefer-dist +``` + +### Install an HTTP driver + +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. + +> You can find the list of all adapters on [this page](https://docs.php-http.org/en/latest/clients.html#clients-adapters). + +To install the packages, run the following command: + +```shell +composer require php-http/httplug php-http/guzzle7-adapter --prefer-dist +``` + +## Configuration + +### Get and store the token + +Next, configure the application. + +First, register at [Sentry](https://sentry.io) and create a project. + +Then, in the project settings on the “General Settings” tab, find the +“Security Token” field and copy its value. + +Now put this token into the package configuration. By default, the config is located at `config/packages/yiisoft/yii-sentry/config/params.php`. +Set the copied token as the value of the array element at `yiisoft/yii-sentry` => `options` => `dsn`. Example: + +```diff +'yiisoft/yii-sentry' => [ + 'enabled' => true, + 'options' => [ +- 'dsn' => '', ++ 'dsn' => 'TOKEN', + ], +], +``` + +### Configure the HTTP client + +After installing the HTTP client, configure it. + +Create the file `config/common/sentry.php` and put the following code into +it: + +```php + \GuzzleHttp\Client::class, + \Http\Client\HttpAsyncClient::class => [ + 'class' => \Http\Adapter\Guzzle7\Client::class, + '__construct()' => [ + \Yiisoft\Factory\Definition\Reference::to(\Http\Client\HttpClient::class), + ], + ], +]; +``` + +# Integration + +### Web + +Sentry support for `web` is implemented as middleware. + +That means you only need to add `SentryMiddleware` to the global middleware +list in `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 + +Sentry supports `console` via a handler for the +[ConsoleEvents::ERROR](https://symfony.com/doc/current/components/console/events.html#the-consoleevents-error-event) +event. + +The package provides a configuration file that automatically subscribes the +application to this event. diff --git a/src/it/guide/caching/data.md b/src/it/guide/caching/data.md new file mode 100644 index 00000000..0b7d1a62 --- /dev/null +++ b/src/it/guide/caching/data.md @@ -0,0 +1,216 @@ +# 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). + +To use cache, install [yiisoft/cache](https://github.com/yiisoft/cache) +package: + +```shell +composer require yiisoft/cache +``` + +The following code is a typical usage pattern of data caching, where +`$cache` refers to a `Cache` instance from the package: + +```php +public function getTopProducts(\Yiisoft\Cache\CacheInterface $cache): array +{ + $key = ['top-products', $count = 10]; + + // Try retrieving $data from cache. + $data = $cache->getOrSet($key, function (\Psr\SimpleCache\CacheInterface $cache) use ($count) { + // Can't find $data in a cache, calculate it from scratch. + return getTopProductsFromDatabase($count); + }, 3600); + + return $data; +} +``` + +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. + +If the anonymous function requires some data from the outer scope, you can +pass it with the `use` statement. + +## Cache handlers + +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. + +Yii provides the following handlers: + +- `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. +- `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 + 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. +- [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. +- [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 + (e.g., with several servers, load balancers, etc.) +- [Wincache](https://github.com/yiisoft/cache-wincache) — uses PHP [WinCache](https://iis.net/downloads/microsoft/wincache-extension) + ([see also](https://secure.php.net/manual/en/book.wincache.php)) extension. + +[You could find more handlers at +packagist.org](https://packagist.org/providers/psr/simple-cache-implementation). + +> [!TIP] +> You may use different cache storage in the same application. A common strategy is: +> - To use memory-based cache storage to store small but constantly used data (e.g., statistics) +> - To use file-based or database-based cache storage to store big and less often used data (e.g., page content) + +Cache handlers are usually set up in a [dependency injection +container](../concept/di-container.md) so that they can be globally +configurable and accessible. + +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. + +### Cache keys + +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. + +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. + +A common strategy of defining a cache key is to include all determining +factors in terms of an array. + +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: + +```php +$arrayCacheWithPrefix = new \Yiisoft\Cache\PrefixedCache(new \Yiisoft\Cache\ArrayCache(), 'myapp_'); +$cache = new \Yiisoft\Cache\Cache($arrayCacheWithPrefix); +``` + +### Cache expiration + +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: + +```php +$ttl = 3600; +$data = $cache->getOrSet($key, function (\Psr\SimpleCache\CacheInterface $cache) use ($count) { +return getTopProductsFromDatabase($count); +}, $ttl); +``` + +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. + +You may set the default TTL for the cache: + +```php +$cache = new \Yiisoft\Cache\Cache($arrayCache, 60 * 60); // 1 hour +``` + +Additionally, you can invalidate a cache key explicitly: + +```php +$cache->remove($key); +``` + +### Invalidation dependencies + +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. + +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, + +```php +/** + * @var callable $callable + * @var \Yiisoft\Cache\CacheInterface $cache + */ + +use Yiisoft\Cache\Dependency\TagDependency; + +// Set many cache values marking both with a tag. +$cache->getOrSet('item_42_price', $callable, null, new TagDependency('item_42')); +$cache->getOrSet('item_42_total', $callable, 3600, new TagDependency('item_42')); + +// Trigger invalidation by tag. +TagDependency::invalidate($cache, 'item_42'); +``` + +Below is a summary of the available cache dependencies: + +- `\Yiisoft\Cache\Dependency\ValueDependency`: invalidates the cache when + specified value changes. +- `\Yiisoft\Cache\Dependency\CallbackDependency`: invalidates the cache when + the result of the specified PHP callback is different. +- `\Yiisoft\Cache\Dependency\FileDependency`: invalidates the cache when the + file's last modification time is different. +- `\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()`. + +You may combine many dependencies using +`\Yiisoft\Cache\Dependency\AnyDependency` or +`\Yiisoft\Cache\Dependency\AllDependencies`. + +To implement your own dependency, extend from +`\Yiisoft\Cache\Dependency\Dependency`. + +### Cache stampede prevention + +[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. + +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. + +```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/it/guide/caching/overview.md b/src/it/guide/caching/overview.md new file mode 100644 index 00000000..2e2d4845 --- /dev/null +++ b/src/it/guide/caching/overview.md @@ -0,0 +1,21 @@ +# Caching + +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. + +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. + +Yii supports all these caching mechanisms: + +* [Data caching](data.md) +* [Fragment caching](fragment.md) +* [Page caching](page.md) +* [HTTP caching](http.md) diff --git a/src/it/guide/concept/aliases.md b/src/it/guide/concept/aliases.md new file mode 100644 index 00000000..f683f630 --- /dev/null +++ b/src/it/guide/concept/aliases.md @@ -0,0 +1,149 @@ +# Aliases + +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. + +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. + +## Defining aliases + +You can define an alias via application's `config/params.php`: + +```php +return [ + // ... + + 'yiisoft/aliases' => [ + 'aliases' => [ + // ... + + // an alias of a file path + '@foo' => '/path/to/foo', + + // an alias of a URL + '@bar' => 'https://www.example.com', + + // an alias of a concrete file that contains a \foo\Bar class + '@foo/Bar.php' => '/definitely/not/foo/Bar.php', + ], + ], +]; +``` + +> [!NOTE] +> The file path or URL being aliased may *not* necessarily refer to an existing file or resource. + +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. + +You can define an alias using another alias (either root or derived): + +```php +'@foobar' => '@foo/bar', +``` + +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: + +```php +use \Yiisoft\Aliases\Aliases; + +public function actionIndex(Aliases $aliases) +{ + $aliases->set('@uploads', '@root/uploads'); +} +``` + +## Using aliases in configuration + +It's preferred to resolve aliases at the configuration level, so services +get URLs and paths as ready to use strings: + +```php + static fn (Aliases $aliases) => new FileCache( + $aliases->get($params['yiisoft/cache-file']['fileCache']['path']) + ), +]; +``` + +## Resolving aliases + +You can use `Aliases` service to resolve an alias or derived alias into the +file path or URL it represents: + +```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 +} +``` + +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. + +> [!NOTE] +> The `get()` method doesn't check whether the resulting path/URL refers to an existing file or resource. + + +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: + +```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 +} +``` + +If `@foo/bar` isn't defined as a root alias, the last statement would +display `/path/to/foo/bar/file.php`. + + +## Predefined aliases + +[Yii application](https://github.com/yiisoft/app) predefines a set of +aliases to reference commonly used file paths and URLs: + +- `@root` - the base directory of the currently running application. +- `@assets` - application's public directory where it publishes assets. +- `@assetsUrl` - URL of base directory with published assets. +- `@baseUrl` - the base URL of the currently running Web + application. Defaults to `/`. +- `@npm` - node packages directory. +- `@bower` - bower packages directory. +- `@vendor` - Composer's `vendor` directory. +- `@public` - application's publicly accessible directory that with + `index.php`. +- `@runtime` - the runtime path of the currently running + application. Defaults to `@root/runtime`. +- `@layout` - the directory with layouts. +- `@resources` - directory with views, asset sources and other resources. +- `@views` - application view templates base directory. diff --git a/src/it/guide/concept/autoloading.md b/src/it/guide/concept/autoloading.md new file mode 100644 index 00000000..c01226ae --- /dev/null +++ b/src/it/guide/concept/autoloading.md @@ -0,0 +1,37 @@ +# Class autoloading + +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. + +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`: + +```json +{ + "autoload": { + "psr-4": { + "App\\": "src/" + } + } +} +``` + +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. + +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`. + +## References + +- [PSR-4: Autoloader](https://www.php-fig.org/psr/psr-4/). +- [Composer guide on + autoloading](https://getcomposer.org/doc/01-basic-usage.md#autoloading). diff --git a/src/it/guide/concept/configuration.md b/src/it/guide/concept/configuration.md new file mode 100644 index 00000000..6755b9bf --- /dev/null +++ b/src/it/guide/concept/configuration.md @@ -0,0 +1,372 @@ +# Configuration + +There are many ways to configure your application. We will focus on concepts +used in the [default project template](https://github.com/yiisoft/app). + +Yii3 configs are part of the application. You can change many aspects of how +the application works by editing configuration under `config/`. + +## Config plugin + +In the application template +[yiisoft/config](https://github.com/yiisoft/config) is used. Since writing +all application configurations from scratch is a tedious process, many +packages offer default configs, and the plugin helps with copying these into +the application. + +To offer default configs, `composer.json` of the package has to have +`config-plugin` section. When installing or updating packages with +Composer, the plugin reads `config-plugin` sections for each dependency, +copies files themselves to application `config/packages/` if they don't yet +exist and writes a merge plan to `config/packages/merge_plan.php`. The merge +plan defines how to merge the configs into a single big array ready to be +passed to [DI container](di-container.md). + +Take a look at what's in the "yiisoft/app" `composer.json` by default: + +```json +"config-plugin-options": { + "output-directory": "config/packages" +}, +"config-plugin": { + "common": "config/common/*.php", + "params": [ + "config/params.php", + "?config/params-local.php" + ], + "web": [ + "$common", + "config/web/*.php" + ], + "console": [ + "$common", + "config/console/*.php" + ], + "events": "config/events.php", + "events-web": [ + "$events", + "config/events-web.php" + ], + "events-console": [ + "$events", + "config/events-console.php" + ], + "providers": "config/providers.php", + "providers-web": [ + "$providers", + "config/providers-web.php" + ], + "providers-console": [ + "$providers", + "config/providers-console.php" + ], + "routes": "config/routes.php" +}, +``` + +There are many named configs defined. For each name, there is a +configuration. + +A string means that the plugin takes config as is and merges it with +same-named configs from packages you require. That happens if these +packages have `config-plugin` in their `composer.json`. + +The array means that the plugin will merge many files in the order they're +specified. + +`?` at the beginning of the file path indicated that the file may be +absent. In this case, it's skipped. + +`$` at the beginning of the name means a reference to another named config. + +`params` is a bit special because it's reserved for application +parameters. These are automatically available as `$params` in all other +configuration files. + +You can learn more about config plugin features [from its +documentation](https://github.com/yiisoft/config/blob/master/README.md). + +## Config files + +Now, as you know how the plugin assembles configs, look at `config` +directory: + +``` +common/ + application-parameters.php + i18n.php + router.php +console/ +packages/ + yiisoft/ + dist.lock + merge_plan.php +web/ + application.php + psr17.php +events.php +events-console.php +events-web.php +params.php +providers.php +providers-console.php +providers-web.php +routes.php +``` + +### Container configuration + +The application consists of a set of services registered in a [dependency +container](di-container.md). The config files that responsible for direct +dependency container configuration are under `common/`, `console/` and +`web/` directories. We use `web/` for config specific to web application +and `console/` for config specific to console commands. Both web and console +are sharing configuration under `common/`. + +```php + [ + 'class' => ApplicationParameters::class, + 'charset()' => [$params['app']['charset']], + 'name()' => [$params['app']['name']], + ], +]; +``` + +Config plugin passes special `$params` variable to all config files. The +code passes its values to the service. + +The guide on ["Dependency injection and container"](di-container.md) +describes the configuration format and the idea of dependency injection in +detail. + +For convenience, there is a naming convention for custom string keys: + +1. Prefix package name such as `yiisoft/cache-file/custom-definition`. +2. In case configuration are for the application itself, skip package + prefix, such as `custom-definition`. + +### Service providers + +As an alternative to registering dependencies directly, you can use service +providers. Basically, these are classes that given parameters are +configuring and registering services within the container. Similar to three +dependency configuration files described, there are three configs for +specifying service providers: `providers-console.php` for console commands, +`providers-web.php` for web application and `providers.php` for both: + +```php +/* @var array $params */ + +// ... +use App\Provider\CacheProvider; +use App\Provider\MiddlewareProvider; +// ... + +return [ + // ... + 'yiisoft/yii-web/middleware' => MiddlewareProvider::class, + 'yiisoft/cache/cache' => [ + 'class' => CacheProvider::class, + '__construct()' => [ + $params['yiisoft/cache-file']['file-cache']['path'], + ], + ], + // ... +``` + +In this config keys are provider names. By convention these are +`vendor/package-name/provider-name`. Values are provider class names. These +classes could be either created in the project itself or provided by a +package. + +If you need to configure some options for a service, similar to direct +container configuration, take values from `$params` and pass them to +providers. + +Provider should implement a single method, `public function +register(Container $container): void`. In this method you need to add a +service to container using `set()` method. Below is a provider for a cache +service: + +```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\Container; +use Yiisoft\Di\Support\ServiceProvider; + +final readonly class CacheProvider extends ServiceProvider +{ + public function __construct( + private string $cachePath = '@runtime/cache' + ) + { + $this->cachePath = $cachePath; + } + + public function register(Container $container): void + { + $container->set(CacheInterface::class, function (ContainerInterface $container) { + $aliases = $container->get(Aliases::class); + + return new FileCache($aliases->get($this->cachePath)); + }); + + $container->set(YiiCacheInterface::class, Cache::class); + } +} +``` + +### Routes + +You can configure how web application responds to certain URLs in +`config/routes.php`: + +```php +use App\Controller\SiteController; +use Yiisoft\Router\Route; + +return [ + Route::get('/')->action([SiteController::class, 'index'])->name('site/index') +]; +``` + +Read more about it in ["Routes"](../runtime/routing.md). + +### Events + +Many services emit certain events that you can attach to. You could do that +via three config files: `events-web.php` for web application events, +`events-console.php` for console events and `events.php` for both. The +configuration is an array where keys are event names and values are an array +of handlers: + +```php +return [ + EventName::class => [ + // Just a regular closure, it will be called from the Dispatcher "as is". + static fn (EventName $event) => someStuff($event), + + // A regular closure with an extra dependency. All the parameters after the first one (the event itself) + // will be resolved from your DI container within `yiisoft/injector`. + static fn (EventName $event, DependencyClass $dependency) => someStuff($event), + + // An example with a regular callable. If the `staticMethodName` method has some dependencies, + // they will be resolved the same way as in the earlier example. + [SomeClass::class, 'staticMethodName'], + + // Non-static methods are allowed too. In this case, `SomeClass` will be instantiated by your DI container. + [SomeClass::class, 'methodName'], + + // An object of a class with the `__invoke` method implemented + new InvokableClass(), + + // In this case, the `InvokableClass` with the `__invoke` method will be instantiated by your DI container + InvokableClass::class, + + // Any definition of an invokable class may be here while your `$container->has('the definition)` + 'di-alias' + ], +]; +``` + +Read more about it in ["Events"](events.md). + + +### Parameters + +Parameters, `config/params.php` store configuration values that are used in +other config files to configuring services and service providers. + +> [!TIP] +> Don't use parameters, constants or environment variables directly in your application, configure +> services instead. + +Default application `params.php` looks like the following: + +```php + [ + 'charset' => 'UTF-8', + 'locale' => 'en', + 'name' => 'My Project', + ], + + 'yiisoft/aliases' => [ + 'aliases' => [ + '@root' => dirname(__DIR__), + '@assets' => '@root/public/assets', + '@assetsUrl' => '/assets', + '@baseUrl' => '/', + '@message' => '@root/resources/message', + '@npm' => '@root/node_modules', + '@public' => '@root/public', + '@resources' => '@root/resources', + '@runtime' => '@root/runtime', + '@vendor' => '@root/vendor', + '@layout' => '@resources/views/layout', + '@views' => '@resources/views', + ], + ], + + 'yiisoft/yii-view' => [ + 'injections' => [ + Reference::to(ContentViewInjection::class), + Reference::to(CsrfViewInjection::class), + Reference::to(LayoutViewInjection::class), + ], + ], + + 'yiisoft/yii-console' => [ + 'commands' => [ + 'hello' => Hello::class, + ], + ], +]; +``` + +For convenience, there is a naming convention about parameters: + +1. Group parameters package name such as `yiisoft/cache-file`. +2. In case parameters are for the application itself, as in `app`, skip + package prefix. +3. 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. +4. Use `enabled` as parameter name to be able to disable or enable a + service, such as `yiisoft/yii-debug`. + +### Package configs + +Config plugin described copy default package configurations to `packages/` +directory. Once copied you own the configs, so you can adjust these as you +like. `yiisoft/` in the default template stands for package vendor. Since +only `yiisoft` packages are in template, there's a single +directory. `merge_plan.php` is used in runtime to get the order on how +configs are merged. Note that for config keys there should be a single +source of truth. One config can't override values of another config. + +`dist.lock` is used by the plugin to keep track of changes and display diff +between current config and example one. diff --git a/src/it/guide/concept/di-container.md b/src/it/guide/concept/di-container.md new file mode 100644 index 00000000..94fe1609 --- /dev/null +++ b/src/it/guide/concept/di-container.md @@ -0,0 +1,346 @@ +# Dependency injection and container + +## Dependency injection + +There are two ways of re-using things in OOP: inheritance and composition. + +Inheritance is simple: + +```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; + } + // ... + } +} +``` + +The issue here is that these two are becoming unnecessarily coupled or +inter-dependent, making them more fragile. + +Another way to handle this is composition: + +```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; + } + // ... + } +} +``` + +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. + +The `CacheInterface` here is a dependency: a contract our object needs to +function. In other words, our object depends on the contract. + +The process of putting an instance of a contract into an object +(`CachedWidget`) is called dependency injection. There are many ways to +perform it: + +- Constructor injection. Best for mandatory dependencies. +- Method injection. Best for optional dependencies. +- Property injection. Better to be avoided in PHP except maybe data transfer + objects. + +### Why use private properties + +In the composition example above, note that the `$cache` property is +declared as `private`. + +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. + +This design choice provides several benefits: + +- **Encapsulation**: Private properties with getters/setters allow you to + control access and make future changes without breaking existing code. +- **Data integrity**: Setters can validate, normalize, or format values + before storing them, ensuring properties contain valid data. +- **Immutability**: Private properties enable immutable object patterns + where setter `with*()` methods return new instances rather than modifying + the current one. +- **Flexibility**: You can create read-only or write-only properties or add + additional logic to property access later. + + +## DI container + +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. + +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. + +Additionally, lots of dependencies, such as certain third-party API +wrappers, are the same for any class using it. So it makes sense to: + +- Define how to instantiate such common dependencies. +- Instantiate them when required and only once per request. + +That's what dependency containers are for. + +A dependency injection (DI) container is an object that knows how to +instantiate and configure objects and all objects they depend on. + +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. + +> [!NOTE] +> The container contains only shared instances. If you need a factory, use the dedicated +> [yiisoft/factory](https://github.com/yiisoft/factory) package. + +> [!TIP] +> [Martin Fowler's article](https://martinfowler.com/articles/injection.html) has well +> explained why DI container is useful. Here we will mainly explain the usage of the DI container provided by Yii. + +### Configuring container + +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: + +```php +final class MyService implements MyServiceInterface +{ + public function __construct(int $amount) + { + } + + public function setDiscount(int $discount): void + { + + } +} +``` + +configuration could be: + +```php +return [ + MyServiceInterface::class => [ + 'class' => MyService::class, + '__construct()' => [42], + 'setDiscount()' => [10], + ], +]; +``` + +That's equal to the following: + +```php +$myService = new MyService(42); +$myService->setDiscount(10); +``` + +You can provide arguments with names as well: + +```php +return [ + MyServiceInterface::class => [ + 'class' => MyService::class, + '__construct()' => ['amount' => 42], + 'setDiscount()' => ['discount' => 10], + ], +]; +``` + +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: + +```php +final class MyAction +{ + public function __construct( + private readonly MyServiceInterface $myService + ) { + } + + public function __invoke() + { + $this->myService->doSomething(); + } +} +``` + +There are extra methods of declaring dependency configuration. + +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. + +```php +interface EngineInterface +{ + +} + +final class EngineMarkOne implements EngineInterface +{ + public function __construct(CacheInterface $cache) { + } +} +``` + +In the above example, if we already have cache defined in the container, +nothing besides the class name is needed: + +```php +return [ + // declare a class for an interface, resolve dependencies automatically + EngineInterface::class => EngineMarkOne::class, +]; +``` + +If you have a dependency that has public properties, you can configure it as +well. + + +```php +final class NameProvider +{ + public string $name; +} +``` + +Here's how to do it for the example above: + +```php +NameProvider::class => [ + 'class' => NameProvider::class, + '$name' => 'Alex', +], +``` + +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. + +If the configuration is tricky and requires some logic, a closure can be +used: + +```php +MyServiceInterface::class => static function(ContainerInterface $container) { + return new MyService($container->get('db')); +}, +``` + +Additionally, to `ContainerInterface`, you can request any registered +service directly as a closure parameter. The injector will automatically +resolve and inject these: + +```php +MyServiceInterface::class => static function(ConnectionInterface $db) { + return new MyService($db); +}, +``` + +It's possible to use a static method call: + +```php +MyServiceInterface::class => [MyFactory::class, 'create'], +``` + +Or an instance of an object: + +```php +MyServiceInterface::class => new MyService(), +``` + +### Injecting dependencies properly + +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. + +This is primarily done in constructor and handing method of action handlers: + +```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, + ]); + } +} +``` + +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. + + +## References + +- [Inversion of Control Containers and the Dependency Injection pattern by + Martin Fowler](https://martinfowler.com/articles/injection.html) diff --git a/src/it/guide/concept/events.md b/src/it/guide/concept/events.md new file mode 100644 index 00000000..4833b27c --- /dev/null +++ b/src/it/guide/concept/events.md @@ -0,0 +1,155 @@ +# Events + +Events allow you to make custom code executed at certain execution points +without modifying existing code. You can attach a custom code called +"handler" to an event so that when the event is triggered, the handler gets +executed automatically. + +For example, when a user is signed up, you need to send a welcome email. You +can do it right in the `SignupService` but then, when you additionally need +to resize user's avatar image, you'll have to change `SignupService` code +again. In other words, `SignupService` will be coupled to both code sending +welcome email and code resizing avatar image. + +To avoid it, instead of telling what do after signup explicitly you can, instead, raise `UserSignedUp` event +and then finish a signup process. The code sending an email and the code resizing avatar image will attach to the event + and, therefore, will be executed. If you'll ever need to do more on signup, you'll be able to attach extra event +handlers without modifying `SignupService`. + +For raising events and attaching handlers to these events, Yii has a special +service called event dispatcher. It's available from +[yiisoft/event-dispatcher +package](https://github.com/yiisoft/event-dispatcher). + +## Event Handlers + +An event handler is [PHP +callable](https://www.php.net/manual/en/language.types.callable.php) that +gets executed when the event it's attached to is triggered. + +The signature of an event handler is: + +```php +function (EventClass $event) { + // handle it +} +``` + +## Attaching event handlers + +You can attach a handler to an event like the following: + +```php +use Yiisoft\EventDispatcher\Provider\Provider; + +final readonly class WelcomeEmailSender +{ + public function __construct(Provider $provider) + { + $provider->attach([$this, 'handleUserSignup']); + } + + public function handleUserSignup(UserSignedUp $event) + { + // handle it + } +} +``` + +The `attach()` method is accepting a callback. Based on the type of this +callback argument, the event type is determined. + +## Event handlers order + +You may attach one or more handlers to a single event. When an event is +triggered, the attached handlers will be called in the order that they were +attached to the event. In case an event implements +`Psr\EventDispatcher\StoppableEventInterface`, event handler can stop +executing the rest of the handlers that follow it if +`isPropagationStopped()` returns `true`. + +In general, it's better not to rely on the order of event handlers. + +## Raising events + +Events are raised like the following: + +```php +use Psr\EventDispatcher\EventDispatcherInterface; + +final readonly class SignupService +{ + public function __construct( + private EventDispatcherInterface $eventDispatcher + ) + { + } + + public function signup(SignupForm $form) + { + // handle signup + + $event = new UserSignedUp($form); + $this->eventDispatcher->dispatch($event); + } +} +``` + +First, you create an event supplying it with data that may be useful for +handlers. Then you dispatch the event. + +The event class itself may look like the following: + +```php +final readonly class UserSignedUp +{ + public function __construct( + public SignupForm $form + ) + { + } +} +``` + +## Events hierarchy + +Events don't have any name or wildcard matching on purpose. Event class +names and class/interface hierarchy and composition could be used to achieve +great flexibility: + +```php +interface DocumentEvent +{ +} + +final readonly class BeforeDocumentProcessed implements DocumentEvent +{ +} + +final readonly class AfterDocumentProcessed implements DocumentEvent +{ +} +``` + +With the interface, you can listen to all document-related events: + + +```php +$provider->attach(function (DocumentEvent $event) { + // log events here +}); +``` + +## Detaching event handlers + +To detach a handler from an event you can call `detach()` method: + + +```php +$provider->detach(DocmentEvent::class); +``` + +## Configuring application events + +You usually assign event handlers via application config. See +["Configuration"](configuration.md) for details. diff --git a/src/it/guide/concept/immutability.md b/src/it/guide/concept/immutability.md new file mode 100644 index 00000000..f1faeeed --- /dev/null +++ b/src/it/guide/concept/immutability.md @@ -0,0 +1,160 @@ +# Immutability + +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. + +## Mutable pitfalls (what we avoid) + +```php +// A shared base query built once and reused: +$base = Post::find()->where(['status' => Post::STATUS_PUBLISHED]); + +// Somewhere deep in the code we only need one post: +$one = $base->limit(1)->one(); // mutates the underlying builder (sticky limit!) + +// Later we reuse the same $base expecting a full list: +$list = $base->orderBy(['created_at' => SORT_DESC])->all(); +// Oops: still limited to 1 because the previous limit(1) modified $base. +``` + +## Creating an immutable object in PHP + +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. + +```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 is still 1000 USD, $discounted is 800 USD +``` + +- We mark the class `final` to prevent subclass mutations; alternatively, + design for extension carefully. +- Validate in the constructor and `with*` methods so every instance is + always valid. + +> [!TIP] +> If you define a simple DTO, you can use modern PHP `readonly` and leave properties `public`. The `readonly` keyword +> would ensure that the properties cannot be modified after the object is created. + +## Using clone (and why it is inexpensive) + +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. + +If your object holds mutable sub-objects that must also be copied, implement +`__clone` to deep-clone them: + +```php +final class Order +{ + public function __construct( + private Money $total + ) {} + + public function total(): Money + { + return $this->total; + } + + public function __clone(): void + { + // Money is immutable in our example, so a deep clone is not required. + // If it were mutable, you could do: $this->total = clone $this->total; + } + + public function withTotal(Money $total): self + { + $clone = clone $this; + $clone->total = $total; + return $clone; + } +} +``` + +## Usage style + +- Build a value object once and pass it around. If you need a change, use a + `with*` method that returns a new instance. +- Prefer scalar/immutable fields inside immutable objects; if a field can + mutate, isolate it and deep-clone in `__clone` when needed. + +Immutability aligns well with Yii's preference for predictable, +side-effect-free code and makes services, caching, and configuration more +robust. diff --git a/src/it/guide/databases/db-migrations.md b/src/it/guide/databases/db-migrations.md new file mode 100644 index 00000000..196ac403 --- /dev/null +++ b/src/it/guide/databases/db-migrations.md @@ -0,0 +1,430 @@ +# Migrations + +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. + +The following steps show how database migration can be used by a team during +development: + +1. Tim creates a new migration (e.g. creates a new table, changes a column + definition, etc.). +2. Tim commits the new migration into the source control system (e.g. Git, + Mercurial). +3. Doug updates his repository from the source control system and receives + the new migration. +4. Doug applies the migration to his local development database, thereby + synchronizing his database to reflect the changes that Tim has made. + +And the following steps show how to deploy a new release with database +migrations to production: + +1. Scott creates a release tag for the project repository that contains some + new database migrations. +2. Scott updates the source code on the production server to the release + tag. +3. Scott applies any accumulated database migrations to the production + database. + +Yii provides a set of migration command line tools that allow you to: + +* create new migrations; +* apply migrations; +* revert migrations; +* re-apply migrations; +* show migration history and status. + +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. + +> [!TIP] +> Migrations could affect not only database schema but adjust existing data to fit new schema, create RBAC +hierarchy or clean up cache. + +> [!NOTE] +> When manipulating data using a migration you may find that using your Active Record or entity classes +> for this might be useful because some of the logic is already implemented there. Keep in mind however, that in contrast +> to code written in the migrations, whose nature is to stay constant forever, application logic is subject to change. +> So when using Active Record or entity classes in migration code, changes to the logic in the source code +> may accidentally break the existing migrations. For this reason migration code should be kept independent of other +> application logic such. + +## Initial configuration + +To use migrations, install +[yiisoft/db-migration](https://github.com/yiisoft/db-migration/) package: + +```shell +make composer require yiisoft/db-migration +``` + +Create a directory to store migrations `src/Migration` right in the project +root. + +Add the following configuration to `config/common/params.php`: + +```php +'yiisoft/db-migration' => [ + 'newMigrationNamespace' => 'App\\Migration', + 'sourceNamespaces' => ['App\\Migration'], +], +``` + +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. + +You need a database connection configured as well. See [Working with +databases](../start/databases.md) for an example of configuring it for +PostgreSQL. + +## Creating a migration + +To create a new empty migration, run the following command: + +```sh +make shell +./yii migrate:create +``` + +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: + +``` +make shell +./yii migrate:create create_news_table +``` + + +> [!NOTE] +> Because the `name` argument will be used as part of the generated migration class name, +> it should only contain letters, digits, and/or underscore characters. + +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: + +```php +columnBuilder(); + + $b->createTable('news', [ + 'id' => $cb::uuidPrimaryKey(), + 'title' => $cb::string()->notNull(), + 'content' => $cb::text(), + ]); + } + + public function down(MigrationBuilder $b): void + { + $b->dropTable('news'); + } +} +``` + +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. + +Methods available in migration builder belong to the following types: + +- Raw queries + - getDb — to get database connection instance. + - execute — to execute raw SQL query. +- Data + - insert / update / delete + - batchInsert + - upsert +- Tables and views + - createTable / renameTable / dropTable + - truncateTable + - addCommentOnTable / dropCommentFromTable + - createView / dropView +- Columns + - addColumn / renameColumn / alterColumn / dropColumn + - addCommentOnColumn / dropCommentFromColumn +- Keys and indexes + - addPrimaryKey / dropPrimaryKey + - addForeignKey / dropForeignKey + - createIndex / dropIndex + +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: + +- Keys + - primaryKey + - smallPrimaryKey + - bigPrimaryKey + - uuidPrimaryKey +- Boolean + - boolean +- Numbers + - bit + - tinyint + - smallint + - integer + - bigint + - flat + - double + - decimal +- Strings + - char + - string + - text +- Date and time + - timestamp + - datetime + - datetimeWithTimezone + - time + - timeWithTimezone + - date +- Special types + - money + - binary + - uuid + - array + - structured + - json +- enum + +All the above methods create a base type which could be adjusted with +additional methods: + +- null / notNull +- defaultValue +- unique +- scale / size / unsigned +- primaryKey / autoIncrement +- check +- comment +- computed +- extra +- reference + +### Irreversible migrations + +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. + + +### Transactional migrations + +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. + +As a result, if any operation in the `up()` or `down()` method fails, all +prior operations will be rolled back automatically. + +> Note: Not all DBMS support transactions. And some DB queries cannot be put into a transaction. For some examples, +please refer to [implicit commit](https://dev.mysql.com/doc/refman/5.7/en/implicit-commit.html). + +## Generating a migration + +Instead of writing migrations by hand, the command provides a convenient way +generate some of the code. + +```shell +make shell +./yii migrate:create -- my_first_table --command=table --fields=name,example --table-comment=my_first_table +``` + +That would generate the following: + +```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'); + } +} +``` + +Commands available are: + +- create - empty migration. +- 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)`. +- dropTable - dropping a table. +- addColumn - adding a column. +- dropColumn - dropping a column. +- junction - creating a junction table. Use `--and` specify a second table. + +## Applying Migrations + +To upgrade a database to its latest structure, you should apply all +available new migrations using the following command: + +``` +./yii migrate:up +``` + +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. + +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. + +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: + +``` +./yii migrate:up --limit=3 +``` + +## Reverting Migrations + +To revert (undo) one or multiple migrations that have been applied before, +you can run the following command: + +``` +./yii migrate:down # revert the most recently applied migration +./yii migrate:down --limit=3 # revert the most 3 recently applied migrations +./yii migrate:down --all # revert all migrations +``` + +> Note: Not all migrations are reversible. Trying to revert such migrations will cause an error and stop the +entire reverting process. + + +## Redoing Migrations + +Redoing migrations means first reverting the specified migrations and then +applying again. This can be done as follows: + +``` +./yii migrate:redo # redo the last applied migration +./yii migrate:redo --limit=3 # redo the last 3 applied migrations +./yii migrate:redo --all # redo all migrations +``` + +> Note: If a migration is not reversible, you will not be able to redo it. + +## Listing Migrations + +To list which migrations have been applied and which are not, you may use +the following commands: + +``` +./yii migrate/history # showing the last 10 applied migrations +./yii migrate:history --limit=5 # showing the last 5 applied migrations +./yii migrate:history --all # showing all applied migrations + +./yii migrate:new # showing the first 10 new migrations +./yii migrate:new --limit=5 # showing the first 5 new migrations +./yii migrate:new --all # showing all new migrations +``` + +### Upgrading from Yii 2.0 + +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. + +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. diff --git a/src/it/guide/glossary.md b/src/it/guide/glossary.md new file mode 100644 index 00000000..cb8f973c --- /dev/null +++ b/src/it/guide/glossary.md @@ -0,0 +1,92 @@ +# A + +## alias + +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). + +## asset + +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). + +# C + +## configuration + +The 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). + +# D + +## DI + +Dependency Injection is a programming technique where an object injects a +dependent object. Read more in ["Dependency injection and +container"](concept/di-container.md). + +# I + +## installation + +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. + +# M + +## middleware + +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). + +## module + +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. + +# N + +## namespace + +Namespace refers to a [PHP language +feature](https://www.php.net/manual/en/language.namespaces.php) to group +multiple classes under a certain name. + +# P + +## package + +A package usually refers to [Composer +package](https://getcomposer.org/doc/). It's code ready for reuse and +redistribution installable automatically via package manager. + +# R + +## rule + +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. + +# Q + +## queue + +A queue is similar to a stack. Queue follows First-In-First-Out +methodology. Yii has a [yiisoft/queue](https://github.com/yiisoft/queue) +package. + +# V + +## vendor + +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/). diff --git a/src/it/guide/index.md b/src/it/guide/index.md new file mode 100644 index 00000000..9b56817d --- /dev/null +++ b/src/it/guide/index.md @@ -0,0 +1,156 @@ +# La guida definitiva a Yii3 + +Pubblichiamo questa guida secondo i [Termini della documentazione +Yii](https://www.yiiframework.com/license#docs). + +## Introduzione + +- [Informazioni su Yii](intro/what-is-yii.md) +- [Aggiornamento dalla versione 2.0](intro/upgrade-from-v2.md) + +## Per iniziare + +- [Cosa devi sapere?](start/prerequisites.md) +- [Creazione di un progetto](start/creating-project.md) +- [Applicazioni in esecuzione](start/workflow.md) +- [Dire ciao](start/hello.md) +- [Lavorare con i moduli](start/forms.md) +- [Lavorare con i Database](start/databases.md) +- [Generare codice con Gii](start/gii.md) TODO +- [Guardando avanti](start/looking-ahead.md) + +## Struttura applicativa + +- [Panoramica della struttura applicativa](structure/overview.md) +- [Script d’avvio](structure/entry-script.md) +- [Applicazione](structure/application.md) +- [Componenti di servizio](structure/service.md) +- [Azioni](structure/action.md) +- [Dominio](structure/domain.md) +- [Middleware](structure/middleware.md) +- [Pacchetti](structure/package.md) + +## Concetti chiave + +- [Caricamento automatico delle classi](concept/autoloading.md) +- [Contenitore d’iniezione delle dipendenze](concept/di-container.md) +- [Configurazione](concept/configuration.md) +- [Alias](concept/aliases.md) +- [Eventi](concept/events.md) +- [Immutabilità](concept/immutability.md) + +## Gestione delle richieste + +- [Routing e generazione di URL](runtime/routing.md) +- [Richiesta](runtime/request.md) +- [Risposta](runtime/response.md) +- [Sessioni](runtime/sessions.md) +- [Cookie](runtime/cookies.md) +- [Gestione degli errori](runtime/handling-errors.md) +- [Logging](runtime/logging.md) + +## Viste + +- [Vista](views/view.md) +- [Motori di template](views/template-engines.md) TODO: verificare! +- [Iniezione di parametri nella vista](views/view-injections.md) +- [Script, stili e metatag](views/script-style-meta.md) Da fare: verificare! +- [Assets](views/asset.md) TODO: verify! +- [Widget](views/widget.md) TODO: verify! + +## Lavorare con i database + +- [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) +- [Migrazioni](databases/db-migrations.md) TODO: verify/update! + +## Ottenere dati dagli utenti + +- [Creazione di moduli](input/forms.md) TODO +- [Convalida degli + input](https://github.com/yiisoft/validator/blob/master/docs/guide/en/README.md) +- [Caricamento dei file](input/file-upload.md) TODO +- [Raccolta di input tabulari](input/tabular-input.md) TODO + +## Visualizzazione dei dati + +- [Formattazione dei dati](output/formatting.md) TODO +- [Paginazione](output/pagination.md) TODO +- [Ordinamento](output/sorting.md) TODO +- [Fornitori di dati](output/data-providers.md) TODO +- [Widget dati](output/data-widgets.md) TODO + +## Sicurezza + +- [Panoramica sulla sicurezza](security/overview.md) +- [Autenticazione](security/authentication.md) +- [Verifica delle autorizzazioni](security/authorization.md) TODO: verify + and complete! +- [Lavorare con le password](security/passwords.md) +- [Crittografia](security/cryptography.md) +- [Migliori pratiche](security/best-practices.md) + + +## Caching + +- [Panoramica sulla cache](caching/overview.md) +- [Caching dei dati](caching/data.md) +- [Caching dei frammenti](caching/fragment.md) TODO +- [Caching delle pagine](caching/page.md) TODO +- [Caching HTTP](caching/http.md) TODO + + +## API REST + +- [Introduzione rapida](rest/quick-start.md) TODO +- [Risorse](rest/resources.md) Da fare +- [Controller](rest/controllers.md) TODO +- [Routing](rest/routing.md) TODO +- [Autenticazione](rest/authentication.md) TODO +- [Rate limiting](rest/rate-limiting.md) TODO +- [Versionamento](rest/versioning.md) TODO +- [Gestione degli errori](rest/error-handling.md) TODO + +## Strumenti di sviluppo + +- Barra degli strumenti di debug e debugger +- Generare codice utilizzando Gii +- Generazione della documentazione API + + +## Testing + +- [Panoramica sul Testing](testing/overview.md) TODO +- [Configurazione dell'ambiente di test](testing/environment-setup.md) TODO +- [Test unitari](testing/unit.md) TODO +- [Test funzionali](testing/functional.md) TODO +- [Test di accettazione](testing/acceptance.md) TODO +- [Fixtures](testing/fixtures.md) TODO + + +## Argomenti speciali + +- [Applicazioni console](tutorial/console-applications.md) +- [Internazionalizzazione](tutorial/i18n.md) TODO +- [Mailing](tutorial/mailing.md) +- [Ottimizzazione delle prestazioni](tutorial/performance-tuning.md) +- [Usare Yii con event loop](tutorial/using-with-event-loop.md) +- [Usare Yii con RoadRunner](tutorial/using-yii-with-roadrunner.md) +- [Usare Yii con Swoole](tutorial/using-yii-with-swoole.md) + +## Helper + +- [Array](https://github.com/yiisoft/arrays/) +- [File](https://github.com/yiisoft/files/) +- [Html](https://github.com/yiisoft/html/) +- [Json](https://github.com/yiisoft/json) +- [Utilità di rete](https://github.com/yiisoft/network-utilities/) +- [VarDumper](https://github.com/yiisoft/var-dumper) +- [Stringhe](https://github.com/yiisoft/strings) + +## Extra + +- [Ricettario](../cookbook/index.md) +- [Glossario](glossary.md) diff --git a/src/it/guide/intro/upgrade-from-v2.md b/src/it/guide/intro/upgrade-from-v2.md new file mode 100644 index 00000000..7947b135 --- /dev/null +++ b/src/it/guide/intro/upgrade-from-v2.md @@ -0,0 +1,126 @@ +# Aggiornamento dalla versione 2.0 + +> Se non hai mai utilizzato Yii 2.0, puoi saltare questa sezione e passare direttamente alla sezione “[Per iniziare](../start/prerequisites.md)”. +> + +Pur condividendo alcune idee e valori comuni, Yii3 è concettualmente diverso +da Yii 2.0. Non esiste un percorso di aggiornamento semplice, quindi è +opportuno innanzitutto [verificare la politica di manutenzione e le date di +fine vita di Yii 2.0](https://www.yiiframework.com/release-cycle) e +valutare la possibilità di avviare nuovi progetti su Yii3 mantenendo quelli +esistenti su Yii 2.0. + +## Requisiti PHP + +Yii3 richiede PHP 8.2 o versioni successive. Di conseguenza, vengono +utilizzate funzionalità del linguaggio che non erano presenti in Yii 2.0: + +- [Dichiarazioni dei + tipi](https://www.php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration) +- [Dichiarazioni del tipo di + ritorno](https://www.php.net/manual/en/functions.returning-values.php#functions.returning-values.type-declaration) +- [Visibilità delle costanti di + classe](https://www.php.net/manual/en/language.oop5.constants.php) +- [Argomenti + denominati](https://www.php.net/manual/en/functions.arguments.php#functions.named-arguments) +- [Classi + anonime](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) +- [Generatori](https://www.php.net/manual/en/language.generators.php) +- [Funzioni + variadiche](https://www.php.net/manual/en/functions.arguments.php#functions.variable-arg-list) +- [Proprietà in sola + lettura](https://www.php.net/manual/en/language.oop5.properties.php#language.oop5.properties.readonly-properties) +- [Classi in sola + lettura](https://www.php.net/manual/en/language.oop5.basic.php#language.oop5.basic.class.readonly) +- [Promozione delle proprietà del + costruttore](https://www.php.net/manual/en/language.oop5.decon.php#language.oop5.decon.constructor.promotion) +- [Attributi](https://www.php.net/manual/en/language.attributes.php) + +## Rifattorizzazione preliminare + +È una buona idea rifattorizzare il tuo progetto Yii 2.0 prima di trasferirlo +su Yii3. Ciò renderebbe più facile il trasferimento e apporterebbe benefici +al progetto in questione mentre non è ancora stato trasferito su Yii3. + +### Utilizza l’iniezione delle dipendenze (DI) invece del localizzatore di servizi (Service Locator) + +Poiché Yii3 ti obbliga a iniettare le dipendenze, è una buona idea prepararsi e passare dall'uso del +localizzatore di servizi (`Yii::$app->`) al [contenitore DI](https://www.yiiframework.com/doc/guide/2.0/en/concept-di-container). + +Se l'utilizzo del contenitore DI è problematico per qualsiasi motivo, valuta la possibilità di spostare tutte le chiamate a `Yii::$app->` alle azioni del controller +e ai widget e di passare manualmente le dipendenze da un controller a ciò che ne ha bisogno. + +Per una spiegazione dell'idea, consultare [Iniezione di dipendenze e +contenitore](../concept/di-container.md). + +### Introdurre repository per ottenere dati + +Poiché Active Record non è l'unico modo per lavorare con un database in +Yii3, prendete in considerazione l'introduzione di repository che nascondano +i dettagli relativi all'ottenimento dei dati e li raccolgano in un unico +posto. Potrete rifarlo in un secondo momento: + +```php +final readonly class PostRepository +{ + public function getArchive() + { + // ... + } + + public function getTop10ForFrontPage() + { + // ... + } + +} +``` + +### Separare il livello di dominio dall'infrastruttura + +Nel caso in cui si disponga di un dominio ricco e complesso, è consigliabile +separarlo dall'infrastruttura fornita da un framework, in modo che tutta la +logica di business risieda in classi indipendenti dal framework. + +### Suddividi di più in componenti + +I servizi Yii3 sono concettualmente simili ai componenti di Yii 2.0, quindi +è consigliabile spostare le parti riutilizzabili dell'applicazione nei +componenti. + +## Cose da imparare + +### Docker + +I modelli d’applicazione predefiniti utilizzano +[Docker](https://www.docker.com/get-started/) per eseguire l'applicazione. È +consigliabile imparare a utilizzarlo e impiegarlo nei propri progetti poiché +offre numerosi vantaggi: + +1. Esattamente lo stesso ambiente della produzione. +2. Non è necessario installare nulla tranne Docker stesso. +3. L'ambiente è per applicazione, non per server. + +### Variabili d'ambiente + +I modelli dell'applicazione Yii3 utilizzano [variabili +d’ambiente](https://en.wikipedia.org/wiki/Environment_variable) per +configurare parti dell'applicazione. Il concetto è [molto utile per le +applicazioni Dockerizzate](https://12factor.net/) , ma potrebbe risultare +estraneo agli utenti di Yii 1.1 e Yii 2.0. + +### Azioni + +A differenza di Yii 2.0, Yii3 non richiede l’uso di controller. Utilizza +invece le [azioni](../structure/action.md), che sono un qualsiasi oggetto +richiamabile. È possibile organizzarle in controller simili a Yii 2, ma non +è necessario. + +### Struttura applicativa + +La struttura dell'applicazione Yii3 suggerita è diversa da quella di Yii +2.0. È descritta in [struttura applicativa](../structure/overview.md). + +Nonostante ciò, Yii3 è flessibile, quindi è ancora possibile utilizzare una +struttura simile a Yii 2.0 con Yii3. diff --git a/src/it/guide/intro/what-is-yii.md b/src/it/guide/intro/what-is-yii.md new file mode 100644 index 00000000..7ee9514f --- /dev/null +++ b/src/it/guide/intro/what-is-yii.md @@ -0,0 +1,72 @@ +# Cos'è Yii + +Yii è un framework PHP ad alte prestazioni basato su pacchetti per lo +sviluppo di applicazioni moderne. Il nome Yii (pronunciato “Yee” o “[ji:]”) +significa “semplice ed evolutivo” in cinese. Si può anche considerare come +l'acronimo di **Yes It Is**! + +## Per cosa è più indicato usare Yii + +Yii è un framework generico per la programmazione web. È possibile +utilizzarlo per sviluppare tutti i tipi di applicazioni web utilizzando +PHP. Grazie alla sua architettura e al sofisticato supporto della cache, è +particolarmente adatto allo sviluppo di applicazioni su larga scala come +portali, sistemi di gestione dei contenuti, e-commerce, API REST, ecc. + +## Come si posiziona Yii rispetto ad altri framework? + +Se hai già familiarità con un altro framework, potresti trovare interessante +sapere come si posiziona Yii rispetto ad esso: + +- Yii adotta la [filosofia dell'essere pratico e + utile](../../internals/001-yii-values.md) ottenendo: + - Prestazioni sia nello sviluppo che nell'esecuzione. + - Comode impostazioni predefinite personalizzabili. + - Orientamento alla pratica. + - Semplicità. + - Esplicitezza. + - Coerenza. + + Yii non cercherà mai di sovradimensionare le cose principalmente per seguire alcuni modelli di progettazione. +- Yii utilizza ampiamente le interfacce PSR con la possibilità di riutilizzare ciò che la comunità PHP ha creato e persino di + sostituire le implementazioni di base, se necessario. +- Yii è sia un insieme di librerie che un framework full-stack che fornisce molte funzionalità collaudate e pronte all'uso: + caching, logging, motore di template, astrazione dei dati, strumenti di sviluppo, generazione di codice e altro ancora. +- Yii è estensibile. È possibile personalizzare o sostituire ogni parte del codice del core. È inoltre possibile + sfruttare la solida architettura di Yii per utilizzare o sviluppare pacchetti ridistribuibili. +- Le prestazioni elevate sono sempre un obiettivo primario di Yii. + +Yii è supportato da un [forte team di sviluppatori +principali](https://www.yiiframework.com/team/) sostenuto finanziariamente +dalla [fondazione OpenCollective](https://opencollective.com/yiisoft), +nonché da una vasta comunità di professionisti che contribuiscono +costantemente allo sviluppo di Yii. Il team di sviluppatori Yii segue da +vicino le ultime tendenze nello sviluppo web e le migliori pratiche e +funzionalità presenti in altri framework e progetti. Le migliori pratiche e +funzionalità più rilevanti trovate altrove vengono incorporate nel framework +principale ed esposte tramite interfacce semplici ed eleganti. + + +## Versioni di Yii + +Yii ha attualmente tre versioni principali disponibili: 1.1, 2.0 e 3.0. + +- La versione 1.1 è quella di vecchia generazione ed è ora in modalità + bugfix con congelamento delle funzionalità. +- La versione 2.0 è una versione stabile attuale in modalità bugfix con + congelamento delle funzionalità. +- La versione 3.0 è quella attualmente in fase di sviluppo. Questa guida + riguarda principalmente la versione 3. + + +## Requisiti e prerequisiti + +Yii3 richiede PHP 8.2 o versioni successive, ma alcuni pacchetti funzionano +con versioni precedenti di PHP, come PHP 7.4. + +L'utilizzo di Yii richiede conoscenze di base della programmazione orientata +agli oggetti (OOP), poiché Yii è un framework basato esclusivamente su OOP. +Yii3 utilizza anche le ultime funzionalità PHP, come le dichiarazioni di +tipo e i generatori. Comprendere questi concetti ti aiuterà ad apprendere +Yii3 più rapidamente. + diff --git a/src/it/guide/runtime/cookies.md b/src/it/guide/runtime/cookies.md new file mode 100644 index 00000000..9a8ff8a1 --- /dev/null +++ b/src/it/guide/runtime/cookies.md @@ -0,0 +1,211 @@ +# Cookies + +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. + +## Reading cookies + +You could obtain Cookie values from server request that's available as route +handler (such as controller action) argument: + +```php +private function actionProfile(\Psr\Http\Message\ServerRequestInterface $request) +{ + $cookieValues = $request->getCookieParams(); + $cookieValue = $cookieValues['cookieName'] ?? null; + // ... +} +``` + +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. + +Here’s an example of how to work with cookies using the +`\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); +``` + +After forming a cookie call `addToResponse()` passing an instance of +`\Psr\Http\Message\ResponseInterface` to add corresponding HTTP headers to +it. + +## Signing and encrypting cookies + +To prevent the substitution of the cookie value, the package provides two +implementations: + +`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. + +Encryption is more secure than signing but has lower performance. + +```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); +``` + +To validate and get back the pure value, use the `validate()` and +`decrypt()` method. + +```php +$cookie = $signer->validate($signedCookie); +$cookie = $encryptor->decrypt($encryptedCookie); +``` + +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. + +```php +if ($signer->isSigned($cookie)) { + $cookie = $signer->validate($cookie); +} + +if ($encryptor->isEncrypted($cookie)) { + $cookie = $encryptor->decrypt($cookie); +} +``` + +It makes sense to sign or encrypt the value of a cookie if you store +important data that a user shouldn't change. + +### Automating encryption and signing + +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. + +This middleware provides the following features: + +- Validates and decrypts the cookie parameter values from the request. +- Excludes the cookie parameter from the request if it was tampered with and + logs information about it. +- Encrypts/signs cookie values and replaces their clean values in the + `Set-Cookie` headers in the response. + +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`. + +```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, +]; +``` + +For more information on using the wildcard pattern, see the +[yiisoft/strings](https://github.com/yiisoft/strings#wildcardpattern-usage) +package. + +Creating and using 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); +``` + +If the `$cookiesSettings` array is empty, no cookies will be encrypted and +signed. + +## Cookies security + +You should configure each cookie to be secure. Important security settings +are: + +- `httpOnly`. Setting it to `true` would prevent JavaScript to access cookie + value. +- `secure`. Setting it to `true` would prevent sending cookie via `HTTP`. It + will be sent via `HTTPS` only. +- `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. +- Sign or encrypt the value of the cookie to prevent spoofing of values if + the data in the value shouldn't be tampered with. diff --git a/src/it/guide/runtime/handling-errors.md b/src/it/guide/runtime/handling-errors.md new file mode 100644 index 00000000..e009564b --- /dev/null +++ b/src/it/guide/runtime/handling-errors.md @@ -0,0 +1,286 @@ +# Handling errors + +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: + +- [PSR-15](https://www.php-fig.org/psr/psr-15/) middleware for catching + unhandled errors. +- PSR-15 middleware for mapping certain exceptions to custom responses. +- Production and debug modes. +- Debug mode displays details, stacktrace, has dark and light themes and + handy buttons to search for error without typing. +- Takes PHP settings into account. +- Handles out of memory errors, fatal errors, warnings, notices, and + exceptions. +- Can use any [PSR-3](https://www.php-fig.org/psr/psr-3/) compatible logger + for error logging. +- Detects a response format based on a mime type of the request. +- Supports responding with HTML, plain text, JSON, XML, and headers out of + the box. +- You can implement your own error rendering for extra types. + +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). + +## Using error handler + +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. + +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: + +```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}', + ]), + // ... +]; +``` + +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: + +```php +try { + 10 / 0; +} catch (\Yiisoft\ErrorHandler\Exception\ErrorException $e) { + // Write a log or something else. +} +// execution continues... +``` + +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: + +```php +use Psr\Http\Message\ResponseFactoryInterface; +use Yiisoft\ErrorHandler\Middleware\ExceptionResponder; +use Yiisoft\Injector\Injector; + +return [ + // ... + ErrorHandler::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); + }, +]; +``` + +Note that when configuring application middleware stack, you must place +`Yiisoft\ErrorHandler\Middleware\ExceptionResponder` before +`Yiisoft\ErrorHandler\Middleware\ErrorCatcher`. + +## Rendering error data + +One of the renderers could render error data into a certain format. The +following renderers are available out of the box: + +- `Yiisoft\ErrorHandler\Renderer\HeaderRenderer` - Renders error into HTTP + headers. It's used for `HEAD` request. +- `Yiisoft\ErrorHandler\Renderer\HtmlRenderer` - Renders error into HTML. +- `Yiisoft\ErrorHandler\Renderer\JsonRenderer` - Renders error into JSON. +- `Yiisoft\ErrorHandler\Renderer\PlainTextRenderer` - Renders error into + plain text. +- `Yiisoft\ErrorHandler\Renderer\XmlRenderer` - Renders error into XML. + +The renderer produces detailed error data depending on whether debug mode is +enabled or disabled. + +An Example of header rendering with a debugging mode turned off: + +``` +... +X-Error-Message: An internal server error occurred. +... +``` + +An Example of header rendering with a debugging mode turned on: + +``` +... +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 +... +``` + +Example of JSON rendering output with a debugging mode turned off: + +```json +{"message":"An internal server error occurred."} +``` + +An Example of JSON rendering output with debugging mode turned on: + +```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": "->" + }, + ... + ] +} +``` + +Example of HTML rendering with debugging mode turned off: + +![View production](/images/guide/runtime/view-production.png) + +Example of HTML rendering with debugging mode on and a light theme: + +![View development with light +theme](/images/guide/runtime/view-development-light.png) + +Example of HTML rendering with debugging mode on and a dark theme: + +![View development with dark +theme](/images/guide/runtime/view-development-dark.png) + +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 that you register within +the error catcher. By default, it supports JSON, XML, and plain text. + +### Implementing your own renderer + +You may customize the error response format by providing your own instance +of `Yiisoft\ErrorHandler\ThrowableRendererInterface` when registering error +catcher middleware. + +```php +use Psr\Http\Message\ServerRequestInterface; +use Yiisoft\ErrorHandler\ErrorData; +use Yiisoft\ErrorHandler\ThrowableRendererInterface; + +final readonly class MyRenderer implements ThrowableRendererInterface +{ + public function render(Throwable $t, ServerRequestInterface $request = null): ErrorData + { + return new ErrorData($t->getMessage()); + } + + public function renderVerbose(Throwable $t, ServerRequestInterface $request = null): ErrorData + { + return new ErrorData( + $t->getMessage(), + ['X-Custom-Header' => 'value-header'], // Headers to be added to the response. + ); + } +}; +``` + +You may configure it in the application configuration `config/web.php`: + +```php +use Psr\Container\ContainerInterface; +use Psr\Http\Message\ResponseFactoryInterface; +use Yiisoft\ErrorHandler\ErrorHandler; +use Yiisoft\ErrorHandler\Middleware\ErrorCatcher; + +return [ + // ... + ErrorCatcher::class => static function (ContainerInterface $container): ErrorCatcher { + $errorCatcher = new ErrorCatcher( + $container->get(ResponseFactoryInterface::class), + $container->get(ErrorHandler::class), + $container, + ); + // Returns a new instance without renderers by the specified content types. + $errorCatcher = $errorCatcher->withoutRenderers('application/xml', 'text/xml'); + // Returns a new instance with the specified content type and renderer class. + return $errorCatcher->withRenderer('my/format', new MyRenderer()); + }, + // ... +]; +``` + +## Friendly exceptions + +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: + +```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; + } +} +``` + +When the application throws such an exception, the error renderer would +display the name and the solution if the debug mode is on. diff --git a/src/it/guide/runtime/logging.md b/src/it/guide/runtime/logging.md new file mode 100644 index 00000000..2becad6b --- /dev/null +++ b/src/it/guide/runtime/logging.md @@ -0,0 +1,413 @@ +# Logging + +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. + +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. + +Using the Yii logging framework involves the following steps: + +* Record [log messages](#log-messages) at various places in your code; +* Configure [log targets](#log-targets) in the application configuration to + filter and export log messages; +* Examine the filtered logged messages exported by different targets + (e.g. the Yii debugger). + +In this section, the focus in on the first two steps. + +## Log Messages + +To record log messages, you need an instance of PSR-3 logger. A class that +writes log messages should receive it as a dependency: + +```php +class MyService +{ + private $logger; + + public function __construct(\Psr\Log\LoggerInterface $logger) + { + $this->logger = $logger; + } +} +``` + +Recording a log message is as simple as calling one of the following logging +methods that correspond to log levels: + +- `emergency` - System is unusable. +- `alert` - Action must be taken immediately. Example: Entire website down, + database unavailable, etc. This should trigger the SMS alerts and wake + you up. +- `critical` - Critical conditions. Example: Application component + unavailable, unexpected exception. +- `error` - Runtime errors that don't require immediate action but should + typically be logged and monitored. +- `warning` - Exceptional occurrences that aren't errors. Example: Use of + deprecated APIs, poor use of an API, undesirable things that aren't + necessarily wrong. +- `notice` - Normal but significant events. +- `info` - Interesting events. Example: User logs in, SQL logs. +- `debug` - Detailed debug information. + +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. + +```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__]); + } +} +``` + +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. + +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. + +> [!IMPORTANT] +> The logging methods described above are actually shortcuts to the [[\Psr\Log\LoggerInterface::log()]]. + +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. + + +## Log targets + +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. + +You can register many log targets in an application by configuring them +through the `\Yiisoft\Log\Logger` constructor: + +```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 +]); +``` + +In the above code, two log targets are registered: + +* the first target selects error and warning messages and writes them to + `/path/to/app.log` file; +* the second target selects emergency, alert, and critical messages under the categories whose names start with +`Yiisoft\Cache\`, and sends them in an email to both `admin@example.com` and `developer@example.com`. + +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. + +* [[\Yiisoft\Log\PsrTarget]]: passes log messages to another PSR-3 + compatible logger. +* [[\Yiisoft\Log\StreamTarget]]: writes log messages into a specified output + stream. +* [[\Yiisoft\Log\Target\Db\DbTarget]]: saves log messages in database. +* [[\Yiisoft\Log\Target\Email\EmailTarget]]: sends log messages to + pre-specified email addresses. +* [[\Yiisoft\Log\Target\File\FileTarget]]: saves log messages in files. +* [[\Yiisoft\Log\Target\Syslog\SyslogTarget]]: saves log messages to syslog + by calling the PHP function `syslog()`. + +In the following, we will describe the features common to all log targets. + + +### Message Filtering + +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. + +The target `setLevels()` method takes an array consisting of one or several +of `\Psr\Log\LogLevel` constants. + +By default, the target will process messages of *any* severity level. + +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\*`. + +By default, the target will process messages of *any* category. + +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. + +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`. + +```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']); +``` + +### Message Formatting + +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: + +``` +2020-12-05 09:27:52.223800 [info][application] Some message + +Message context: + +time: 1607160472.2238 +memory: 4398536 +category: 'application' +``` + +By default, log messages have the following format: + +``` +Timestamp Prefix[Level][Category] Message Context +``` + +You may customize this format by calling +[[\Yiisoft\Log\Target::setFormat()|setFormat()]] method, which takes a PHP +callable returning a custom-formatted message. + +```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 +``` + +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). + +```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: ... +``` + +The PHP callable that's passed to the +[[\Yiisoft\Log\Target::setFormat()|setFormat()]] and +[[\Yiisoft\Log\Target::setPrefix()|setPrefix()]] methods has the following +signature: + +```php +function (\Yiisoft\Log\Message $message, array $commonContext): string; +``` + +Besides message prefixes, log targets also append some common context information to each of the log messages. +You may adjust this behavior by calling target [[\Yiisoft\Log\Target::setCommonContext()|setCommonContext()]] +method, passing an array of data in the `key => value` format that you want to include. +For example, the following log target configuration specifies that only the +value of the `$_SERVER` variable will be appended to the log messages. + +```php +$fileTarget = new \Yiisoft\Log\Target\File\FileTarget('/path/to/app.log'); +$fileTarget->setCommonContext(['server' => $_SERVER]); +``` + + +### Message Trace Level + +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: + +```php +$logger = new \Yiisoft\Log\Logger($targets); +$logger->setTraceLevel(3); +``` + +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. + +```php +$logger = new \Yiisoft\Log\Logger($targets); +$logger->setExcludedTracePaths(['/path/to/file', '/path/to/folder']); +``` + +> [!IMPORTANT] +> Getting call stack information isn't trivial. Therefore, you should only use this feature during development +or when debugging an application. + + +### Message flushing and exporting + +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: + + +```php +$logger = new \Yiisoft\Log\Logger($targets); +$logger->setFlushInterval(100); // default is 1000 +``` + +> [!IMPORTANT] +> Message flushing also occurs when the application ends, +which ensures log targets can receive complete log messages. + +When the [[\Yiisoft\Log\Logger|logger object]] flushes log messages to [log targets](#log-targets), +they don't get exported immediately. Instead, the message exporting only occurs when a log target + accumulates a certain number of the filtered messages. You can customize this number by calling the +[[\Yiisoft\Log\Target::setExportInterval()|setExportInterval()]] method of individual +[log targets](#log-targets), like the following: + +```php +$fileTarget = new \Yiisoft\Log\Target\File\FileTarget('/path/to/app.log'); +$fileTarget->setExportInterval(100); // default is 1000 +``` + +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: + +```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] +> Frequent message flushing and exporting will degrade the performance of your application. + + +### Toggling log targets + +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: + +```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(); + } +} +``` + +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. + + +### Creating new targets + +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. + +The following protected methods will also be available for child targets: + +- `getMessages` - Get a list of log messages ([[\Yii\Log\Message]] + instances). +- `getFormattedMessages` - Get a list of log messages formatted as strings. +- `formatMessages` - Get all log messages formatted as a string. +- `getCommonContext` - Get an array with common context data in the `key => + value` format. + +For more details, you may refer to any of the log target classes included in +the package. + +> [!TIP] +> Instead of creating your own loggers, you may try any PSR-3 compatible logger such +as [Monolog](https://github.com/Seldaek/monolog) by using [[\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/it/guide/runtime/request.md b/src/it/guide/runtime/request.md new file mode 100644 index 00000000..e319e7f0 --- /dev/null +++ b/src/it/guide/runtime/request.md @@ -0,0 +1,189 @@ +# Request + +HTTP request has a method, URI, a set of headers and a body: + +``` +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!" +} +``` + +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. + +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: + +```php +public function view(ServerRequestInterface $request): ResponseInterface +{ + // ... +} +``` + +## Method + +The method could be obtained from a request object: + +```php +$method = $request->getMethod(); +``` + +Usually it's one of the: + +- GET +- POST +- PUT +- DELETE +- HEAD +- PATCH +- OPTIONS + +In case you want to make sure the request method is of a certain type, there +is a special class with method names: + +```php +use Yiisoft\Http\Method; + +if ($request->getMethod() === Method::POST) { + // method is POST +} +``` + +## URI + +A URI has: + +- Scheme (`http`, `https`) +- Host (`yiiframework.com`) +- Port (`80`, `443`) +- Path (`/posts/1`) +- Query string (`page=1&sort=+id`) +- Fragment (`#anchor`) + +You can obtain `UriInterface` from request like the following: + +```php +$uri = $request->getUri(); +``` + +Then you can get various details from its methods: + +- `getScheme()` +- `getAuthority()` +- `getUserInfo()` +- `getHost()` +- `getPort()` +- `getPath()` +- `getQuery()` +- `getFragment()` + +## Headers + +There are various methods to inspect request headers. To get all headers as +an array: + +```php +$headers = $request->getHeaders(); +foreach ($headers as $name => $values) { + // ... +} +``` + +To get a single header: + +```php +$values = $request->getHeader('Accept-Encoding'); +``` + + +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: + +```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. +} +``` + +To check if a header is present in the request: + +```php +if ($request->hasHeader('Accept-Encoding')) { + // ... +} +``` + +## Body + +There are two methods to get body contents. The first is getting the body as +it is without parsing: + +```php +$body = $request->getBody(); +``` + +The `$body` would be an instance of `Psr\Http\Message\StreamInterface`. + +Also, you could get a parsed body: + +```php +$bodyParameters = $request->getParsedBody(); +``` + +Parsing depends on PSR-7 implementation and may require middleware for +custom body formats. + +```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); + } +} +``` + +## File uploads + +Uploaded files that user submitted from a form with `enctype` attribute +equals to `multipart/form-data` are handled via special request method: + +```php +$files = $request->getUploadedFiles(); +foreach ($files as $file) { + if ($file->getError() === UPLOAD_ERR_OK) { + $file->moveTo('path/to/uploads/new_filename.ext'); + } +} +``` + +## Attributes + +Application middleware may set custom request attributes using +`withAttribute()` method. You can get these attributes with +`getAttribute()`. diff --git a/src/it/guide/runtime/response.md b/src/it/guide/runtime/response.md new file mode 100644 index 00000000..58ae1a2f --- /dev/null +++ b/src/it/guide/runtime/response.md @@ -0,0 +1,128 @@ +# Response + +HTTP response has status code and message, a set of headers and a body: + +``` +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! +``` + +Yii uses [PSR-7 `Response`](https://www.php-fig.org/psr/psr-7/) in the web +application to represent response. + +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. + +```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; + } +} +``` + +## Status code + +You can set a status code like the following: + +```php +use Yiisoft\Http\Status; + +$response = $response->withStatus(Status::NOT_FOUND); +``` + +Majority of status codes are available from `Status` class for convenience +and readability. + +## Headers + +You can set headers like this: + +```php +$response = $response->withHeader('Content-type', 'application/json'); +``` + +If there is a need to append a header value to the existing header: + +```php +$response = $response->withAddedHeader('Set-Cookie', 'qwerty=219ffwef9w0f; Domain=somecompany.co.uk; Path=/; Expires=Wed, 30 Aug 2019 00:00:00 GMT'); +``` + +And, if needed, headers could be removed: + +```php +$response = $response->withoutHeader('Set-Cookie'); +``` + +## Body + +Response body is an object implementing `Psr\Http\Message\StreamInterface`. + +You can write to it via the interface itself: + +```php +$body = $response->getBody(); +$body->write('Hello'); +``` + + +## Examples + +### Redirecting + +```php +use Yiisoft\Http\Status; + +return $response + ->withStatus(Status::PERMANENT_REDIRECT) + ->withHeader('Location', 'https://www.example.com'); +``` + +Note that there are different statuses used for redirection: + +| Code | Usage | What is it for | +|------|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 301 | `Status::MOVED_PERMANENTLY` | Permanently changed a URL structure. Search engines update their indexes, and browsers cache it. | +| 308 | `Status::PERMANENT_REDIRECT` | Like 301, but guarantees the HTTP method won't change. | +| 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. | +| 307 | `Status::TEMPORARY_REDIRECT` | Like 302, but guarantees the HTTP method won't change. | +| 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`. | + +### Responding with 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/it/guide/runtime/routing.md b/src/it/guide/runtime/routing.md new file mode 100644 index 00000000..2b331676 --- /dev/null +++ b/src/it/guide/runtime/routing.md @@ -0,0 +1,326 @@ +# Routing and URL generation + +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*. + +The reverse process of routing is *URL generation*, which creates a URL from +a given named route and the associated query parameters. When you later +request the created URL, the routing process can resolve it back into the +original route and query parameters. + +Routing and URL generation are separate services, but they use a common set +of routes for both URL matching and URL generation. + +## Configuring routes + +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: + +```php +action([SiteController::class, 'index']) + ->name('site/index') +]; +``` + +The file returns an array of routes. When defining a route, you start with a +method corresponding to a certain HTTP request type: + +- get +- post +- put +- delete +- patch +- head +- options + +If you need many methods, you can use `methods()`: + +```php +action([SiteController::class, 'user']) + ->name('site/user') +]; +``` + +All these methods accept a route pattern and a handler. 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. You could specify a handler as: + +- [Middleware](../structure/middleware.md) class name. +- Handler action (an array of [HandlerClass, handlerMethod]). +- A callable. + +In case of a handler action, a class of type `HandlerClass` is instantiated +and its `handlerMethod` is called: + +```php +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\ResponseInterface; + +final readonly class HandlerClass +{ + public function handle(ServerRequestInterface $request): ResponseInterface + { + // ... + } +} +``` + +The callable is called as is: + +```php +static function (ServerRequestInterface $request, RequestHandlerInterface $next) use ($responseFactory) { + $response = $responseFactory->createResponse(); + $response->getBody()->write('You are at homepage.'); + return $response; +} +``` + +For handler action and callable typed parameters are automatically injected +using the dependency injection container passed to the route. + +Get current request and handler by type-hinting for `ServerRequestInterface` +and `RequestHandlerInterface`. You could add extra handlers to wrap primary +one with `middleware()` method: + +```php +action([DownloadController::class, 'download']) + ->name('download/id') + ->middleware(LimitDownloadRate::class) +]; +``` + +Check ["the middleware"](../structure/middleware.md) guide to learn more +about how to implement middleware. + +This is especially useful when grouping routes: + +```php +middleware(ApiDataWrapper::class) + ->routes( + Route::get('/info/v2') + ->action(ApiInfo::class) + ->name('api/info/v2') + ->middleware(FormatDataResponseAsJson::class), + Route::get('/user') + ->action([ApiUserController::class, 'index']) + ->name('api/user/index'), + Route::get('/user/{login}') + ->action([ApiUserController::class, 'profile']) + ->middleware(FormatDataResponseAsJson::class) + ->name('api/user/profile'), + ) +]; +``` + +Router executes `ApiDataWrapper` before handling any URL starting with +`/api`. + +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. + +You can set a default value for a route parameter. For example: + + +```php +action([SiteController::class, 'user']) + ->name('site/user') + ->defaults(['id' => '42']) +]; +``` + +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`. + +In cause URL should be valid for a single host, you can specify it with +`host()`. + +## Routing + +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. + +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). + +## Generating URLs + +To generate URL based on a route, a route should have a name: + +```php +name('test/index'), + Route::post('/test/submit/{id}', [TestController::class, 'submit']) + ->name('test/submit') +]; +``` + + +The generation looks like the following: + +```php +generate('test/submit', ['id' => '42']); + // ... + } +} +``` + +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`. + +Then we use `generate()` method to get actual URL. It accepts a route name +and an array of named query parameters. The code will return +"/test/submit/42." If you need absolute URL, use `generateAbsolute()` +instead. + +## Route patterns + +Route patterns used depend on the underlying implementation used. The +default implementation is +[nikic/FastRoute](https://github.com/nikic/FastRoute). + +Basic patterns are static like `/test`. That means they must match exactly +in order for a route match. + +### Named Parameters + +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. + +> [!NOTE] +> You can only use regular expressions inside parameters. The rest of the pattern is considered plain text. + +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)}`. + +On a route match router fills the associated request attributes 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. + +Let's use some examples to illustrate how named parameters work. Assume +you've declared the following three patterns: + + +1. `'posts/{year:\d{4}}/{category}` +2. `'posts'` +3. `'post/{id:\d+}'` + +- `/posts` match the second pattern; +- `/posts/2014/php` match a first pattern. Parameters are the `year` whose + value is 2014 and the `category` whose value is `php`; +- `/post/100` match a third pattern. The `id` parameter value is 100; +- `/posts/php` doesn't match. + +When generating URLs, you should use the following parameters: + +```php +echo $url->generate('first', ['year' => '2020', 'category' => 'Virology']); +echo $url->generate('second'); +echo $url->generate('third', ['id' => '42']); +``` + +### Optional parts + +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: + +```php +use \Yiisoft\Router\Route; + +Route::get('/posts[/{id}]')->defaults(['id' => '1']); +``` + +Optional parts are only supported in a trailing position, not in the middle +of a route. diff --git a/src/it/guide/runtime/sessions.md b/src/it/guide/runtime/sessions.md new file mode 100644 index 00000000..e2df2a50 --- /dev/null +++ b/src/it/guide/runtime/sessions.md @@ -0,0 +1,161 @@ +# Sessions + +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. + +To add it to your application, use composer: + +```shell +composer require yiisoft/session +``` + +## Configuring middleware + +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. + +To add a session for a certain group of routes, edit `config/routes.php` +like the following: + +```php +middleware(SessionMiddleware::class) + ->routes( + // ... + ) +]; +``` + +To add a session to the whole application, edit `config/application.php` +like the following: + +```php +return [ + Yiisoft\Yii\Web\Application::class => [ + '__construct()' => [ + 'dispatcher' => DynamicReference::to(static function (Injector $injector) { + return ($injector->make(MiddlewareDispatcher::class)) + ->withMiddlewares( + [ + Router::class, + CsrfMiddleware::class, + SessionMiddleware::class, // <-- add this + ErrorCatcher::class, + ] + ); + }), + ], + ], +]; +``` + +## Opening and closing session + +```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] +> Closing session as early as possible is a good practice since many session implementations are blocking other +> requests while the session is open. + +There are two more ways to close a session: + +```php +public function actionProfile(\Yiisoft\Session\SessionInterface $session) +{ + // discard changes and close the session + $session->discard(); + + // destroy the session completely + $session->destroy(); +} +``` + +## Working with session data + +Usually you will use the following methods to work with session data: + +```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(); +} +``` + +## Flash messages + +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. + +`FlashInteface` usage is the following: + +```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 +} +``` + +## Custom session storage + +When using `Yiisoft\Session\Session`, you can use your own storage +implementation: + +```php +$handler = new MySessionHandler(); +$session = new \Yiisoft\Session\Session([], $handler); +``` + +Custom storage must implement `\SessionHandlerInterface`. diff --git a/src/it/guide/security/authentication.md b/src/it/guide/security/authentication.md new file mode 100644 index 00000000..4e530e88 --- /dev/null +++ b/src/it/guide/security/authentication.md @@ -0,0 +1,256 @@ +# Authentication + +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. + +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: + +* Configure the `Yiisoft\User\CurrentUser` service; +* Create a class implementing the `\Yiisoft\Auth\IdentityInterface` + interface; +* Create a class implementing the + `\Yiisoft\Auth\IdentityRepositoryInterface` interface; + +To use the `Yiisoft\User\CurrentUser` service, install +[yiisoft/user](https://github.com/yiisoft/user) package: + +```shell +composer require yiisoft/user +``` + +## Configuring `Yiisoft\User\CurrentUser` + +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. + +```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)] + ], +]; +``` + +## Implementing`\Yiisoft\Auth\IdentityInterface` + +The identity class must implement the `\Yiisoft\Auth\IdentityInterface` +which has a single method: + +* [[yii\web\IdentityInterface::getId()|getId()]]: it returns the ID of the + user represented by this identity instance. + +In the following example, an identity class is implemented as a pure PHP +object. + +```php +id; + } +} +``` + +## Implementing`\Yiisoft\Auth\IdentityRepositoryInterface` + +The identity repository class must implement the +`\Yiisoft\Auth\IdentityRepositoryInterface` which has the following methods: + +* `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. +* `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). + +A dummy implementation may look like the following: + +```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; + } +} +``` + +## Using `\Yiisoft\User\CurrentUser` + +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: + +```php +use \Psr\Http\Message\ServerRequestInterface; +use \Yiisoft\User\CurrentUser; + +final readonly class SiteController +{ + public function actionIndex(ServerRequestInterface $request, CurrentUser $user) + { + if ($user->isGuest()) { + // user is guest + } else { + $identity = $user->getIdentity(); + // do something based on identity + } + } +} +``` + +`isGuest()` determines if user is logged in or not. `getIdentity()` returns +an instance of identity. + +To log in a user, you may use the following code: + +```php +$identity = $identityRepository->findByEmail($email); + +/* @var $user \Yiisoft\User\CurrentUser */ +$user->login($identity); +``` + +The `login()` method sets the identity to the User service. It stores +identity into session so user authentication status is maintained. + +To log out a user, call + +```php +/* @var $user \Yiisoft\User\CurrentUser */ +$user->logout(); +``` + +## Protecting Routes + +The `Yiisoft\Auth\Middleware\Authentication` middleware can be used to +restrict access to a given route to authenticated users only. + +First, configure the `Yiisoft\Auth\AuthenticationMethodInterface`: + +```php +use Yiisoft\Auth\AuthenticationMethodInterface; +use Yiisoft\User\Method\WebAuth; + +return [ + // ... + AuthenticationMethodInterface::class => WebAuth::class, +]; +``` + +Then, apply the `Yiisoft\Auth\Middleware\Authentication` middleware to a +route: + +```php +use Yiisoft\Auth\Middleware\Authentication; + +Route::post('/create') + ->middleware(Authentication::class) + ->action([SiteController::class, 'create']) + ->name('site/create') +``` + + Or to a group of routes: + +```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') + ) +``` + +## Authentication Events + +The user service raises a few events during the login and logout processes. + + +* `\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. +* `\Yiisoft\User\Event\AfterLogin`: raised after a successful login. +* `\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. +* `\Yiisoft\User\Event\AfterLogout`: raised after a successful logout. + +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. diff --git a/src/it/guide/security/authorization.md b/src/it/guide/security/authorization.md new file mode 100644 index 00000000..5f3587c8 --- /dev/null +++ b/src/it/guide/security/authorization.md @@ -0,0 +1,607 @@ +# Authorization + +Authorization is the process of verifying that a user has enough permission +to do something. + +## Checking for permission + +You can check if a user has certain permissions by using +`\Yiisoft\User\CurrentUser` service: + +```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) { + // respond with 404 + } + + if (!$this->canCurrentUserUpdatePost($post)) { + // respond with 403 + } + + // continue with updating the post + } + + private function canCurrentUserUpdatePost(Post $post): bool + { + return $post->getAuthorId() === $this->user->getId() && + $this->user->can('updatePost'); + } +} +``` + +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. + +## Role-based access control (RBAC) + +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. + +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). + +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. + +To ease description next, there are some basic RBAC concepts first. + +### Basic concepts + +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. + +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. + +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. + +### Configuring RBAC + +Yii RBAC requires storage to be provided. + +One of the following storages could be installed: + +- [PHP storage](https://github.com/yiisoft/rbac-php) - PHP file storage; +- [DB storage](https://github.com/yiisoft/rbac-db) - database storage based + on [Yii DB](https://github.com/yiisoft/db); +- [Cycle DB storage](https://github.com/yiisoft/rbac-cycle-db) - database + storage based on [Cycle DBAL](https://github.com/cycle/database). + +You can also provide your own storage using the +[yiisoft/rbac](https://github.com/yiisoft/rbac) package. + +#### Configuring RBAC with the [PHP storage](https://github.com/yiisoft/rbac-php) + +Install [yiisoft/rbac-php](https://github.com/yiisoft/rbac-php) package: + +``` +composer require yiisoft/rbac-php +``` + +Before we set off to define authorization data and perform access checking, +you need to configure the `Yiisoft\Access\AccessCheckerInterface` in +dependency container: + +```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; + +return [ + // ... + ItemsStorageInterface::class => [ + 'class' => ItemsStorage::class, + '__construct()' => [ + 'filePath' => $params['rbacItemsStorageFilePath'] + ] + ], + AssignmentsStorageInterface::class => [ + 'class' => AssignmentsStorage::class, + '__construct()' => [ + 'filePath' => $params['rbacAssignmentsStorageFilePath'] + ] + ], + AccessCheckerInterface::class => ManagerInterface::class, +]; +``` + +`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. + +#### Configuring RBAC with the [DB storage](https://github.com/yiisoft/rbac-db) + +Install [yiisoft/rbac-db](https://github.com/yiisoft/rbac-db) package: + +``` +composer require yiisoft/rbac-db +``` + +Install one of the following drivers: + - [SQLite](https://github.com/yiisoft/db-sqlite) (minimal required version is 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 +connection](https://yiisoft.github.io/docs/guide/start/databases.html#configuring-connection). + +Before we set off to define authorization data and perform access checking, +you need to configure the `Yiisoft\Access\AccessCheckerInterface` in +dependency container: + +```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, +]; +``` + +Add the RBAC [DB storage](https://github.com/yiisoft/rbac-db) migration +paths to params.php: + +```php +return [ + // ... + 'yiisoft/db-migration' => [ + 'sourcePaths' => [ + __DIR__ . '/../../vendor/yiisoft/rbac-db/migrations/items', + __DIR__ . '/../../vendor/yiisoft/rbac-db/migrations/assignments', + ], + ], +]; +``` + +Apply migrations: + +``` +APP_ENV=dev ./yii migrate:up +``` + +### Building authorization data + +Building authorization data is all about the following tasks: + +- defining roles and permissions; +- establishing relations between roles and permissions; +- defining rules; +- associating rules with roles and permissions; +- assigning roles to users. + +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. + +Either way, in the end, you'll get the following RBAC hierarchy: + +![Simple RBAC hierarchy](/images/guide/security/rbac-hierarchy-1.svg "Simple +RBAC hierarchy") + +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. + +### Using console command + +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`: + +```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')); + + // add the "author" role and give this role the "createPost" permission + $this->manager->addRole(new Role(RbacCommand::ROLE_AUTHOR)); + $this->manager->addChild(RbacCommand::ROLE_AUTHOR, RbacCommand::CREATE_POST_PERMISSION); + + // add the "admin" role and give this role the "updatePost" permission + // as well as the permissions of the "author" role + $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); + + // Assign roles to users. 1 and 2 are IDs returned by IdentityInterface::getId() + // usually implemented in your User model. + $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); + } +} +``` + +Add the command to `config/console/commands.php`: + +```php +return [ + // ... + 'rbac:init' => App\Command\RbacCommand::class +]; +``` + +You can execute the command above from the console the following way: + +``` +APP_ENV=dev ./yii rbac:init +``` + +> If you don't want to hardcode what users have certain roles, don't put `->assign()` calls into the command. Instead, + create either UI or console command to manage assignments. + +#### Using migrations + +**TODO**: finish it when migrations are implemented. + +You can use [migrations](../databases/db-migrations.md) to initialize and +change hierarchy via APIs offered by `\Yiisoft\Rbac\ManagerInterface`. + +Create new migration using `APP_ENV=dev ./yii migrate:create init_rbac` then +implement creating a hierarchy: + +```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')); + + // add the "author" role and give this role the "createPost" permission + $this->manager->addRole(new Role(M260112125812InitRbac::ROLE_AUTHOR)); + $this->manager->addChild(M260112125812InitRbac::ROLE_AUTHOR, M260112125812InitRbac::CREATE_POST_PERMISSION); + + // add the "admin" role and give this role the "updatePost" permission + // as well as the permissions of the "author" role + $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); + + // Assign roles to users. 1 and 2 are IDs returned by IdentityInterface::getId() + // usually implemented in your User model. + $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); + } +} +``` + +> If you don't want to hardcode which users have certain roles, don't put `->assign()` calls in migrations. Instead, + create either UI or console command to manage assignments. + +You could apply migration by using `APP_ENV=dev ./yii migrate:up`. + +## Assigning roles to users + +TODO: update when signup implemented in demo / template. + +The author can create a post, admin can update the post and do everything +the author can. + +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: + +```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); + + // the following three lines were added: + $authorRole = $this->manager->getRole('author'); + if ($authorRole !== null) { + $this->manager->assign($authorRole->getName(), $user->getId()); + } + + return $user; + } + + return null; +} +``` + +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`. + + +### Using rules + +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: + +```php +namespace App\User\Rbac; + +use Yiisoft\Rbac\Item; +use \Yiisoft\Rbac\Rule; + +/** + * Checks if the authorID matches user passed via params. + */ +final readonly class AuthorRule extends Rule +{ + private const NAME = 'isAuthor'; + + public function __construct() { + parent::__construct(self::NAME); + } + + public function execute(string $userId, Item $item, array $parameters = []): bool + { + return isset($params['post']) ? $params['post']->getAuthorId() == $userId : false; + } +} +``` + +The rule checks if user created the `post`. Create a special permission +`updateOwnPost` in the command you've used before: + +```php +/** @var \Yiisoft\Rbac\ManagerInterface $auth */ + +// add the rule +$rule = new AuthorRule(); +$auth->add($rule); + +// add the "updateOwnPost" permission and associate the rule with it. +$updateOwnPost = (new \Yiisoft\Rbac\Permission('updateOwnPost')) + ->withDescription('Update own post') + ->withRuleName($rule->getName()); +$auth->add($updateOwnPost); + +// "updateOwnPost" will be used from "updatePost" +$auth->addChild($updateOwnPost, $updatePost); + +// allow "author" to update their own posts +$auth->addChild($author, $updateOwnPost); +``` + +Now you've got the following hierarchy: + +![RBAC hierarchy with a rule](/images/guide/security/rbac-hierarchy-2.svg +"RBAC hierarchy with a rule") + + +### Access check + +The check is done similarly to how it was done in the first section of this +guide: + +```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) { + // respond with 404 + } + + if (!$this->canCurrentUserUpdatePost($post)) { + // respond with 403 + } + + // continue with updating the post + } + + private function canCurrentUserUpdatePost(Post $post): bool + { + return $this->user->can('updatePost', ['post' => $post]); + } +} +``` + +The difference is that now checking for a user's own post is part of the +RBAC. + +If the current user is Jane with `ID=1` you are starting at `createPost` and +trying to get to `Jane`: + +![Access check](/images/guide/security/rbac-access-check-1.svg "Access +check") + +To check if a user can update a post, you need to pass an extra parameter +that's required by `AuthorRule` described before: + +```php +if ($user->can('updatePost', ['post' => $post])) { + // update post +} +``` + +Here is what happens if the current user is John: + + +![Access check](/images/guide/security/rbac-access-check-2.svg "Access +check") + +You're starting with the `updatePost` and going through `updateOwnPost`. To pass the access check, `AuthorRule` +should return `true` from its `execute()` method. The method receives its `$params` from the `can()` method call, so the value is +`['post' => $post]`. +If everything is fine, you will get to `author` assigned to John. + +In the case of Jane, it's a bit simpler since she is an admin: + +![Access check](/images/guide/security/rbac-access-check-3.svg "Access +check") + +## Implementing your own access checker + +If RBAC doesn't suit your needs, you can implement your own access checker +without changing the application code: + + +```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/it/guide/security/best-practices.md b/src/it/guide/security/best-practices.md new file mode 100644 index 00000000..8d232123 --- /dev/null +++ b/src/it/guide/security/best-practices.md @@ -0,0 +1,277 @@ +# Security best practices + +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. + + +## Basic principles + +There are two main principles when it comes to security no matter which +application is being developed: + +1. Filter input. +2. Escape output. + + +### Filter input + +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: + +```php +$sortBy = $_GET['sort']; +if (!in_array($sortBy, ['title', 'created_at', 'status'])) { + throw new \InvalidArgumentException('Invalid sort value.'); +} +``` + +In Yii, most probably you'll use form validation to do similar checks. + +Further reading on the topic: + +- +- + + +### Escape output + +Escape output means that, depending on the context where you're using data, +you should prepend it with special characters to negate its special meaning. +In context of HTML you should escape `<`, `>` and alike special characters. +In the context of JavaScript or SQL, it will be a different set of characters. +Since it's error-prone to escape manually, Yii provides various tools to perform escaping in different contexts. + +Further reading on the topic: + +- +- +- + + +## Avoiding SQL injections + +SQL injection happens when you form a query text by concatenating unescaped +strings such as the following: + +```php +$username = $_GET['username']; +$sql = "SELECT * FROM user WHERE username = '$username'"; +``` + +Instead of supplying correct username attacker could give your applications +something like `'; DROP TABLE user; --`. The Resulting SQL will be the +following: + +```sql +SELECT * FROM user WHERE username = ''; DROP TABLE user; --' +``` + +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?). + +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. + +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: + +```php +function actionList($orderBy = null) +{ + if (!in_array($orderBy, ['name', 'status'])) { + throw new \InvalidArgumentException('Only name and status are allowed to order by.'); + } + + // ... +} +``` + +Further reading on the topic: + +- + + +## Avoiding XSS + +XSS or cross-site scripting happens when output isn't escaped properly when outputting HTML to the browser. For example, +if user can enter his name and instead of `Alexander` he enters ``, every page that +outputs username without escaping it will execute JavaScript `alert('Hello!');` resulting in alert box popping up +in a browser. Depending on the website instead of innocent alert, such a script could send messages using your name or even +perform bank transactions. + +Avoiding XSS is quite easy in Yii. There are two cases: + +1. You want to output data as plain text. +2. You want to output data as HTML. + +If all you need is plain text, then escaping is as easy as the following: + + +```php + +``` + +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. + +Further reading on the topic: + +- + + +## Avoiding CSRF + +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. + +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 +as it's requested by the user themselves everything is OK, but one day bad guys are somehow posting +`` on a forum the user often visits. The browser doesn't make any difference between +requesting an image or requesting a page so when the user opens a page with such a manipulated `` tag, +the browser will send the GET request to that URL and the user will be logged out from `an.example.com`. + +That's the basic idea of how a CSRF attack works. One can say that logging out a user isn't a serious thing. +However, this was just an example. +There are many more things one could do using this approach. +For example, triggering payments or changing data. Imagine that some website has a URL +`http://an.example.com/purse/transfer?to=anotherUser&amount=2000`. Accessing it using GET request, causes transfer of $2000 +from an authorized user account to user `anotherUser`. +You know that the browser will always send a GET request to load an image, +so you can change the code to accept only POST requests on that URL. +Unfortunately, this won't save you, because an attacker +can put some JavaScript code instead of `` tag, which allows sending POST requests to that URL as well. + +For this reason, Yii applies extra mechanisms to protect against CSRF +attacks. + +To avoid CSRF, you should always: + +1. Follow HTTP specification. GET shouldn't change the application state. + See [RFC2616](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html) for + more details. +2. Keep Yii CSRF protection enabled. + +Yii has CSRF protection as `Yiisoft\Yii\Web\Middleware\Csrf` middleware. +Make sure it's in your application middleware stack. + +Further reading on the topic: + +- +- + + +## Avoiding file exposure + +By default, server webroot is meant to be pointed to `public` directory where `index.php` is. In the case of shared hosting + environments, it could be impossible to achieve, so you'll end up with all the code, configs and logs in server webroot. + +If so, remember to deny access to everything except `web`. If it's +impossible, consider hosting your application elsewhere. + + +## Avoiding debug info and tools in production + +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. + +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. + +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. + +Further reading on the topic: + +- +- + + +## Using secure connection over TLS + +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)). + +Nowadays, anyone can get a certificate for free and automatically update it +thanks to [Let's Encrypt](https://letsencrypt.org/). + +## Secure server configuration + +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. + +### Avoiding `Host`-header attacks + +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. + +For more information about the server configuration, please refer to the +documentation of your webserver: + +- Apache 2: + +- Nginx: + + +### Configuring SSL peer validation + +There is a typical misconception about how to solve SSL certificate +validation issues such as: + +``` +cURL error 60: SSL certificate problem: unable to get local issuer certificate +``` + +or + +``` +stream_socket_enable_crypto(): SSL operation failed with code 1. OpenSSL Error messages: error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed +``` + +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: + +1. Download + [https://curl.haxx.se/ca/cacert.pem](https://curl.haxx.se/ca/cacert.pem). +2. Add the following to your php.ini: + ``` + openssl.cafile="/path/to/cacert.pem" + curl.cainfo="/path/to/cacert.pem". + ``` + +Note that you should keep the file up to date. + +## References + +- [OWASP top 10](https://owasp.org/Top10/) +- [The Basics of Web Application + Security](https://martinfowler.com/articles/web-security-basics.html) by + Martin Fowler +- [PHP manual: security](https://www.php.net/manual/en/security.php) +- [Information security at + STackExchange](https://security.stackexchange.com/) + diff --git a/src/it/guide/security/cryptography.md b/src/it/guide/security/cryptography.md new file mode 100644 index 00000000..4b596bab --- /dev/null +++ b/src/it/guide/security/cryptography.md @@ -0,0 +1,123 @@ +# Cryptography + +In this section, we'll review the following security aspects: + +- Generating random data +- Encryption and Decryption +- Confirming Data Integrity + +To use these features, you need to install `yiisoft/security` package: + +``` +composer install yiisoft/security +``` + +## Generating pseudorandom data + +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. + +`\Yiisoft\Security\Random` makes generating pseudorandom data simple: + +```php +$key = \Yiisoft\Security\Random::string(42); +``` + +The code above would give you a random string consisting of 42 characters. + +If you need bytes or integers, use PHP functions directly: + +- `random_bytes()` for bytes. Note that the output may not be ASCII. +- `random_int()` for integers. + +## Encryption and decryption + +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): + +```php +$encryptedData = (new \Yiisoft\Security\Crypt())->encryptByPassword($data, $password); + +// save data to a database or another storage +saveData($encryptedData); +``` + +Decrypting it: + +```php +// collect encrypted data from a database or another storage +$encryptedData = getEncryptedData(); + +$data = (new \Yiisoft\Security\Crypt())->decryptByPassword($encryptedData, $password); +``` + +You could use a key instead of a password: + +```php +$encryptedData = (new \Yiisoft\Security\Crypt())->encryptByKey($data, $key); + +// save data to a database or another storage +saveData($encryptedData); +``` + +Decrypting it: + +```php +// collect encrypted data from a database or another storage +$encryptedData = getEncryptedData(); + +$data = (new \Yiisoft\Security\Crypt())->decryptByKey($encryptedData, $key); +``` + +## Confirming data integrity + +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. + +The `$key` should be present at both sending and receiving sides. On the +sending side: + +```php +$signedMessage = (new \Yiisoft\Security\Mac())->sign($message, $key); + +sendMessage($signedMessage); +``` + +On the receiving side: + +```php +$signedMessage = receiveMessage($signedMessage); + +try { + $message = (new \Yiisoft\Security\Mac())->getMessage($signedMessage, $key); +} catch (\Yiisoft\Security\DataIsTamperedException $e) { + // data is tampered +} +``` + +## Masking token length + +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. + +To mask a token: + +```php +$maskedToken = \Yiisoft\Security\TokenMask::apply($token); +``` + +To get the original value from the masked one: + +```php +$token = \Yiisoft\Security\TokenMask::remove($maskedToken); +``` diff --git a/src/it/guide/security/overview.md b/src/it/guide/security/overview.md new file mode 100644 index 00000000..ca33f4c4 --- /dev/null +++ b/src/it/guide/security/overview.md @@ -0,0 +1,19 @@ +# Sicurezza + +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. + +* [Authentication](authentication.md) +* [Authorization](authorization.md) +* [Working with Passwords](passwords.md) +* [Cryptography](cryptography.md) +* [Best Practices](best-practices.md) +* [Trusted request](trusted-request.md) + +See also: + +* [Views security](../views/view.md#security) diff --git a/src/it/guide/security/passwords.md b/src/it/guide/security/passwords.md new file mode 100644 index 00000000..2e112d77 --- /dev/null +++ b/src/it/guide/security/passwords.md @@ -0,0 +1,45 @@ +# Working with passwords + +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. + +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. + +To use it, you need to require the package first: + +``` +composer require yiisoft/security +``` + +When a user provides a password for the first time (e.g., upon +registration), the password needs to be hashed and stored: + + +```php +$hash = (new PasswordHasher())->hash($password); + +// save hash to a database or another storage +saveHash($hash); +``` + +When a user attempts to log in, the submitted password must be verified +against the previously hashed and stored password: + + +```php +// get hash from a database or another storage +$hash = getHash(); + +if ((new PasswordHasher())->validate($password, $hash)) { + // all good, logging in user +} else { + // wrong password +} +``` diff --git a/src/it/guide/security/trusted-request.md b/src/it/guide/security/trusted-request.md new file mode 100644 index 00000000..29ff339a --- /dev/null +++ b/src/it/guide/security/trusted-request.md @@ -0,0 +1,43 @@ +# Trusted request + +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. + +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). + +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: + +```php +/** @var \Yiisoft\Yii\Web\Middleware\TrustedHostsNetworkResolver $trustedHostsNetworkResolver */ +$trustedHostsNetworkResolver = $trustedHostsNetworkResolver->withAddedTrustedHosts(['1.0.2.0/24']); +``` + +The proxy sends the IP in the `X-Forwarded-For` header by default, and the +protocol (`http` or `https`) is in `X-Forwarded-Proto`. + +In case your proxies are using different headers, you can use the request +configuration to adjust these, e.g.: + +```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'] + ); +``` + +With the above configuration, `X-ProxyUser-Ip` and `Front-End-Https` headers +are used to get user IP and protocol. diff --git a/src/it/guide/start/creating-project.md b/src/it/guide/start/creating-project.md new file mode 100644 index 00000000..eaf2bc33 --- /dev/null +++ b/src/it/guide/start/creating-project.md @@ -0,0 +1,65 @@ +# Creazione di un progetto + +In questa guida forniremo comandi sia per +[Docker](https://docs.docker.com/get-started/get-docker/) che per il server +di sviluppo integrato con tutto installato localmente. + +> [!NOTE] +> Se si desidera utilizzare un altro server web, +> consultare ["Configurazione dei server Web"](../../cookbook/configuring-webservers/general.md). + +Si consiglia di iniziare con un template di progetto che sia un progetto Yii +minimale funzionante che implementa alcune funzionalità di base. Può fungere +da buon punto di partenza per i propri progetti. + +È possibile creare un nuovo progetto da un template utilizzando il gestore +di pacchetti [Composer](https://getcomposer.org): + +```sh +composer create-project yiisoft/app your_project +``` + +Gli utenti Docker possono eseguire i seguenti comandi: + +```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 +``` + +Se vuoi la versione di sviluppo invece di quella di rilascio: + +```sh +git clone https://github.com/yiisoft/app.git --depth 1 your_project && \ +cd your_project && \ +rm -rf .git && \ +make composer update +``` + +Questo installa l'ultima versione stabile del template di progetto Yii in +una directory denominata `your_project`. È possibile scegliere un nome di +directory diverso se lo si desidera. + +> [!TIP] +> Se si desidera installare l'ultima versione di sviluppo di Yii, è possibile aggiungere `--stability=dev` al comando. +> Non utilizzare la versione di sviluppo di Yii in produzione perché potrebbe compromettere il codice in esecuzione. + +Accedere alla directory appena creata ed eseguire: + +```sh +APP_ENV=dev ./yii serve --port=80 +``` + +Per gli utenti Docker, eseguire: + +```sh +make up +``` + +Aprire il browser all'URL `http://localhost/`. + +> [!NOTE] +> Il server HTTP è in ascolto sulla porta 80. Se quella porta è già in uso, specificare la porta tramite `--port` o, nel caso di Docker, +> `DEV_PORT` nel file `docker/.env`. + +![Installazione riuscita di Yii](/images/guide/start/app-installed.png) diff --git a/src/it/guide/start/databases.md b/src/it/guide/start/databases.md new file mode 100644 index 00000000..e0491b99 --- /dev/null +++ b/src/it/guide/start/databases.md @@ -0,0 +1,758 @@ +# Lavorare con i database + +Yii doesn't dictate using a particular database or storage for your +application. There are many ways you can work with relational databases: + +- [Yii DB](https://github.com/yiisoft/db) +- [Yii Active Record](https://github.com/yiisoft/active-record) +- [Cycle](https://github.com/cycle) via [Yii Cycle + package](https://github.com/yiisoft/yii-cycle) +- [Doctrine](https://www.doctrine-project.org/) via [Yii Doctrine + package](https://github.com/stargazer-team/yii-doctrine) +- [PDO](https://www.php.net/manual/en/book.pdo.php) + +For non-relational ones, there are usually official libraries available: + +- [ElasticSearch](https://github.com/elastic/elasticsearch-php) +- [Redis](https://redis.io/docs/latest/develop/clients/php/) +- ... + +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). + +## Installing PostgreSQL + +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. + +If you use Docker, it is a bit simpler. Modify `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:-15}-alpine + environment: + POSTGRES_DB: app + POSTGRES_PASSWORD: password + POSTGRES_USER: user + volumes: + - ../runtime/db:/var/lib/postgresql/data:rw + ports: + - "${DEV_DB_PORT:-5432}:5432" + healthcheck: + test: [ "CMD-SHELL", "pg_isready -U user -d app" ] + interval: 5s + timeout: 5s + retries: 5 + +volumes: + db: +``` + +Note that we add `depends_on` so application waits for database to be up. + +Also, we'll need a `pdo_pgsql` extension to communicate with PostgreSQL. You +can enable it locally in `php.ini`. If you use Docker, check +`docker/Dockerfile` and add `pdo_pgsql` in `install-php-extensions` +list. Then rebuild PHP image with `make build && make down && make up`. + +## Configuring connection + +Now that we have the database, it's time to define the connection. + +First we need a package to be installed: + +```sh +make composer require yiisoft/db-pgsql +``` + +Now create `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'], + ), + ], + ], +]; +``` + +And define parameters in `config/common/params.php`. For Docker that would +be: + +```php +use Yiisoft\Db\Pgsql\Dsn; + +return [ + // ... + 'yiisoft/db-pgsql' => [ + 'dsn' => new Dsn('pgsql', 'db', 'app', '5432'), + 'username' => 'user', + 'password' => 'password', + ], +]; +``` + +`db` host is resolved automatically within the Docker network. + +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. + +## Creating and applying migrations + +For the initial state of the application and for further database changes, +it is a good idea to use migrations. These are files that create database +changes. Applied migrations are tracked in the database, allowing us to know +the current state and which migrations remain to be applied. + +To use migrations we need another package installed: + +```sh +make composer require yiisoft/db-migration +``` + +Create a directory to store migrations `src/Migration` right in the project +root. Add the following configuration to `config/common/params.php`: + +```php +'yiisoft/db-migration' => [ + 'newMigrationNamespace' => 'App\\Migration', + 'sourceNamespaces' => ['App\\Migration'], +], +``` + +Now you can use `make yii migrate:create page` to create a new +migration. For our example we need a `page` table with some columns: + +```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'); + } +} +``` + +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. + +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. + +```shell +make composer require ramsey/uuid +``` + +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". + +Apply the migration with `make yii migrate:up`. + +## An entity + +Now that you have a table it is time to define an entity in the code. Create +`src/Web/Page/Page.php`: + +```php +toSlug($this->title); + } +} +``` + +## Repository + +Now that we have entity, we need a place for methods to save an entity, +delete it and select either a single page or multiple pages. + +Create `src/Web/Page/PageRepository.php`: + +```php + $page->id, + 'title' => $page->title, + 'slug' => $page->getSlug(), + 'text' => $page->text, + 'created_at' => $page->createdAt, + 'updated_at' => $page->updatedAt, + ]; + + if ($this->exists($page->id)) { + $this->connection->createCommand()->update('{{%page}}', $data, ['id' => $page->id])->execute(); + } else { + $this->connection->createCommand()->insert('{{%page}}', $data)->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 + { + $data = $this->connection + ->select() + ->from('{{%page}}') + ->all(); + + foreach ($data as $page) { + yield $this->createPage($page); + } + } + + private function createPage(?array $data): ?Page + { + if ($data === null) { + return null; + } + + return Page::create( + id: $data['id'], + title: $data['title'], + text: $data['text'], + createdAt: new DateTimeImmutable($data['created_at']), + updatedAt: new DateTimeImmutable($data['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(); + } +} +``` + +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. + +## Actions and routes + +We need some actions to: + +1. List all pages. +2. View a page. +3. Delete a page. +4. Create a page. +5. Update a page. + +Then we need routing for all these. + +Let's tackle these one by one. + +### List all pages + +Create `src/Web/Page/ListAction.php`: + +```php +viewRenderer->render(__DIR__ . '/list', [ + 'pages' => $this->pageRepository->findAll(), + ]); + } +} +``` + +Define list view in `src/Web/Page/list.php`: + +```php + $pages */ +/** @var UrlGeneratorInterface $urlGenerator */ +?> + +
    + +
  • + title, $urlGenerator->generate('page/view', ['slug' => $page->getSlug()])) ?> +
  • + +
+ +generate('page/edit', ['slug' => 'new'])) ?> +``` + +### View a page + +Create `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, + ]); + } +} +``` + +Now, a template in `src/Web/Page/view.php`: + +```php + + +

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

+ +

+ text) ?> +

+ +generate('page/edit', ['slug' => $page->getSlug()])) ?> | + + +post($urlGenerator->generate('page/delete', ['slug' => $page->getSlug()])) + ->csrf($csrf); +?> +open() ?> + +close() ?> +``` + +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". + +### Delete a page + +Create `src/Web/Page/DeleteAction.php`: + +```php +pageRepository->deleteBySlug($slug); + + return $this->responseFactory + ->createResponse(Status::SEE_OTHER) + ->withHeader('Location', $this->urlGenerator->generate('page/list')); + } +} +``` + +### Create or update a page + +First of all, we need a form at `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, + updatedAt: new DateTimeImmutable(), + ); + + $pageRepository->save($page); + + return $this->responseFactory + ->createResponse(Status::SEE_OTHER) + ->withHeader( + 'Location', + $this->urlGenerator->generate('page/view', ['slug' => $page->getSlug()]), + ); + } + + return $this->viewRenderer->render(__DIR__ . '/edit', [ + 'form' => $form, + 'isNew' => $isNew, + 'slug' => $slug, + ]); + } +} +``` + +Note that `Uuid::uuid7()->toString()` won't work for MySQL and you'll need bytes instead, `Uuid::uuid7()->getBytes()`. + +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. + +Now, a template in `src/Web/Page/edit.php`: + +```php +post($urlGenerator->generate('page/edit', ['slug' => $slug])) + ->csrf($csrf); +?> + +open() ?> + required() ?> + required() ?> + +close() ?> +``` + +### Routing + +Adjust `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'), + ), + ), +]; +``` + +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. + +## Trying it out + +Now try it out by opening `http://localhost/pages` in your browser. + diff --git a/src/it/guide/start/forms.md b/src/it/guide/start/forms.md new file mode 100644 index 00000000..e0fbc001 --- /dev/null +++ b/src/it/guide/start/forms.md @@ -0,0 +1,219 @@ +# Working with forms + +This section continues to improve on "Saying Hello." Instead of using URL, +you will now ask a user for a message via form. + +Through this tutorial, you will learn how to: + +* Create a form model to represent the data entered by a user through a + form. +* Declare rules to validate the data entered. +* Build an HTML form in a view. + +## Installing form package + +To install form package, issue the following command in your application +directory: + +``` +composer require yiisoft/form-model +``` + +For Docker that would be: + +``` +make composer require yiisoft/form-model +``` + +## Creating a form + +The data to be requested from the user will be represented by a `Form` class +as shown below and saved in the file `/src/App/Web/Echo/Form.php`: + +```php + + +Now that you have a form, use it in your action from "[Saying +Hello](hello.md)". + +Here's what you end up with in `/src/Web/Echo/Action.php`: + +```php +formHydrator->populateFromPostAndValidate($form, $request); + + return $this->viewRenderer->render(__DIR__ . '/template', [ + 'form' => $form, + ]); + } +} +``` + +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. + +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`: + +```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'), + ), +]; +``` + +## Adjusting view + +To render a form, you need to change your view, `src/Web/Echo/template.php`: + +```php +post($urlGenerator->generate('echo/say')) + ->csrf($csrf); +?> + +open() ?> + required() ?> + +close() ?> + +isValid()): ?> + Echo said: message) ?> + +``` + +If the form is valid, you display a message. The rest initializes and +renders the form. + +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`: + +```php +'yiisoft/yii-view-renderer' => [ + 'injections' => [ + Reference::to(CsrfViewInjection::class), + ], +], +``` + +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). + +You use `Field::text()` to output "message" field, so it takes care about +filling the value, escaping it, rendering field label and validation errors. + +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." + +## Trying it Out + +To see how it works, use your browser to access the following URL: + +``` +http://localhost:8080/say +``` + +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. + +![Form with a validation error](/images/guide/start/form-error.png) + +After you enter a valid message and click the "submit" button, the page +echoes the data that you entered. + +![Form with a success message](/images/guide/start/form-success.png) + +## Riepilogo + +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. + +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. + +In the next section, you will learn how to work with databases, which are +needed in nearly every application. diff --git a/src/it/guide/start/gii.md b/src/it/guide/start/gii.md new file mode 100644 index 00000000..5c34c4c6 --- /dev/null +++ b/src/it/guide/start/gii.md @@ -0,0 +1 @@ +# Generating code with Gii diff --git a/src/it/guide/start/hello.md b/src/it/guide/start/hello.md new file mode 100644 index 00000000..b280c824 --- /dev/null +++ b/src/it/guide/start/hello.md @@ -0,0 +1,195 @@ +# Dire ciao + +Questa sezione descrive come creare una nuova pagina “Hello” nella tua +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 +risposta. Poi lo migliorerai per usare [una vista](../views/view.md) per +costruire la risposta. + +Attraverso questo tutorial, imparerai tre cose: + +1. Come creare un gestore di richieste per rispondere a una richiesta. +2. Come mappare l'URL al gestore di richieste. +3. Come usare [una vista](../views/view.md) per comporre il contenuto della + risposta. + +## Creare un gestore di richieste + +Per il compito "Hello", creerai una classe gestore di richieste che legge un +parametro `message` dalla richiesta e visualizza quel messaggio +all'utente. Se la richiesta non fornisce un parametro `message`, l'azione +visualizzerà il messaggio "Hello" predefinito. + +Crea `src/Web/Echo/Action.php`: + +```php +responseFactory->createResponse(); + $response->getBody()->write('The message is: ' . Html::encode($message)); + return $response; + } +} +``` + +Nel tuo esempio, il metodo `__invoke` riceve il parametro `$message` che con +l'aiuto dell'attributo `RouteArgument` ottiene il messaggio dall'URL. Il +valore predefinito è `"Hello!"`. Se la richiesta viene effettuata a +`/say/Goodbye`, l'azione assegna il valore "Goodbye" alla variabile +`$message`. + +L'applicazione passa la risposta attraverso lo [stack di +middleware](../structure/middleware.md) all'emettitore che invia la risposta +all'utente finale. + +## Configurazione del router + +Ora, per mappare il tuo gestore di richieste all'URL, devi aggiungere una +rotta in `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'), + ), +]; +``` + +Nell'esempio sopra, mappi il pattern `/say[/{message}]` a +`\App\Web\Echo\Action`. Per una richiesta, il router crea un'istanza e +chiama il metodo `__invoke()`. La parte `{message}` del pattern scrive tutto +ciò che viene specificato in questa posizione nell'attributo `message` della +richiesta. `[]` marca questa parte del pattern come facoltativa. + +Dai anche un nome `echo/say` a questa rotta per poter generare URL che +puntano ad essa. + +## Provarlo + +Dopo aver creato l'azione e la vista apri `http://localhost/say/Hello+World` +nel tuo browser. + +Questo URL visualizza una pagina con “The message is: Hello World". + +Se ometti il parametro `message` nell'URL, la pagina visualizza “The message +is: Hello!". + +## Creare un modello di vista + +Solitamente, il compito è più complicato che stampare "hello world" e +comporta il rendering di HTML complesso. Per questo compito, è utile usare +modelli di vista. Sono script che scrivi per generare il corpo della +risposta. + +Per il compito "Hello", crea un modello `src/Web/Echo/template.php` che +stampa il parametro `message` ricevuto dal metodo dell'azione: + +```php + + +

The message is:

+``` + +Nel codice sopra, il parametro `message` utilizza la codifica HTML prima di +stamparlo. Questo è necessario perché il parametro proviene da un utente +finale ed è vulnerabile ad [attacchi cross-site scripting +(XSS)](https://en.wikipedia.org/wiki/Cross-site_scripting) tramite +l'incorporamento di JavaScript malevolo nel parametro. + +Naturalmente, puoi inserire più contenuto nella vista `say`. Il contenuto +può consistere di tag HTML, testo semplice e persino istruzioni +PHP. Infatti, il servizio di vista esegue la vista `say` come uno script +PHP. + +Per usare la vista, devi modificare `src/Web/Echo/Action.php`: + +```php +viewRenderer->render(__DIR__ . '/template', [ + 'message' => $message, + ]); + } +} +``` + +Ora apri il tuo browser e controllalo di nuovo. Dovresti vedere il testo +simile ma con un layout applicato. + +Inoltre, hai separato la parte su come funziona e la parte su come viene +presentata. Nelle applicazioni più grandi, questo aiuta molto a gestire la +complessità. + +## Riepilogo + +In questa sezione, hai toccato le parti del gestore di richieste e del +modello della tipica applicazione web. Hai creato un gestore di richieste +come parte di una classe per gestire una richiesta specifica. Hai anche +creato una vista per comporre il contenuto della risposta. In questo +semplice esempio, non è stata coinvolta alcuna fonte di dati poiché l'unico +dato utilizzato era il parametro `message`. + +Hai anche imparato sul routing in Yii, che funge da ponte tra le richieste +utente e i gestori di richieste. + +Nella prossima sezione, imparerai come recuperare dati e aggiungere una +nuova pagina contenente un modulo HTML. diff --git a/src/it/guide/start/looking-ahead.md b/src/it/guide/start/looking-ahead.md new file mode 100644 index 00000000..47d7d2fe --- /dev/null +++ b/src/it/guide/start/looking-ahead.md @@ -0,0 +1,9 @@ +# Looking ahead + +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. diff --git a/src/it/guide/start/prerequisites.md b/src/it/guide/start/prerequisites.md new file mode 100644 index 00000000..26731a06 --- /dev/null +++ b/src/it/guide/start/prerequisites.md @@ -0,0 +1,49 @@ +# Cosa devi sapere? + +La curva di apprendimento di Yii non è così ripida come quella di altri +framework PHP, ma ci sono comunque alcune cose che dovresti imparare prima +di iniziare a usare Yii. + +## PHP + +Yii è un framework PHP, quindi assicurarsi di [leggere e comprendere il +riferimento del linguaggio](https://www.php.net/manual/en/langref.php). + +## Programmazione orientata agli oggetti + +È necessaria una conoscenza di base della programmazione orientata agli +oggetti. Se non si ha familiarità con questo argomento, consultare uno dei +numerosi tutorial disponibili, [come quello offerto da +tuts+](https://code.tutsplus.com/tutorials/object-oriented-php-for-beginners--net-12762). + +Quando si sviluppa con Yii, si scrive codice in modo orientato agli oggetti, +quindi assicurarsi di avere familiarità con il [supporto OOP di +PHP](https://www.php.net/manual/en/language.oop5.php). + +Si noti che più l'applicazione è complessa, più concetti OOP avanzati si +dovrebbero apprendere per gestire con successo tale complessità. + +## Riga di comando e Composer + +Yii utilizza ampiamente il gestore di pacchetti PHP standard de facto, +[Composer](https://getcomposer.org), quindi assicurarsi di leggere e +comprendere la sua +[guida](https://getcomposer.org/doc/01-basic-usage.md). Se non si ha +familiarità con l'uso della riga di comando, è il momento di iniziare a +provarla. Una volta appresi i concetti di base, non si vorrà più farne a +meno. + +## HTTP + +Poiché Yii è un framework web e il web utilizza principalmente HTTP, è +consigliabile [saperne di +più](https://developer.mozilla.org/en-US/docs/Web/HTTP). + +## Docker + +Il modello di applicazione predefinito sfrutta Docker, pertanto ti +consigliamo di [leggere e comprendere i +concetti](https://docs.docker.com/get-started/). + +Inoltre, sarà utile familiarizzare con i principi della [twelve-factor +app](https://12factor.net/). diff --git a/src/it/guide/start/workflow.md b/src/it/guide/start/workflow.md new file mode 100644 index 00000000..8d8c2643 --- /dev/null +++ b/src/it/guide/start/workflow.md @@ -0,0 +1,122 @@ +# Running applications + +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. + +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. + +## Functionality + +The installed application contains only one page, accessible at +`http://localhost/`. It shares a common layout that you can reuse on +further pages. + + + +In addition to the web application, you can access a console script via +`APP_ENV=dev ./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. + + +## Application structure + +The most important directories and files in your application are (assuming +the application's root directory is `app`): + +``` +assets/ Asset bundle source files. +config/ Configuration files. + common/ Common configuration and DI definitions. + console/ Console-specific configuration. + environments/ Environment-specific configuration (dev/test/prod). + web/ Web-specific configuration. +docker/ Docker-specific files. +public/ Files publically accessible from the Internet. + assets/ Published/compiled assets. + index.php Entry script. +runtime/ Files generated during runtime. +src/ Application source code. + Console/ Console commands. + Shared/ Code shared between web and console applications. + Web/ Web-specific code (actions, handlers, layout). + Shared/ Shared web components. + Layout/ Layout components and templates. + Environment.php Environment configuration class. +tests/ A set of Codeception tests for the application. + Console/ Console command tests. + Functional/ Functional tests. + Unit/ Unit tests. + Web/ Web actions tests. +vendor/ Installed Composer packages. +Makefile Config for make command. +yii Console application entry point. +``` + +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. + +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. + +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. + +You can learn more about the application template from the [yiisoft/app +package +documentation](https://github.com/yiisoft/app/blob/master/README.md). + +## Request Lifecycle + +The following diagram shows how an application handles a request. + +```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. A user makes a request to the [entry + script](../structure/entry-script.md) `public/index.php`. +2. 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. +3. Request factory creates a request object based on a raw request that came + from a user. +4. Application passes a request object through a middleware array + configured. One of these is typically a router. +5. The Router finds out what handler to execute based on request and + configuration. +6. The handler may load some data, possibly from a database. +7. The handler forms a response by using data. Either directly or with the + help of the view package. +8. Emitter receives the response and takes care of sending the response to + the user's browser. diff --git a/src/it/guide/structure/action.md b/src/it/guide/structure/action.md new file mode 100644 index 00000000..0324e062 --- /dev/null +++ b/src/it/guide/structure/action.md @@ -0,0 +1,118 @@ +# Azioni + +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. + +There are multiple ways to describe an action. The simplest one is using a +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; +}); +``` + +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: + +```php +use Yiisoft\Router\Route; + +Route::get('/')->action(FrontPageAction::class), +``` + +The class itself would be like: + +```php +use \Psr\Http\Message\ServerRequestInterface; +use \Psr\Http\Message\ResponseInterface; + +final readonly class FrontPageAction +{ + public function __invoke(ServerRequestInterface $request): ResponseInterface + { + // build response for a front page + } +} +``` + +For many cases, it makes sense to group handling for many routes into a +single class: + + +```php +use Yiisoft\Router\Route; + +Route::get('/post/index')->action([PostController::class, 'actionIndex']), +Route::get('/post/view/{id:\d+}')->action([PostController::class, 'actionView']), +``` + +The class itself would look like the following: + +```php +use \Psr\Http\Message\ServerRequestInterface; +use \Psr\Http\Message\ResponseInterface; + +final readonly class PostController +{ + public function actionIndex(ServerRequestInterface $request): ResponseInterface + { + // render posts list + } + + + public function actionView(ServerRequestInterface $request): ResponseInterface + { + // render a single post + } +} +``` + +We usually call such a class "controller." + +## Autowiring + +Both constructors of action-classes and action-methods are automatically getting services from + the dependency injection container: + +```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'); + // render posts list + } + + + public function actionView(ServerRequestInterface $request): ResponseInterface + { + // render a single post + } +} +``` + +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. + diff --git a/src/it/guide/structure/application.md b/src/it/guide/structure/application.md new file mode 100644 index 00000000..3fff6311 --- /dev/null +++ b/src/it/guide/structure/application.md @@ -0,0 +1,18 @@ +# Application + +The primary purpose of the web application and its runner in Yii3 is to +process requests to get responses. + +Typically, the runtime consists of: + +1. 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. +2. 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. +3. Shutdown. Fire `ApplicationShutdown` event. diff --git a/src/it/guide/structure/domain.md b/src/it/guide/structure/domain.md new file mode 100644 index 00000000..6a35bb14 --- /dev/null +++ b/src/it/guide/structure/domain.md @@ -0,0 +1,91 @@ +# Domain + +The Domain or domain model is what makes the project unique. With requirements and terminology of the problem being solved +in mind (the problem context), you build an abstraction that consists of entities, their relationships, and logic that +operates these entities. To focus on the complex part of the problem, domain is, ideally, separated from + the infrastructure part of the system (that's how to save data into a database, how to form HTTP response, etc.). + +> [!NOTE] +> Such isolation is suitable for complex systems. If your project domain is basically create/read/update/delete +> for a set of records with not much complex logic, it makes no sense to apply a complex solution to a simple problem. +> The individual concepts of domain design below could be applied separately, so make sure to check these even if your +> project isn't that complicated. + +## Bounded context + +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." + +## Building blocks + +There are various building blocks that are typically used when describing +domain models. It isn't mandatory to use them all. + +### Entity + +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. + +### Value object + +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. + +### Aggregate + +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. + +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. + +### Domain event + +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. + +### Data transfer object + +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. + +### Service + +Service is a class that contains a standalone operation within the context +of your domain model. See "[service components](service.md)". + +### Repository + +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. + +Repository is usually implemented as a service. + +### Instantiating building blocks + +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. + +## References + +- [BoundedContext by Martin + Fowler](https://martinfowler.com/bliki/BoundedContext.html) +- [ValueObject by Martin + Fowler](https://martinfowler.com/bliki/ValueObject.html) +- [Aggregate by Marting + Fowler](https://martinfowler.com/bliki/DDD_Aggregate.html) + diff --git a/src/it/guide/structure/entry-script.md b/src/it/guide/structure/entry-script.md new file mode 100644 index 00000000..29f63c0f --- /dev/null +++ b/src/it/guide/structure/entry-script.md @@ -0,0 +1,114 @@ +# Entry scripts + +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. + +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. + +Entry script for console application is `./yii`. + +Entry scripts mainly perform the following work with the help of +`ApplicationRunner`: + +* Register [Composer + autoloader](https://getcomposer.org/doc/01-basic-usage.md#autoloading); +* Obtain configuration; +* Use configuration to initialize a dependency injection container; +* Get an instance of the request. +* Pass it to `Application` to handle and get a response from it. +* With the help of an emitter that transforms a response object into an + actual HTTP response that's sent to the client browser. + +## Web Applications + +The following is the code in the entry script for the application template: + +```php +debug(); +// Run application: +$runner->run(); +``` + + +## Console Applications + +Similarly, the following is the code for the entry script of a console +application: + +```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); +} +``` + +## Alternative runtimes + +For alternative runtimes such as RoadRunner or Swoole, special entry scripts +should be used. See: + +- [Using Yii with RoadRunner](../tutorial/using-yii-with-roadrunner.md) +- [Using Yii with Swoole](../tutorial/using-yii-with-swoole.md) diff --git a/src/it/guide/structure/handler.md b/src/it/guide/structure/handler.md new file mode 100644 index 00000000..651475be --- /dev/null +++ b/src/it/guide/structure/handler.md @@ -0,0 +1,3 @@ +# Request handlers + + diff --git a/src/it/guide/structure/middleware.md b/src/it/guide/structure/middleware.md new file mode 100644 index 00000000..2b450c2c --- /dev/null +++ b/src/it/guide/structure/middleware.md @@ -0,0 +1,195 @@ +# Middleware + +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/). + +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: + +- Pass the request to the next middleware performing some work before / + after it. +- Form the response and return it. + +Depending on middleware used, application behavior may vary significantly. + +![Middleware](/images/guide/middleware.svg) + +In the above each next middleware wraps the previous +middleware. Alternatively, it could be presented as follows: + +![Middleware](/images/guide/middleware_alternative.svg) + +## Using middleware + +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. + +Authentication middleware is implemented by +`middlewares/http-authentication` package so execute `composer require +middlewares/http-authentication` in the application root directory. + +Now register the middleware in DI container configuration `config/web.php`: + +```php + [ + 'class' => \Middlewares\BasicAuthentication::class, + '__construct()' => [ + 'users' => [ + 'foo' => 'bar', + ], + ], + 'realm()' => ['Access to the staging site via basic auth'], + 'attribute()' => ['username'], +], +``` + +In the `config/routes.php`, add new route: + +```php +action([SiteController::class, 'auth']) + ->name('site/auth') + ->prependMiddleware(BasicAuthentication::class) +]; +``` + +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. + +The action itself could be the following: + +```php +public function auth(ServerRequestInterface $request): ResponseInterface +{ + $response = $this->responseFactory->createResponse(); + $response->getBody()->write('Hi ' . $request->getAttribute('username')); + return $response; +} +``` + +Basic authentication middleware wrote to request `username` attribute, so +you can access the data if needed. + +To apply middleware to application overall regardless of URL, adjust +`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, + CsrfMiddleware::class, + Router::class, + ] + ); + }), + 'fallbackHandler' => Reference::to(NotFoundHandler::class), + ], + ], +]; +``` + +## Creating your own middleware + +To create middleware, you need to implement a single `process` method of +`Psr\Http\Server\MiddlewareInterface`: + +```php +public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface; +``` + +There are multiple ways to handle a request, and choosing one depends on +what the middleware should achieve. + +### Forming a response directly + +To respond directly, one needs a response factory passed via constructor: + +```php +responseFactory->createResponse(); + $response->getBody()->write('Hello!'); + return $response; + } +} +``` + +### Delegating handling to the next middleware + +If middleware either isn't intended to form a response or change the request or can't do anything this time, +handling could be left to the next middleware in the stack: + +```php +public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface +{ + return $handler->handle($request); +} +``` + +In case you need to pass data to the next middleware, you can use request +attributes: + +```php +$request = $request->withAttribute('answer', 42); +return $handler->handle($request); +``` + +To get it in the next middleware: + +```php +$answer = $request->getAttribute('answer'); +``` + +### Capturing response to manipulate it + +You may want to capture the response to manipulate it. It could be useful +for adding CORS headers, gzipping content, etc. + +```php +$response = $handler->handle($request); +// extra handing +return $response; +``` diff --git a/src/it/guide/structure/overview.md b/src/it/guide/structure/overview.md new file mode 100644 index 00000000..3d8f5d9d --- /dev/null +++ b/src/it/guide/structure/overview.md @@ -0,0 +1,65 @@ +# Overview + +Yii applications code is typically grouped into modules by context. In each +module there could be grouping by type. + +For example, if the application is an online store, the context could be: + +- Customer + - Profile + - Products list + - Checkout +- Logistics +- Delivery + - Addresses +- Helpdesk + - Support + - Claims + - Returns +- Accounting + - Returns + - Transactions + - Taxes + +For a "Customer" context, residing under `App\Customer` namespace, structure +would be: + +``` +App/ + Customer/ <-- module namespace + Entity/ + Customer.php <-- entity shared by "Profile" and "Checkout" + Profile/ + Widget/ + Gravatar.php + ProfileRepository.php <-- repository is usually specific to context + ProfileController.php <-- "Customer\Profile" entry point + ProductList/ <-- module namespace + Entity/ <-- entities specific to "Customer\ProductList" + Category.php + Product.php + ProductsListController.php <-- "Customer\ProductList" entry point + Checkout/ <-- module namespace + CheckoutController.php +``` + +A context may include sub-contexts. If a class is shared by multiple +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. + +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 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/guide/structure/package.md b/src/it/guide/structure/package.md new file mode 100644 index 00000000..a0bb1716 --- /dev/null +++ b/src/it/guide/structure/package.md @@ -0,0 +1,242 @@ +# Packages + +Reusable code could be released as [a Composer +package](https://getcomposer.org/doc/05-repositories.md#package). It could +be an infrastructure library, a module representing one of the application +contexts or, basically, any reusable code. + +## Using packages + +By default, Composer installs packages registered on +[Packagist](https://packagist.org/) — the biggest repository for open source +PHP packages. You can look for packages on Packagist. You may also [create +your own +repository](https://getcomposer.org/doc/05-repositories.md#repository) and +configure Composer to use it. This is useful if you're developing private +packages that you want to share within your projects only. + +Packages installed by Composer are stored in the `vendor` directory of your +project. Because the Composer is a dependency manager, when it installs a +package, it will also install all its dependent packages. + +> [!WARNING] +> `vendor` directory of your application should never be modified. + +A package could be installed with the following command: + +``` +composer install vendor-name/package-name +``` + +After it's done, Composer modifies `composer.json` and `composer.lock`. The +former defines what packages to install, and their version constraints the +latter stores a snapshot of exact versions actually installed. + +Classes from the package will be available immediately via +[autoloading](../concept/autoloading.md). + +## Creating packages + + +You may consider creating a package when you feel the need to share with +other people your great code. A package can contain any code you like, such +as a helper class, a widget, a service, middleware, the whole module, etc. + +Below are the basic steps you may follow. + +1. Create a project for your package and host it on a VCS repository, such + as [GitHub.com](https://github.com). The development and maintenance + work for the package should be done on this repository. +2. Under the root directory of the project, create a file named + `composer.json` as required by Composer. Please refer to the next + subsection for more details. +3. Register your package with a Composer repository, such as + [Packagist](https://packagist.org/), so that other users can find and + install your package using Composer. + + +### `composer.json` + +Each Composer package must have a `composer.json` file in its root +directory. The file contains the metadata about the package. You may find +the complete specification about this file in the [Composer +Manual](https://getcomposer.org/doc/01-basic-usage.md#composer-json-project-setup). +The following example shows the `composer.json` file for the +`yiisoft/yii-widgets` package: + +```json +{ + "name": "yiisoft/yii-widgets", + "type": "library", + "description": "Yii widgets collection", + "keywords": [ + "yii", + "widgets" + ], + "homepage": "https://www.yiiframework.com/", + "license": "BSD-3-Clause", + "support": { + "issues": "https://github.com/yiisoft/yii-widgets/issues?state=open", + "forum": "https://www.yiiframework.com/forum/", + "wiki": "https://www.yiiframework.com/wiki/", + "irc": "ircs://irc.libera.chat:6697/yii", + "chat": "https://t.me/yii3en", + "source": "https://github.com/yiisoft/yii-widgets" + }, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/yiisoft" + }, + { + "type": "github", + "url": "https://github.com/sponsors/yiisoft" + } + ], + "require": { + "php": "^7.4|^8.0", + "yiisoft/aliases": "^1.1|^2.0", + "yiisoft/cache": "^1.0", + "yiisoft/html": "^2.0", + "yiisoft/view": "^4.0", + "yiisoft/widget": "^1.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5", + "roave/infection-static-analysis-plugin": "^1.16", + "spatie/phpunit-watcher": "^1.23", + "vimeo/psalm": "^4.18", + "yiisoft/psr-dummy-provider": "^1.0", + "yiisoft/test-support": "^1.3" + }, + "autoload": { + "psr-4": { + "Yiisoft\\Yii\\Widgets\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "Yiisoft\\Yii\\Widgets\\Tests\\": "tests" + } + }, + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "scripts": { + "test": "phpunit --testdox --no-interaction", + "test-watch": "phpunit-watcher watch" + }, + "config": { + "sort-packages": true, + "allow-plugins": { + "infection/extension-installer": true, + "composer/package-versions-deprecated": true + } + } +} +``` + + +#### Package Name + +Each Composer package should have a package name which uniquely identifies +the package among all others. The format of package names is +`vendorName/projectName`. For example, in the package name `yiisoft/queue`, +the vendor name, and the project name are `yiisoft` and `queue`, +respectively. + +> [!WARNING] +> Don't use `yiisoft` as your vendor name as it's reserved for use by the Yii itself. + +We recommend you prefix `yii-` to the project name for packages that aren't +able to work as general PHP packages and require Yii application. This will +allow users to more easily tell whether a package is Yii specific. + + +#### Dependencies + +If your extension depends on other packages, you should list them in +`require` section of `composer.json`. Make sure you also list appropriate +version constraints (e.g. `^1.0`, `@stable`) for each dependent package. +Use stable dependencies when your extension is released in a stable version. + +#### Class Autoloading + +In order for your classes to be autoloaded, you should specify the +`autoload` entry in the `composer.json` file, like shown below: + +```json +{ + // .... + + "autoload": { + "psr-4": { + "MyVendorName\\MyPackageName\\": "src" + } + } +} +``` + +You may list one or multiple root namespaces and their corresponding file +paths. + +### Recommended Practices + +Because packages are meant to be used by other people, you often need to +make an extra effort during development. Below, we introduce some common +and recommended practices in creating high-quality extensions. + + +#### Testing + +You want your package to run flawlessly without bringing problems to other +people. To reach this goal, you should test your extension before releasing +it to the public. + +It's recommended that you create various test cases to cover your extension +code rather than relying on manual tests. Each time before you release a +new version of your package, you may run these test cases to make sure +everything is in good shape. For more details, please refer to the +[Testing](../testing/overview.md) section. + + +#### Versioning + +You should give each release of your extension a version number +(e.g. `1.0.1`). We recommend you follow the [semantic +versioning](https://semver.org) practice when determining what version +numbers should be used. + + +#### Releasing + +To let other people know about your package, you need to release it to the +public. + +If it's the first time you're releasing a package, you should register it in +a Composer repository, such as [Packagist](https://packagist.org/). After +that, all you need to do is create a release tag (for example, `v1.0.1`) on +the VCS repository of your extension and notify the Composer repository +about the new release. People will then be able to find the new release and +install or update the package through the Composer repository. + +In the release of your package, in addition to code files, you should also +consider including the following to help other people learn about and use +your extension: + +* A readme file in the package root directory: it describes what your + extension does and how to install and use it. We recommend you write it + in [Markdown](https://daringfireball.net/projects/markdown/) format and + name the file as `README.md`. +* A changelog file in the package root directory: it lists what changes are + made in each release. The file may be written in Markdown format and named + as `CHANGELOG.md`. +* An upgrade file in the package root directory: it gives the instructions + on how to upgrade from older releases of the extension. The file may be + written in Markdown format and named as `UPGRADE.md`. +* Tutorials, demos, screenshots, etc.: these are needed if your extension + provides many features that can't be fully covered in the readme file. +* API documentation: your code should be well-documented to allow other + people to more easily read and understand it. diff --git a/src/it/guide/structure/service.md b/src/it/guide/structure/service.md new file mode 100644 index 00000000..0baee5d5 --- /dev/null +++ b/src/it/guide/structure/service.md @@ -0,0 +1,119 @@ +# Service components + +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: + +```php +public function actionIndex(CurrentRoute $route, MyService $myService): ResponseInterface +{ + $id = $route->getArgument('id'); + + // ... + $extraData = $myService->getExtraData($id); + + // ... +} +``` + +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: + +```php +final readonly class MyService +{ + public function __construct( + private ExtraDataStorage $extraDataStorage + ) + { + } + + public function getExtraData(string $id): array + { + return $this->extraDataStorage->get($id); + } +} +``` + +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. + +## Service dependencies and configuration + +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. + +- After the service is created, it shouldn't be re-configured in runtime. +- DI container instance usually **shouldn't** be injected as a + dependency. Prefer concrete interfaces. +- In case of complicated or "heavy" initialization, try to postpone it until + the service method is called. + +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: + +```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 + { + // check DSN validity + } +} +``` + +## Service methods + +Service method usually does something. It could be a simple thing repeated +exactly, but usually it depends on the context. For example: + +```php +final readonly class PostPersister +{ + public function __construct( + private Storage $db + ) + { + } + + public function persist(Post $post) + { + $this->db->insertOrUpdate('post', $post); + } +} +``` + +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. + +## Is everything a service? + +Often it makes sense to choose another class type to place your code +into. Check: + +- Repository +- Widget +- [Middleware](middleware.md) +- Entity diff --git a/src/it/guide/tutorial/console-applications.md b/src/it/guide/tutorial/console-applications.md new file mode 100644 index 00000000..3f5d2e11 --- /dev/null +++ b/src/it/guide/tutorial/console-applications.md @@ -0,0 +1,85 @@ +# Console applications + +Console applications are mainly used to create utility, background +processing and maintenance tasks. + +To get support for console application in your project, get +`yiisoft/yii-console` via composer: + + +``` +composer require yiisoft/yii-console +``` + +After it's installed, you can access the entry point as + +``` +./yii +``` + +Out of the box only `serve` command is available. It's starting PHP built-in +web server to serve the application locally. + +Commands are executed with `symfony/console`. To create your own console +command, you need to define a command: + +```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; + } +} +``` + +Now register the command in `config/params.php`: + +```php +return [ + 'console' => [ + 'commands' => [ + 'demo/hello' => App\Demo\HelloCommand::class, + ], + ], +]; +``` + +After it's done, the command could be executed as + +``` +./yii demo:hello Alice +``` + + +## References + +- [Symfony Console component + guide](https://symfony.com/doc/current/components/console.html) diff --git a/src/it/guide/tutorial/mailing.md b/src/it/guide/tutorial/mailing.md new file mode 100644 index 00000000..e5833e5d --- /dev/null +++ b/src/it/guide/tutorial/mailing.md @@ -0,0 +1,329 @@ +# Mailing + +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. + +To send actual emails, you can use the [Symfony +Mailer](https://github.com/yiisoft/mailer-symfony) implementation, which is +used in the examples below. + +## Configuring the Mailer + +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`. + +You can also create an instance manually as follows: + +```php + +use Yiisoft\Mailer\Symfony\Mailer; + +/** + * @var \Symfony\Component\Mailer\Transport\TransportInterface $transport + */ + +$mailer = new \Yiisoft\Mailer\Symfony\Mailer( + $transport, +); +``` + +The `Yiisoft\Mailer\MailerInterface` provides two main methods: + +- `send()` - Sends the given email message. +- `sendMultiple()` - Sends many messages at once. + +## Creating a Message + +### Simple Text Message + +To create a simple message with a text body, 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' +); +``` + +### Simple HTML Message + +```php +$message = new \Yiisoft\Mailer\Message( + from: 'from@domain.com', + to: 'to@domain.com', + subject: 'Message subject', + htmlBody: 'HTML content' +); +``` + +### HTML Message from template + +For this example, we will use package rendering package +[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 +); +``` + +### Using Layouts + +You can also pass parameters to layouts from your template message: + +```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 +); +``` + +### Layout Example + +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: + +```php + + + + + + + + + + +
+--
+Mailed by Yii +
+ + + +``` + +## Adding More Data + +The `Yiisoft\Mailer\MessageInterface` provides several methods to customize +your message: + +- `withCharset()` - Returns a new instance with the specified charset. +- `withFrom()` - Returns a new instance with the specified sender email + address. +- `withTo()` - Returns a new instance with the specified recipient(s) email + address. +- `withReplyTo()` - Returns a new instance with the specified reply-to + address. +- `withCc()` - Returns a new instance with the specified Cc (extra copy + receiver) addresses. +- `withBcc()` - Returns a new instance with the specified Bcc (hidden copy + receiver) addresses. +- `withSubject()` - Returns a new instance with the specified message + subject. +- `withDate()` - Returns a new instance with the specified date when the + message was sent. +- `withPriority()` - Returns a new instance with the specified priority of + this message. +- `withReturnPath()` - Returns a new instance with the specified return-path + (the bounce address) of this message. +- `withSender()` - Returns a new instance with the specified actual sender + email address. +- `withHtmlBody()` - Returns a new instance with the specified message HTML + content. +- `withTextBody()` - Returns a new instance with the specified message plain + text content. +- `withAddedHeader()` - Returns a new instance with the specified added + custom header value. +- `withHeader()` - Returns a new instance with the specified custom header + value. +- `withHeaders()` - Returns a new instance with the specified custom header + values. + +These methods are immutable, meaning they return a new instance of the +message with the updated data. + +Note `with` prefix. It indicates that the method is immutable and returns a +new instance of the class with the changed data. + +### Getters + +The following getters are available to retrieve message data: + +- `getCharset()` - Returns the charset of this message. +- `getFrom()` - Returns the message sender email address. +- `getTo()` - Returns the message recipient(s) email address. +- `getReplyTo()` - Returns the reply-to address of this message. +- `getCc()` - Returns the Cc (extra copy receiver) addresses of this + message. +- `getBcc()` - Returns the Bcc (hidden copy receiver) addresses of this + message. +- `getSubject()` - Returns the message subject. +- `getDate()` - Returns the date when the message was sent, or null if it + wasn't set. +- `getPriority()` - Returns the priority of this message. +- `getReturnPath()` - Returns the return-path (the bounce address) of this + message. +- `getSender()` - Returns the message actual sender email address. +- `getHtmlBody()` - Returns the message HTML body. +- `getTextBody()` - Returns the message text body. +- `getHeader()` - Returns all values for the specified header. +- `__toString()` - Returns string representation of this message. + +## Attaching Files + +You can attach files to your message using the `withAttached()` method: + +```php +use Yiisoft\Mailer\File; + +// Attach a file from the local file system +$message = $message->withAttached( + File::fromPath('/path/to/source/file.pdf'), +); + +// Create an attachment on-the-fly +$message = $message->withAttached( + File::fromContent('Attachment content', 'attach.txt', 'text/plain'), +); +``` + +## Embedding Images + +You can embed images into the message content using the `withEmbedded()` +method. This is particularly useful when composing messages with 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 + ); +``` + +In your view or layout template, you can reference the embedded image using +its CID: + +```php + +``` + +## Sending a Message + +To send an email message: + +```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); +``` + +## Sending Multiple Messages + +You can send multiple messages at once: + +```php +$messages = []; + +foreach ($users as $user) { + $messages[] = (new \Yiisoft\Mailer\Message()) + // ... + ->withTo($user->email); +} + +$result = $mailer->sendMultiple($messages); +``` + +The `sendMultiple()` method returns a `Yiisoft\Mailer\SendResults` object +containing arrays of successfully sent and failed messages. + +## Implementing your own mail driver + +To create a custom mail solution, implement the +`Yiisoft\Mailer\MailerInterface` and `Yiisoft\Mailer\MessageInterface` +interfaces. + +## For Development + +For local or test development, you can use simplified implementations of the +mailer that does not send emails. The package provides these +implementations: + +- `Yiisoft\Mailer\StubMailer` - A simple mailer that stores messages in a + local array. +- `Yiisoft\Mailer\FileMailer` - A mock mailer that saves email messages as + files instead of sending them. +- `Yiisoft\Mailer\NullMailer` - A mailer that discards messages without + sending or storing them. + +To use one of these mailers, configure it in your development environment +file Example: `environments/local/di.php` + +```php +return [ + Yiisoft\Mailer\MailerInterface::class => Yiisoft\Mailer\StubMailer::class, //or any other +]; + +``` diff --git a/src/it/guide/tutorial/performance-tuning.md b/src/it/guide/tutorial/performance-tuning.md new file mode 100644 index 00000000..bf43d4a4 --- /dev/null +++ b/src/it/guide/tutorial/performance-tuning.md @@ -0,0 +1,219 @@ +# Performance tuning + +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. + + +## Optimizing your PHP Environment + +A well-configured PHP environment is important. To get maximum performance: + +- Use the latest stable PHP version. Major releases of PHP may bring + significant performance improvements. +- 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. +- [Tune `realpath()` + cache](https://github.com/samdark/realpath_cache_tuner). +- Make sure [XDebug](https://xdebug.org/) isn't installed in the production + environment. +- Try [PHP 7 preloading](https://wiki.php.net/rfc/preload). + +## Optimizing your code + +Beyond environment configuration, there are code-level optimizations that +can improve your application's performance: + +- 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. +- [Speeding up + array_merge()](https://www.exakat.io/speeding-up-array_merge/) +- [Move that foreach() inside the + method](https://www.exakat.io/move-that-foreach-inside-the-method/) +- [Array, classes and anonymous classes memory + usage](https://www.exakat.io/array-classes-and-anonymous-memory-usage/) +- 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. + +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. + +## Using caching techniques + +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. + + +## Optimizing session storage + +By default, session data is stored in files. The implementation is locking a file from opening a session to the point it's +closed either by `$session->close()` or at the end of request. +While the session file is locked, all other requests that are trying to use the same session are blocked. That's waiting for the +initial request to release a session file. This is fine for development and probably small projects. But when it comes +to handling massive concurrent requests, it's better to use more sophisticated storage, such as Redis. + +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: + +```php +\Yiisoft\Session\SessionInterface::class => [ + 'class' => \Yiisoft\Session\Session::class, + '__construct()' => [[], $myCustomSessionHandler], +], +``` + +## Optimizing databases + +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. + +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. + +For complex DB queries, it's recommended that you create database views to +save the query parsing and preparation time. + +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. + + +## Optimizing composer autoloader + +Because Composer autoloader is used to include most third-party class files, +you should consider optimizing it by executing the following command: + +``` +composer dumpautoload -o +``` + +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. + + +## Processing data offline + +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. + +There are two methods to process data offline: pull and push. + +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. + +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. + +## Using preloading + +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). + +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. + +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. + +### Preloading benchmarks + +The application template benchmark includes configuring classes to injected +dependencies in the bootstrap script. + +For both variants, +[ApacheBench](https://httpd.apache.org/docs/2.4/programs/ab.html) was used +with the following run parameters: + +```shell +ab -n 1000 -c 10 -t 10 +``` + +Also, the debug mode was disabled. And an optimized autoloader of the +[Composer](https://getcomposer.org) was used, and development dependencies +weren't used: + +```shell +composer install --optimize-autoloader --no-dev +``` + +With preloading enabled, the entire composer class map (825 files) was used: + +```php +$files = require 'vendor/composer/autoload_classmap.php'; + +foreach (array_unique($files) as $file) { + opcache_compile_file($file); +} +``` + +#### Test results + +| Benchmark | Preloaded files | Opcache memory used | Per request memory used | Time per request | Requests per second | +|--------------------|-----------------|---------------------|-------------------------|------------------|---------------------| +| Without preloading | 0 | 12.32 mb | 1.71 mb | 27.63 ms | 36.55 rq/s | +| With preloading | 825 | 17.86 mb | 1.82 mb | 26.21 ms | 38.42 rq/s | + +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). + +## Performance profiling + +You should profile your code to find out the performance bottlenecks and +take appropriate measures accordingly. The following profiling tools may be +useful: + + + +- [Blackfire](https://blackfire.io/) +- [XHProf](https://secure.php.net/manual/en/book.xhprof.php) +- [XDebug profiler](https://xdebug.org/docs/profiler) diff --git a/src/it/guide/tutorial/using-with-event-loop.md b/src/it/guide/tutorial/using-with-event-loop.md new file mode 100644 index 00000000..5b2c09df --- /dev/null +++ b/src/it/guide/tutorial/using-with-event-loop.md @@ -0,0 +1,65 @@ +# Using Yii with event loop + +A normal PHP web request execution cycle consists of setting up an environment, getting a request, processing it to form a response +and sending the result. After the response is sent, execution is terminated and its context is lost. So, for the further + request, the whole sequence is repeated. Such an approach has a big advantage in ease of development since a developer doesn't +have to take much care about memory leaks or properly clean up context. On the other side, initializing everything for +every request takes time and overall consumes up to 50% of processing resources. + +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. + +There are multiple tools that could be used to achieve it. Notably, +[FrankenPHP](https://frankenphp.dev/), [RoadRunner](https://roadrunner.dev/) +and [Swoole](https://www.swoole.co.uk/). + +## Event loop implications + +Event loop worker basically looks like the following: + +```php +initializeContext(); +while ($request = getRequest()) { + $response = process($request); + emit($response); +} +``` + +Usually, there are multiple workers processing requests at the same time as +with traditional php-fpm. + +That means that there's more to consider when developing applications. + +### Processing is blocking + +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. + +### Services and state + +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. + +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: + +```php +initializeContext(); +$resetter = $container->get(\Yiisoft\Di\StateResetter::class); +while ($request = getRequest()) { + $response = process($request); + emit($response); + $resetter->reset(); // We should reset the state of such services on every request. +} +``` + +## Integrations + +- [RoadRunner](using-yii-with-roadrunner.md) +- [Swoole](using-yii-with-swoole.md) diff --git a/src/it/guide/tutorial/using-yii-with-roadrunner.md b/src/it/guide/tutorial/using-yii-with-roadrunner.md new file mode 100644 index 00000000..49c353ab --- /dev/null +++ b/src/it/guide/tutorial/using-yii-with-roadrunner.md @@ -0,0 +1,97 @@ +# Using Yii with RoadRunner + +[RoadRunner](https://roadrunner.dev/) is a Golang-powered application server that integrates well with PHP. It runs +it as workers and 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. + +## Installation + +RoadRunner works on Linux, macOS and Windows. The best way to install it is +to use a Composer: + +``` +composer require yiisoft/yii-runner-roadrunner +``` + +After installation is done, run + +``` +./vendor/bin/rr get +``` + +That would download ready to use RoadRunner server `rr` binary. + +## Configuration + +First, we need to configure the server itself. Create `/.rr.yaml` and add +the following config: + +```yaml +server: + command: "php worker.php" + +rpc: + listen: tcp://127.0.0.1:6001 + +http: + address: :8080 + pool: + num_workers: 4 + max_jobs: 64 + middleware: ["static", "headers"] + static: + dir: "public" + forbid: [".php", ".htaccess"] + headers: + response: + "Cache-Control": "no-cache" + +reload: + interval: 1s + patterns: [ ".php" ] + services: + http: + recursive: true + dirs: [ "." ] + +logs: + mode: production + level: warn +``` + +We're specifying that entry script is `worker.php`, there should be three +workers on port 8080, `public` directory files are static ones except `.php` +and `.htaccess`. Also, we're sending an additional header. + +Create `/worker.php`: + +```php +run(); +``` + +## Starting a server + +To start a server, execute the following command: + +``` +./rr serve -d +``` + +## On worker scope + +- Each worker's scope is isolated from other workers. Memory isn't shared. +- A single worker serves multiple requests where the scope is shared. +- At each iteration of the event loop, every service that depends on state + should be reset. diff --git a/src/it/guide/tutorial/using-yii-with-swoole.md b/src/it/guide/tutorial/using-yii-with-swoole.md new file mode 100644 index 00000000..6fd19ffc --- /dev/null +++ b/src/it/guide/tutorial/using-yii-with-swoole.md @@ -0,0 +1,129 @@ +# Using Yii with Swoole + +[Swoole](https://www.swoole.co.uk/) is a PHP network framework distributed as a PECL extension. It allows you built-in async, +multiple threads I/O modules. Developers can use sync or async, coroutine API to write the applications. + +In the context of Yii, it allows running request handlers 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. + +## Installation + +Swoole works on Linux and macOS and can be installed via pecl: + +```bash +pecl install swoole +``` + +## Putting up a server + +Since Swoole doesn't have built-in PSR-7 support, you need a package fixing +so: + +```php +composer require ilexn/swoole-convent-psr7 +``` + +Create an entry script, `server.php`: + +```php +withDefinitions($config->get('web')) + ->withProviders($config->get('providers-web')); +$container = new Container($containerConfig); + +$bootstrapList = $config->get('bootstrap-web'); +foreach ($bootstrapList as $callback) { + if (!(is_callable($callback))) { + $type = is_object($callback) ? get_class($callback) : gettype($callback); + + throw new \RuntimeException("Bootstrap callback must be callable, $type given."); + } + $callback($container); +} + +$application = $container->get(Application::class); + +$serverRequestFactory = new \Ilex\SwoolePsr7\SwooleServerRequestConverter( + $container->get(ServerRequestFactoryInterface::class), + $container->get(UriFactoryInterface::class), + $container->get(UploadedFileFactoryInterface::class), + $container->get(StreamFactoryInterface::class) +); + +$server = new Swoole\HTTP\Server('0.0.0.0', 9501); + +$server->on('start', static function (Swoole\Http\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 (Swoole\Http\Request $request, Swoole\Http\Response $response) use ($serverRequestFactory, $application, $container) { + $psr7Response = null; + try { + $requestContainer = clone $container; + $psr7Request = $serverRequestFactory->createFromSwoole($request); + $psr7Response = $application->handle($psr7Request); + + $converter = new \Ilex\SwoolePsr7\SwooleResponseConverter($response); + $converter->send($psr7Response); + } catch (\Throwable $t) { + // TODO: render it properly + $response->end($t->getMessage()); + } finally { + $application->afterEmit($psr7Response ?? null); + $container->get(\Yiisoft\Di\StateResetter::class)->reset(); + $container = $requestContainer; + } +}); + +$server->on('shutdown', static function (Swoole\Http\Server $server) use ($application) { + $application->shutdown(); +}); + +$server->start(); +``` + +## Starting a server + +To start a server, execute the following command: + +``` +php server.php +``` + +## On scope + +A scope is shared, so at each iteration of the event loop every service that +depends on state should be reset. diff --git a/src/it/guide/views/asset.md b/src/it/guide/views/asset.md new file mode 100644 index 00000000..95ecbd5a --- /dev/null +++ b/src/it/guide/views/asset.md @@ -0,0 +1,658 @@ +# Assets + +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. + +## Installation + +The asset management functionality is provided by the `yiisoft/assets` +package: + +```bash +composer require yiisoft/assets +``` + +This package is included by default in the `yiisoft/app` application +template. + +## Basic Concepts + +### Asset Bundles + +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. + +### Asset Manager + +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 + +## Creating Asset Bundles + +### Basic Asset Bundle + +Here's a simple asset bundle definition: + +```php + 'print'], + ['css/admin/mobile.css', 'media' => 'screen and (max-width: 768px)'], + ]; + + // JavaScript files with attributes + public array $js = [ + 'js/admin/core.js', + ['js/admin/charts.js', 'defer' => true], + ['js/admin/analytics.js', 'async' => true], + ]; + + // Global options for all JS files in this bundle + public array $jsOptions = [ + 'data-admin' => 'true', + ]; + + // Global options for all CSS files in this bundle + public array $cssOptions = [ + 'data-bundle' => 'admin', + ]; + + public array $depends = [ + MainAsset::class, + ChartJsAsset::class, + ]; +} +``` + +## Using Asset Bundles + +### In Controllers + +Register asset bundles in your controllers or views: + +```php +assetManager->register(MainAsset::class); + + return $this->viewRenderer->render('index', [ + 'title' => 'Home Page', + ]); + } + + public function admin(): ResponseInterface + { + // Register multiple asset bundles + $this->assetManager->register([ + MainAsset::class, + AdminAsset::class, + ]); + + return $this->viewRenderer->render('admin/dashboard'); + } +} +``` + +### In Views + +You can also register assets directly in views: + +```php +register(ProductAsset::class); +?> + +
+

+ +
+``` + +### With WebView Integration + +The recommended approach is to integrate with WebView for automatic asset +rendering: + +```php +register(MainAsset::class); + +// Add all registered assets to the view +$this->addCssFiles($assetManager->getCssFiles()); +$this->addCssStrings($assetManager->getCssStrings()); +$this->addJsFiles($assetManager->getJsFiles()); +$this->addJsStrings($assetManager->getJsStrings()); +$this->addJsVars($assetManager->getJsVars()); +?> + +
+ +
+``` + +## Asset Publishing + +### Source Path Publishing + +When assets are located in non-web-accessible directories (like vendor +packages), they need to be published: + +```php +publish('@vendor/company/package/assets'); + +// Get the published URL +$publishedUrl = $assetManager->getPublishedUrl('@vendor/company/package/assets'); +``` + +## Third-party Library Assets + +### jQuery Asset Bundle + +```php + 'sha256-...', + 'crossorigin' => 'anonymous', + ]; +} +``` + +### Bootstrap Asset Bundle + +```php + 'sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p', + 'crossorigin' => 'anonymous', + ]; +} +``` + +## Asset Configuration + +### Application Configuration + +Configure asset management in your application configuration: + +**config/web/params.php** +```php +return [ + 'yiisoft/assets' => [ + // Base path for published assets + 'basePath' => '@webroot/assets', + + // Base URL for assets + 'baseUrl' => '@web/assets', + + // Asset converter configuration + 'converter' => [ + 'commands' => [ + 'scss' => ['sass', '{from}', '{to}', '--style=compressed'], + 'ts' => ['tsc', '{from}', '--outFile', '{to}'], + ], + ], + ], +]; +``` + +### Environment-specific Assets + +Configure different assets for different environments: + +```php +css = ['css/main.css', 'css/debug.css']; + $this->js = ['js/main.js', 'js/debug.js']; + } else { + // Production assets (minified) + $this->css = ['css/main.min.css']; + $this->js = ['js/main.min.js']; + } + } +} +``` + +## Asset Optimization + +### Asset Combination + +Combine multiple CSS or JavaScript files into single files: + +```php +/** + * @var \Yiisoft\Assets\AssetManager $assetManager + */ + +// Enable asset combination +$assetManager->setCombine(true); + +// Set combination options +$assetManager->setCombineOptions([ + 'css' => true, // Combine CSS files + 'js' => true, // Combine JavaScript files +]); +``` + +### Asset Compression + +Configure asset compression for production: + +```php +// In your asset manager configuration +'converter' => [ + 'commands' => [ + 'css' => ['cleancss', '{from}', '-o', '{to}'], + 'js' => ['uglifyjs', '{from}', '-o', '{to}', '--compress', '--mangle'], + ], +], +``` + +## Working with Asset Converter + +### SCSS/SASS Compilation + +```php + 'screen and (max-width: 768px)'], + ]; + + public array $depends = [ + AppAsset::class, + ]; +} +``` + +## Best Practices + +1. **Organize by functionality**: Group related assets into logical bundles +2. **Manage dependencies**: Properly declare dependencies between bundles +3. **Use meaningful names**: Name your asset bundles clearly +4. **Environment optimization**: Use minified assets in production +5. **CDN consideration**: Use CDN for popular libraries when appropriate +6. **Version your assets**: Include version numbers in filenames for cache + busting +7. **Minimize HTTP requests**: Combine related assets when possible +8. **Optimize file sizes**: Compress and minify assets for production + +## Troubleshooting + +### Common Issues + +**Asset not found:** +- Check that the asset file exists in the specified path +- Verify `$basePath` and `$baseUrl` are configured correctly +- Ensure assets are published if using `$sourcePath` + +**Dependencies not loading:** +- Verify the dependency bundles are properly registered +- Check for circular dependencies +- Ensure dependency bundles are correctly configured + +**Assets not appearing in HTML:** +- Make sure you're calling `$this->addCssFiles()` and `$this->addJsFiles()` in your layout +- Verify that `$this->head()`, `$this->beginBody()`, and `$this->endBody()` are called in the layout + +**Permission issues:** +- Check that the web server has write permissions to the assets directory +- Verify the published assets directory is web-accessible diff --git a/src/it/guide/views/script-style-meta.md b/src/it/guide/views/script-style-meta.md new file mode 100644 index 00000000..4a899f47 --- /dev/null +++ b/src/it/guide/views/script-style-meta.md @@ -0,0 +1,505 @@ +# Scripts, styles and meta tags + +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. + +## Overview + +The `WebView` class extends the basic `View` class with web-specific +functionality, allowing you to: + +- Register CSS files and inline styles +- Register JavaScript files and inline scripts +- Manage HTML meta tags and link tags +- Control the position where resources are rendered +- Handle dependencies between resources + +## CSS management + +### Registering CSS Files + +You can register CSS files to be included in your HTML pages: + +```php +registerCssFile('/css/styles.css'); + +// Register CSS file with attributes +$this->registerCssFile('/css/print.css', WebView::POSITION_HEAD, [ + 'media' => 'print', +]); + +// Register CSS file with custom key to avoid duplicates +$this->registerCssFile('/css/theme.css', WebView::POSITION_HEAD, [], 'theme-css'); +``` + +### Registering Inline CSS + +For inline CSS styles, use the `registerCss()` method: + +```php +// Register inline CSS +$this->registerCss(' + .highlight { + background-color: yellow; + font-weight: bold; + } + .error { + color: red; + border: 1px solid red; + } +', WebView::POSITION_HEAD); + +// With custom attributes +$this->registerCss(' + @media print { + .no-print { display: none; } + } +', WebView::POSITION_HEAD, ['id' => 'print-styles']); +``` + +### CSS from Files + +You can also register CSS content from external files: + +```php +// Read CSS from a file and register as inline CSS +$this->registerCssFromFile('/path/to/dynamic-styles.css', WebView::POSITION_HEAD, [ + 'id' => 'dynamic-styles', +]); +``` + +### Using Style Tags + +For more control, you can use HTML style tags directly: + +```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); +``` + +## JavaScript management + +### Registering JavaScript Files + +Include external JavaScript files using `registerJsFile()`: + +```php +// Register a JavaScript file +$this->registerJsFile('/js/main.js'); + +// Register with attributes (async loading) +$this->registerJsFile('/js/analytics.js', WebView::POSITION_END, [ + 'async' => true, +]); + +// Register with defer attribute +$this->registerJsFile('/js/interactive.js', WebView::POSITION_END, [ + 'defer' => true, +]); + +// Register from CDN +$this->registerJsFile('https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js', + WebView::POSITION_END, [], 'jquery'); +``` + +### Registering Inline JavaScript + +Add inline JavaScript code with `registerJs()`: + +```php +// Register inline JavaScript +$this->registerJs(' + document.addEventListener("DOMContentLoaded", function() { + console.log("Page loaded!"); + initializeComponents(); + }); +', WebView::POSITION_END); + +// Register JavaScript that should run when DOM is ready +$this->registerJs(' + function showAlert(message) { + alert(message); + } +', WebView::POSITION_READY); +``` + +### JavaScript Variables + +Pass PHP data to JavaScript using `registerJsVar()`: + +```php +// Register JavaScript variables +$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(), +]); +``` + +This generates JavaScript code like: + +```html + +``` + +### Using Script Tags + +For more control over script tags: + +```php +use Yiisoft\Html\Html; + +$scriptTag = Html::script(' + window.myApp = { + init: function() { + console.log("App initialized"); + } + }; +', ['type' => 'module']); + +$this->registerScriptTag($scriptTag, WebView::POSITION_END); +``` + +## Position Constants + +Resources can be positioned at different locations in the HTML document: + +```php +use Yiisoft\View\WebView; + +// In the section +WebView::POSITION_HEAD + +// At the beginning of +WebView::POSITION_BEGIN + +// At the end of (before ) +WebView::POSITION_END + +// When DOM is ready (jQuery document.ready equivalent) +WebView::POSITION_READY + +// When page is fully loaded (window.onload equivalent) +WebView::POSITION_LOAD +``` + +Example layout showing where each position is rendered: + +```php + +beginPage() ?> + + + + + head() ?> + + + + beginBody() ?> + +
+ +
+ + + endBody() ?> + + +endPage() ?> +``` + +## Meta tags + +### Basic Meta Tags + +Register meta tags for SEO and page information: + +```php +// Register meta tags using array syntax +$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 for responsive design +$this->registerMeta(['name' => 'viewport', 'content' => 'width=device-width, initial-scale=1']); + +// Open Graph tags for social media +$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']); +``` + +### Using Meta Tag Objects + +For more control, use the `Html::meta()` helper: + +```php +use Yiisoft\Html\Html; + +// Create meta tags with the Html helper +$this->registerMetaTag( + Html::meta() + ->name('description') + ->content('This is a comprehensive guide to Yii3 views') +); + +$this->registerMetaTag( + Html::meta() + ->httpEquiv('refresh') + ->content('300') // Refresh every 5 minutes +); +``` + +### Preventing Duplicate Meta Tags + +Use keys to prevent duplicate meta tags: + +```php +// First registration +$this->registerMeta([ + 'name' => 'description', + 'content' => 'Original description' +], 'description'); + +// This will override the previous one +$this->registerMeta([ + 'name' => 'description', + 'content' => 'Updated description' +], 'description'); +``` + +## Link tags + +### Basic Link Tags + +Register various types of link tags: + +```php +// Favicon +$this->registerLink([ + 'rel' => 'icon', + 'type' => 'image/png', + 'href' => '/favicon.png', +]); + +// RSS feed +$this->registerLink([ + 'rel' => 'alternate', + 'type' => 'application/rss+xml', + 'title' => 'RSS Feed', + 'href' => '/feed.rss', +]); + +// Canonical URL +$this->registerLink([ + 'rel' => 'canonical', + 'href' => 'https://example.com/canonical-url', +]); + +// Preload resources +$this->registerLink([ + 'rel' => 'preload', + 'href' => '/fonts/main.woff2', + 'as' => 'font', + 'type' => 'font/woff2', + 'crossorigin' => 'anonymous', +]); +``` + +### Using Link Tag Objects + +```php +use Yiisoft\Html\Html; + +// CSS stylesheet +$this->registerLinkTag( + Html::link('/css/main.css', [ + 'rel' => 'stylesheet', + ]) +); + +// DNS prefetch +$this->registerLinkTag( + Html::link('https://fonts.googleapis.com', [ + 'rel' => 'dns-prefetch', + ]) +); +``` + +## Practical Examples + +### Complete Page Setup + +Here's how you might set up a complete page with all types of resources: + +```php +setTitle($title); + +// Meta tags +$this->registerMeta(['name' => 'description', 'content' => $description]); +$this->registerMeta(['name' => 'keywords', 'content' => 'ecommerce, products, online shop']); + +// Open Graph tags +$this->registerMeta(['property' => 'og:title', 'content' => $title]); +$this->registerMeta(['property' => 'og:description', 'content' => $description]); +$this->registerMeta(['property' => 'og:image', 'content' => $product['image']]); + +// CSS files +$this->registerCssFile('/css/product.css'); +$this->registerCssFile('/css/responsive.css', WebView::POSITION_HEAD, [ + 'media' => 'screen and (max-width: 768px)', +]); + +// JavaScript files +$this->registerJsFile('/js/product-gallery.js', WebView::POSITION_END); +$this->registerJsFile('/js/shopping-cart.js', WebView::POSITION_END); + +// JavaScript variables +$this->registerJsVar('productData', $product); +$this->registerJsVar('cartApiUrl', '/api/cart'); + +// Inline JavaScript +$this->registerJs(' + document.addEventListener("DOMContentLoaded", function() { + initProductGallery(); + initShoppingCart(); + }); +', WebView::POSITION_END); + +// Page-specific styles +$this->registerCss(' + .product-special { + background: linear-gradient(45deg, #ff6b6b, #4ecdc4); + padding: 20px; + border-radius: 10px; + } +', WebView::POSITION_HEAD); +?> + +
+ +
+``` + +### Conditional Resource Loading + +Load resources based on conditions: + +```php +registerCssFile('/css/dark-theme.css'); +} else { + $this->registerCssFile('/css/light-theme.css'); +} + +// Admin-specific resources +if ($isAdmin) { + $this->registerCssFile('/css/admin-toolbar.css'); + $this->registerJsFile('/js/admin-functions.js'); +} + +// Role-based JavaScript configuration +$this->registerJsVar('userPermissions', [ + 'canEdit' => in_array($userRole, ['admin', 'editor']), + 'canDelete' => $userRole === 'admin', + 'canPublish' => in_array($userRole, ['admin', 'publisher']), +]); +?> +``` + +## Best Practices + +1. **Use appropriate positions**: Place CSS in `POSITION_HEAD`, JavaScript + at `POSITION_END` +2. **Minimize inline resources**: Prefer external files for better caching +3. **Use keys for duplicates**: Prevent duplicate resources with meaningful + keys +4. **Optimize loading**: Use `async` and `defer` attributes for non-critical + JavaScript +5. **Group related resources**: Keep related CSS and JS files together +6. **Use CDNs wisely**: Balance performance with reliability +7. **Validate meta tags**: Ensure proper SEO meta tags are set +8. **Consider security**: Be careful with inline scripts and CSP policies + +## Working with Asset Bundles + +For more complex asset management, consider using asset bundles: + +```php +// Register an asset bundle (covered in detail in the Assets guide) +$assetBundle = $this->assetManager->register(MainAsset::class); + +// Add all CSS files from the bundle +$this->addCssFiles($this->assetManager->getCssFiles()); + +// Add all JavaScript files from the bundle +$this->addJsFiles($this->assetManager->getJsFiles()); +``` diff --git a/src/it/guide/views/template-engines.md b/src/it/guide/views/template-engines.md new file mode 100644 index 00000000..708f6141 --- /dev/null +++ b/src/it/guide/views/template-engines.md @@ -0,0 +1,205 @@ +# Template engines + +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 or create your own custom renderers. + +PHP templates were described in the "[View](view.md)" guide section. + +## Twig Template Engine + +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. + +```bash +composer require yiisoft/view-twig +``` + +Now you can use `.twig` templates. For example, `views/site/about.twig`: + +```twig +{# Variable type hints for IDE support #} +{# @var user \App\Entity\User #} +{# @var posts \App\Entity\Post[] #} + + +``` + +### Twig Features + +**Automatic Escaping**: Twig automatically escapes variables for HTML context: + +```twig +{# Automatically escaped #} +

{{ title }}

+ +{# Raw output (use carefully) #} +
{{ content|raw }}
+``` + +**Filters and Functions**: Twig provides many built-in filters and functions: + +```twig +{# Date formatting #} + + +{# String manipulation #} +

{{ description|truncate(100) }}

+ +{# URL generation #} +Profile +``` + +**Template Inheritance**: Twig supports template inheritance: + +**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 %} +``` + +### Rendering Twig Templates + +Use Twig templates the same way as PHP templates: + +```php +// In your controller +public function about(): ResponseInterface +{ + return $this->viewRenderer->render('about.twig', [ + 'user' => $this->getCurrentUser(), + 'posts' => $this->getRecentPosts(), + ]); +} +``` + +## Custom Template Engines + +You can create custom template engines by implementing the +`TemplateRendererInterface`: + +```php + $value) { + $content = str_replace("{{$key}}", (string) $value, $content); + } + + return $this->parser->parse($content); + } +} +``` + +Register your custom renderer: + +```php +use Yiisoft\Container\Reference; + +// In configuration +'yiisoft/view' => [ + 'renderers' => [ + 'md' => Reference::to(App\View\MarkdownRenderer::class), + ], +], +``` + +Now you can use `.md` template files: + +**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 +``` + +## Choosing the Right Template Engine + +**Use PHP templates when:** +- You need maximum flexibility and performance +- Your team is comfortable with PHP +- You want to leverage existing PHP knowledge +- You need complex logic in templates (though this should be minimized) + +**Use Twig templates when:** +- You want stricter separation between logic and presentation +- You work with designers who prefer cleaner syntax +- You need automatic escaping and security features +- You want template inheritance and advanced features + +**Use custom templates when:** +- You have specific requirements not met by PHP or Twig +- You're working with specialized content formats +- You need integration with external template systems + +## Best Practices + +1. **Keep templates simple**: Move complex logic to controllers or services +2. **Always escape output**: Prevent XSS attacks by properly escaping + variables +3. **Use meaningful names**: Name your templates and variables clearly +4. **Organize templates**: Group related templates in subdirectories +5. **Document variables**: Always add type hints for better IDE support +6. **Avoid business logic**: Keep business logic in models and services diff --git a/src/it/guide/views/view-injections.md b/src/it/guide/views/view-injections.md new file mode 100644 index 00000000..5a7e5f03 --- /dev/null +++ b/src/it/guide/views/view-injections.md @@ -0,0 +1,116 @@ +# View injections + +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. + +The view injections could be used if you require `yiisoft/yii-view-renderer` +package: + + +```sh +composer require yiisoft/yii-view-renderer +``` + +## Configuration + +In config `params.php`: + + +```php +... +'yiisoft/yii-view' => [ + 'injections' => [ + Reference::to(ContentViewInjection::class), + Reference::to(CsrfViewInjection::class), + Reference::to(LayoutViewInjection::class), + ], + ], +``` + +## New injections + +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. + +```php +class MyCustomParametersInjection implements Yiisoft\Yii\View\Renderer\CommonParametersInjectionInterface +{ + // Class properties and methods will go here + + public function __construct(UserService $userService) + { + $this->userService = $userService; + } + + public function getCommonParameters(): array + { + return [ + 'siteName' => 'My Awesome Site', + 'currentYear' => date('Y'), + 'user' => $this->userService->getCurrentUser(), + ]; + } +} +``` + +Add your new Injection to `params.php`: + +```php +'yiisoft/yii-view' => [ + 'injections' => [ + ..., + Reference::to(MyCustomParametersInjection::class), + ], + ], +``` + +## Using Separate Injections for Different Layouts + +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. + +Create your custom ViewInjection for a specific layout: + +```php +readonly final class CartViewInjection implements CommonParametersInjectionInterface +{ + public function __construct(private Cart $cart) + { + } + + public function getCommonParameters(): array + { + return [ + 'cart' => $this->cart, + ]; + } +} +``` + +Add your new injection to `params.php` under specific layout name. In the +following example, it's `@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', // layout name for injection + + new CartViewInjection($cart) + ); + }), + ], + ], +``` diff --git a/src/it/guide/views/view.md b/src/it/guide/views/view.md new file mode 100644 index 00000000..c01a1c38 --- /dev/null +++ b/src/it/guide/views/view.md @@ -0,0 +1,315 @@ +# Viste + +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. + +```mermaid +flowchart LR + A[Data] --> V[View] + B[Template] --> V + V --> C[HTML] + C --> D[Browser] +``` + +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). + +## Installation + +For basic view functionality, you need the `yiisoft/view` package: + +```sh +composer require yiisoft/view +``` + +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: + +```sh +composer require yiisoft/yii-view-renderer +``` + +These packages are included by default in the `yiisoft/app` application +template. + +## Basic Concepts + +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`: + +```php + + +

The message is:

+``` + +Here `$message` is a view data that is passed when you render a template +with the help of `ViewRenderer`. For example, `src/Web/Echo/Action.php`: + +```php +viewRenderer->render(__DIR__ . '/template', [ + 'message' => $message, + ]); + } +} +``` + +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. + +## Working with layouts + +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`: + +```php +return [ + 'yiisoft/yii-view-renderer' => [ + 'viewPath' => null, + 'layout' => '@src/Web/Shared/Layout/Main/layout.php', + ], +]; +``` + +A typical layout file such as `src/Web/Shared/Layout/Main/layout.php` looks +like this: + +```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() ?> +``` + +In the template above `$applicationParams` is an array of parameters from +`config/common/application.php`. + +`$aliases` refers to [aliases component](../concept/aliases.md) that is used +to get the base URL of the application at the server for URLs. + +`$this` is an instance of the view that we use to get page title and output +assets. Both standard and custom. + +With `$assetManager->register(MainAsset::class);` we register an asset that defines `css` to include to the page. It is +automatically copied to `public/assets` on first use. It is not very useful for a single CSS file but becomes handy as +the number of assets grows. + +> [!IMPORTANT] +> No output in plain PHP templates is encoded you should not forget to use `Html::encode()` to prevent +XSS security vulnerabilities. + +More about what's available in layout could be read in +[yiisoft/view](https://github.com/yiisoft/view) documentation. + +### Rendering without layout + +Sometimes you need to render a view without a layout (for example, for AJAX +responses): + +```php +public function ajaxContent(): ResponseInterface +{ + return $this->viewRenderer + ->withLayout(null) + ->render('ajax-content', ['data' => $data]); +} + +// Or use the renderPartial method +public function ajaxContent(): ResponseInterface +{ + return $this->viewRenderer->renderPartial('ajax-content', ['data' => $data]); +} +``` + +## Nested Views and Partials + +### Rendering Sub-views + +You can render other views from within a view using the `$this->render()` method: + +```php + +
+ + render('_post_item', ['post' => $post]) ?> + +
+``` + +**src/Web/Post/_item.php** +```php + +
+

getTitle()) ?>

+

getExcerpt()) ?>

+ +
+``` + +### Using Blocks + +Blocks allow you to define content in one view and display it in another, +typically in layouts: + +```php +// In a view file +setBlock('sidebar', $this->render('_sidebar', ['items' => $sidebarItems])) ?> + +// In the layout file +hasBlock('sidebar')): ?> + + +``` + +## Rendering as String + +If you need the rendered content as a string instead of a PSR-7 response: + +```php +public function getEmailContent(): string +{ + return $this->viewRenderer->renderAsString('email/welcome', [ + 'user' => $user, + ]); +} +``` + +## View Events + +The view system triggers events during the rendering process that you can +listen to: + +```php +use Yiisoft\View\Event\WebView\BeforeRender; +use Yiisoft\View\Event\WebView\AfterRender; + +// Example event listener +final class ViewEventListener +{ + public function onBeforeRender(BeforeRender $event): void + { + // Add global CSS class based on view name + if (str_contains($event->getFile(), 'admin/')) { + $event->getView()->registerCssClass('admin-view'); + } + } + + public function onAfterRender(AfterRender $event): void + { + // Log rendering time + $this->logger->info('View rendered', [ + 'view' => $event->getFile(), + 'time' => $event->getRenderTime(), + ]); + } +} +``` diff --git a/src/it/guide/views/widget.md b/src/it/guide/views/widget.md new file mode 100644 index 00000000..9242128a --- /dev/null +++ b/src/it/guide/views/widget.md @@ -0,0 +1,767 @@ +# Widgets + +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. + +## Installation + +The widget functionality is provided by the `yiisoft/widget` package: + +```bash +composer require yiisoft/widget +``` + +For ready-made widgets (like forms, navigation, etc.), you can also install: + +```bash +composer require yiisoft/yii-widgets +``` + +These packages are included by default in the `yiisoft/app` application +template. + +## Basic Concepts + +### Widget Class + +A widget is a PHP class that extends the abstract `Widget` class and +implements a `render()` method that returns HTML content as a string. + +### Widget Factory + +The `WidgetFactory` is responsible for creating widget instances and can +inject dependencies through the DI container. + +### Widget Configuration + +Widgets can be configured with properties and methods, making them highly +customizable and reusable across different contexts. + +## Creating Custom Widgets + +### Simple Widget + +Here's a basic widget that displays an alert message: + +```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)]); + } +} +``` + +### Using the Widget + +```php + + +
+ message('Operation completed successfully!') + ->type('success') + ->closeable() ?> + + message('Please review the form errors below.') + ->type('danger') ?> +
+``` + +### Widget with Dependencies + +Widgets can use dependency injection for services: + +```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'] + ); + } +} +``` + +## Widget Factory Setup + +### Bootstrap Configuration + +Initialize the widget factory in your application bootstrap: + +**config/bootstrap.php** +```php + [ + 'type()' => ['info'], + 'closeable()' => [true], + ], + App\Widget\CardWidget::class => [ + 'headerClass()' => ['card-header bg-primary text-white'], + ], +]; + +WidgetFactory::initialize($container, $widgetDefaults); +``` + +### DI Container Configuration + +**config/web/di.php** +```php +use App\Widget\AlertWidget; +use App\Widget\UserMenuWidget; + +return [ + // Widget configurations can be defined here if needed + AlertWidget::class => static fn() => new AlertWidget(), + + UserMenuWidget::class => static fn( + App\Service\UserService $userService, + Yiisoft\Router\UrlGeneratorInterface $urlGenerator + ) => new UserMenuWidget($userService, $urlGenerator), +]; +``` + +## Advanced Widget Examples + +### Data List Widget + +A widget that displays a list of items with pagination: + +```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]); + } +} +``` + +Usage: + +```php + + +paginator($postPaginator) + ->containerClass('posts-list row') + ->itemClass('col-md-4 mb-3') + ->itemRenderer(function ($post) { + return $this->render('_post_card', ['post' => $post]); + }) ?> +``` + +### Form Widget + +A widget that simplifies form rendering: + +```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); + } +} +``` + +### Breadcrumb Widget + +A widget for navigation breadcrumbs: + +```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) { + // Last item (current page) - no link + $links[] = Html::span($item['label'], ['class' => 'breadcrumb-item active']); + } else { + // Regular breadcrumb item with 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 + ); + } +} +``` + +## Widget Best Practices + +### Configuration Pattern + +Use immutable configuration methods: + +```php +public function someProperty($value): self +{ + $new = clone $this; + $new->someProperty = $value; + return $new; +} +``` + +### Validation + +Validate widget configuration in the render method: + +```php +protected function render(): string +{ + if (empty($this->items)) { + throw new InvalidArgumentException('Items cannot be empty.'); + } + + // ... render logic +} +``` + +### HTML Encoding + +Always encode user data: + +```php +protected function render(): string +{ + return Html::div(Html::encode($this->userContent), [ + 'class' => 'user-content', + ]); +} +``` + +### Asset Management + +Register widget-specific assets: + +```php +assetManager->register(ChartWidgetAsset::class); + + // Render widget content + return $this->renderChart(); + } +} +``` + +## Using Widgets in Layouts + +Widgets are particularly useful in layouts for common UI elements: + +**views/layout/main.php** +```php + + + + + + + +
+ + +
+ +
+ +
+ +
+ +
+ + +``` + +## Testing Widgets + +### Unit Testing + +Test widget rendering logic: + +```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); + } +} +``` + +## Common Widget Patterns + +### Conditional Rendering + +```php +protected function render(): string +{ + if (!$this->shouldRender()) { + return ''; + } + + return $this->doRender(); +} + +private function shouldRender(): bool +{ + return !empty($this->items) && $this->isVisible; +} +``` + +### Template-based Rendering + +```php +protected function render(): string +{ + return $this->renderTemplate('widget-template', [ + 'items' => $this->items, + 'options' => $this->options, + ]); +} + +private function renderTemplate(string $template, array $data): string +{ + // Use a view renderer to render template files + return $this->viewRenderer->renderPartialAsString($template, $data); +} +``` + +### Event Integration + +```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(); +} +``` + +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. diff --git a/src/it/index.md b/src/it/index.md new file mode 100644 index 00000000..7e6a53f0 --- /dev/null +++ b/src/it/index.md @@ -0,0 +1,40 @@ +--- +features: + - + details: 'Yii offre la massima funzionalità aggiungendo il minor overhead possibile.' + icon: '' + title: Veloce + - + details: 'Le impostazioni predefinite e gli strumenti integrati ti aiutano a scrivere codice solido e sicuro.' + icon: '' + title: Sicuro + - + details: 'Scrivi più codice in meno tempo con API semplici ma potenti e la generazione di codice.' + icon: '' + title: Efficiente +hero: + actions: + - + link: guide/intro/what-is-yii.html + text: 'Per iniziare' + theme: brand + class: homeHero2 + image: + alt: Yii + src: /images/yii_logo.svg + name: 'Yii3 Framework' + tagline: 'Un framework semplice, potente e veloce. Scopri la guida moderna e definitiva a Yii che hai sempre desiderato.' + text: Documentazione +layout: home +--- + +

+ +- [La guida definitiva](guide/) — la guida completa che copre tutti gli + aspetti del framework. +- [Ricettario della comunità](cookbook/) — una raccolta di suggerimenti, + trucchi e soluzioni forniti dalla comunità per le attività di sviluppo Yii + più comuni. +- [Internals](internals/) — documentazione per gli sviluppatori che + contribuiscono al framework Yii stesso, comprese linee guida, flussi di + lavoro e best practice. diff --git a/src/it/internals/000-packages.md b/src/it/internals/000-packages.md new file mode 100644 index 00000000..b8f9434a --- /dev/null +++ b/src/it/internals/000-packages.md @@ -0,0 +1,84 @@ +# 000 — Packages + +Yii3 team divided the framework into several packages that conform to the +following agreements. + +For all packages, the GitHub repository name exactly matches the Packagist +package name. + +For a full list of packages and their building status, see [status page at +yiiframework.com](https://www.yiiframework.com/status/3.0). + +## Yii-specific packages (framework and extensions) + +- named `yiisoft/yii-something` or more specific: `yii-type-something` e.g.: + - modules: `yii-module-users`, `yii-module-pages` + - themes: `yii-theme-adminlte`, `yii-theme-hyde` + - widgets: `yii-widget-datepicker` + - ... +- titled as "Yii Framework ..." +- may have any dependencies and Yii-specific code + +## General purpose packages (libraries) + +- you can use these independently of Yii Framework +- named as `yiisoft/something` without yii-prefix +- titled as "Yii ..." +- must not have dependencies on any Yii-specific packages +- should have as fewer dependencies as possible + +## Configs and defaults + +The following applies to both Yii-specific packages and general purpose +packages: + +- Package may have `config` directory with Yii-specific defaults. +- Package may have "config-plugin" in "extra" section of `composer.json`. +- Package mustn't have dependencies in `require` section of `composer.json` + that are used in `config` only. +- You should namespace parameters with `vendor/package-name`: + +```php +return [ + 'vendor/package-name' => [ + 'param1' => 1, + 'param2' => 2, + ], +]; +``` + +## Versions + +All packages follow [SemVer](https://semver.org/) versioning: + +- `x.*.*` - incompatible API changes. +- `*.x.*` - add functionality (backwards-compatible). +- `*.*.x` - bug fixes (backwards-compatible). + +The first stable version should be 1.0.0. + +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. + +It's alright to use packages with different major versions together, as long +as they're compatible. + +## PHP versions support + +The support of PHP versions supported for a package depends on [PHP versions +life cycle](https://www.php.net/supported-versions.php). + +- Package versions with active support MUST support all PHP versions that + have active support. +- Both packages and application templates MUST have supported versions that + receive bug and security fixes. These SHOULD correspond to PHP versions + receiving security fixes. +- Packages and application templates MIGHT have supported versions that work + with unsupported PHP versions. +- Bumping the minimal PHP version in a package or an application template is + a minor change. + +## composer.json + +A logical OR operator in version ranges MUST use double pipe (`||`). For example: `"yiisoft/arrays": "^1.0 || ^2.0"`. diff --git a/src/it/internals/001-yii-values.md b/src/it/internals/001-yii-values.md new file mode 100644 index 00000000..b69a77e2 --- /dev/null +++ b/src/it/internals/001-yii-values.md @@ -0,0 +1,82 @@ +# 001 — Yii goal and values + +## Goal + +The Yii project aims to build and support _practical_ and _helpful_ tools +and community. + +## Values + +The values we express in our work support the goal. We try to + +- Be practical + - [High performance](#high-performance) + - [Sensible defaults and + flexibility](#sensible-defaults-and-flexibility) + - [Be practice-oriented](#be-practice-oriented) +- Be helpful + - [Be simple](#be-simple) + - [Be explicit](#be-explicit) + - [Be consistent](#be-consistent) + +## Be practical + +### High performance + +Performance is a necessary condition of practicality. Software shouldn't +waste machine resources or human resources. + +### Sensible defaults and flexibility + +We prefer sensible defaults and conventions that users can customize. We +seek a balance between flexibility, discipline and simplicity that meets +common needs. + +### Be practice-oriented + +We prefer practice to theory. For example: + +- Solutions for known use cases should avoid excess complexity by providing + only necessary flexibility. +- Standard implementations should take practical use into account. +- Experience is at least as useful as theory in guiding design. +- Context is critical in determining appropriateness. + +## Be helpful + +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. + +When the other principles conflict, we choose a solution that's more helpful +to the community. + +### Be simple + +Solutions should be simple and expressive: + +- We use as much complexity as needed and no more. +- We avoid ugly solutions unless there is no alternative. +- Fewer rules are better than more rules. + +### Be Explicit + +We prefer explicit, obvious solutions and code. Solutions should clearly +express exactly what they do. For example: + +- A straightforward solution is better than an abstract one unless the + abstraction has a practical purpose. +- Loud fails are better than silent fails or masking errors. +- Explicit casts are better than PHP type juggling, type hints are good. +- No magic unless necessary. + +### Be consistent + +We try to be consistent in: + +- Code style +- Naming +- Design +- Structure +- Values and goals diff --git a/src/it/internals/002-issue-workflow.md b/src/it/internals/002-issue-workflow.md new file mode 100644 index 00000000..58f8df1c --- /dev/null +++ b/src/it/internals/002-issue-workflow.md @@ -0,0 +1,27 @@ +# 002 — Issue workflow + +The process of handing incoming issues is the following: + +![Issue workflow schema](/images/internals/002-issue-workflow.svg) + +## Roles + +We've many roles: + +- Process managers - initially triage issues and manage labels. +- Decision makers - participate in discussions moving them to resolutions. +- Bug hunters - verifying bugs. +- Contributors - create code for pull requests. +- Code reviewers - review pull requests. + +A single person may take one or more roles in the issue-resolving process. + +## Labels + +We label issues to mark many things: current status, issue type, component +affected. Status labels speak for themselves. + +## Milestones + +Issues aren't assigned to milestones unless they're critical or there is a +likely good pull request exists. diff --git a/src/it/internals/003-roadmap.md b/src/it/internals/003-roadmap.md new file mode 100644 index 00000000..3ddf9f4b --- /dev/null +++ b/src/it/internals/003-roadmap.md @@ -0,0 +1,207 @@ +# 003 — Roadmap + +We want Yii 3 to: + +- Not limit a developer to choosing architecture. Allow anything from + "classic" MVC to DDD. +- Be based on the best practices such as SOLID, GRASP, etc. and teach them + to the community. +- Keep the most good things from Yii 2. +- Be more open to the global PHP community and infrastructure. + +## PSRs compliance + +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. + +### PSR-3 Logger + +Implemented as a [separate package that isn't dependent on a +framework](https://github.com/yiisoft/log). + +- [x] Framework packages should depend on interface only. +- [x] Split drivers into packages. +- [x] Clean-up code. +- [x] [Fix email target](https://github.com/yiisoft/log-target-email). + +### PSR-4 Autoloading + +- [x] Autoloading is fine already. +- [x] Document on how it works. + +### PSR-7 HTTP message + +- [x] Remove our own implementation. At least for now. +- [x] Framework packages should depend on interfaces only. + +### PSR-11 Container + +Implemented as a [separate package that isn't dependent on a +framework](https://github.com/yiisoft/di). + +- [x] Framework packages shouldn't use container directly. One should be + able to instantiate everything manually. +- [x] Finish refactoring. +- [x] Remove all framework-specific implementations from the package. Move + to a framework. +- [x] [Implement autoloader + fallback](https://github.com/yiisoft/di/issues/88) + +### PSR-12 Code style + +- [x] Make sure the code follows it. +- [x] Automate fixing style before release. + +### PSR-14 Event dispatcher + +- [x] [Implement as a separate + library](https://github.com/yiisoft/event-dispatcher). +- [x] Use in other packages. +- [x] Polish. + +### PSR-15 HTTP handlers + +- [x] Rewrite HTTP flow to PSR-7 request-response + formatting response via + emitter. +- [x] Offer SAPI emitter out of the box. +- [x] Make it possible to use alternative emitters such as RoadRunner. +- [x] Support middleware. +- [x] Implement filters as middleware: + - [x] [Rate limiting](https://github.com/yiisoft/yii-web/issues/63) + - [x] [Authentication](https://github.com/yiisoft/yii-web/issues/114) +- [x] Re-implement router w/ middleware support for route groups. +- [x] Filters should be middlewares. + +### PSR-16 Simple cache + +Implemented as a [separate package that isn't dependent on a +framework](https://github.com/yiisoft/cache). + +- [x] Framework packages should depend on interfaces only. +- [x] Split drivers into packages. +- [x] Clean-up code. + +### PSR-17 HTTP factories + +- [x] Use PSR factories. + +### PSR-18 HTTP client + +- [x] Remove our own implementation. At least for now. +- [x] Framework packages should depend on interfaces only. + +## Stricter types + +- [x] Make sure type hinting is used everywhere. +- [x] Make sure types are as definitive as possible. Avoid varying types if + possible. + +## Single application template + +- [x] Drop basic/advanced. +- [x] Create a [single application template that works out of the + box](https://github.com/yiisoft/app). + +## Router + +Implemented as a [separate package that isn't dependent on a +framework](https://github.com/yiisoft/router). + +- [x] DSL for configuration. +- [x] Ability to route to any callable. +- [x] Named routes. +- [x] Route groups w/ middleware support. + +## Best practices and SOLID compliance of all classes/packages + +- [x] Make sure interfaces follow the "interface segregation" principle. +- [x] Don't use public properties. +- [x] Don't use `init()`. +- [x] Don't inherit from `BaseObject` or `Component`. Remove these. +- [x] No globals. +- [x] No static calls except helpers that are final. +- [x] Prefer throwing exceptions to fixing input. + +## Development toolkit + +- [x] Release command line tool +- [x] Development command line tool (symlinks packages into usable + application) + +## Console + +- [x] Separate web and console application +- [x] Possibly eliminate base application (still needed) +- [x] Create an interface for the console (using Symfony one) +- [x] Implementation may be one of the popular ones (using Symfony one) +- [x] Ensure application can add commands via config + +## Documentazione + +- [ ] Follow best practices. +- [ ] Don't use the "MVC" term. +- [ ] Upgrading from Yii 2. + +## RBAC + +RBAC is implemented as [a framework-independent +package](https://github.com/yiisoft/rbac). + +- [x] Finish refactoring. +- [x] Make sure it follows best practices. +- [x] Split drivers into packages. + +## View + +View is implemented as [framework-independent +package](https://github.com/yiisoft/view). + +- [x] Finish refactoring ([see + issues](https://github.com/yiisoft/view/issues)). +- [x] Port widgets. +- [x] Rethink and implement active form widgets. +- [x] Implement caching widgets. + +## Data abstractions and grid + +- [x] Finish [data abstractions](https://github.com/yiisoft/data). +- [x] Port sort, use data abstractions. Should be part of + [yii-dataview](https://github.com/yiisoft/yii-dataview). +- [x] Port paging, use data abstractions. Should be part of + [yii-dataview](https://github.com/yiisoft/yii-dataview). +- [x] Port grid, use data abstractions. Should be part of + [yii-dataview](https://github.com/yiisoft/yii-dataview). +- [x] Port list, use data abstractions. Should be part of + [yii-dataview](https://github.com/yiisoft/yii-dataview). + +## Validators + +- [x] Finish [the main package](https://github.com/yiisoft/validator) + redesign +- [x] Port necessary validators + +## Debug toolbar + +- [x] Port debug toolbar. + +## Gii + +- [x] Port Gii. + +## Infrastructure + +- [x] Cover [config](https://github.com/yiisoft/config) with tests. +- [x] Release stable [config](https://github.com/yiisoft/config). + +## Others + +- [x] [Decide on + namespaces](https://forum.yiiframework.com/t/lowercase-or-camelcase-namespaces/124983/52). +- [x] [Clean up error + handler](https://github.com/yiisoft/yii2/issues/14348). Make sure the + error handler catches fatals and is using response. +- [x] Make validators independent of models to allow reusing them in + handlers. +- [x] [Split + IdentityInterface](https://github.com/yiisoft/yii2/issues/13825). diff --git a/src/it/internals/004-namespaces.md b/src/it/internals/004-namespaces.md new file mode 100644 index 00000000..8f623dbd --- /dev/null +++ b/src/it/internals/004-namespaces.md @@ -0,0 +1,23 @@ +# 004 — Namespaces + +Package namespace rules are the following: + +1. PascalCase is used for namespace parts. +2. Root vendor namespace is `Yiisoft`. +3. Package name parts are used in namespace. +4. Adjective is added to a noun and is a single part. + + +Some examples: + +| Package | Namespace | +|----------------------------|---------------------------| +| yiisoft/yii-web | Yiisoft\Yii\Web | +| yiisoft/di | Yiisoft\Di | +| yiisoft/db-mysql | Yiisoft\Db\Mysql | +| yiisoft/friendly-exception | Yiisoft\FriendlyException | + +## References + +- [International forum + discussion](https://forum.yiiframework.com/t/use-yiisoft-as-a-root-namespace-instead-of-yii-for-yii-3-packages/125734) diff --git a/src/it/internals/005-development-tool.md b/src/it/internals/005-development-tool.md new file mode 100644 index 00000000..961d7e7e --- /dev/null +++ b/src/it/internals/005-development-tool.md @@ -0,0 +1,51 @@ +# 005 — Yii development tool + +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). + +``` +$ ./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 +``` + +There are many commands available. The most important ones are `install` and +`update`. What it does is: + +1. 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. +2. 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. + +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. + +A [detailed example](https://github.com/yiisoft/yii-dev-tool#usage-example) +of using the tool is available in its README. diff --git a/src/it/internals/006-git-commit-messages.md b/src/it/internals/006-git-commit-messages.md new file mode 100644 index 00000000..18a29f3c --- /dev/null +++ b/src/it/internals/006-git-commit-messages.md @@ -0,0 +1,18 @@ +# 006 — Git commit messages + + +## Subject line + +- Use `#123` to reference issue by number +- Use imperative mood that's `Fix`, not `Fixed` +- Don't add a period at the end +- Use `[skip ci]` if there is no need to run unit tests +- Start with a capital letter +- Limit to 50 characters + +## Body + +Use the message body **if** you need an extra explanation. Explain why, not +how. + +- Limit line length to 72 characters diff --git a/src/it/internals/007-exceptions.md b/src/it/internals/007-exceptions.md new file mode 100644 index 00000000..f40cf62e --- /dev/null +++ b/src/it/internals/007-exceptions.md @@ -0,0 +1,16 @@ +# 007 — Exceptions + +- Throw exceptions instead of returning an error code. +- Exception class name must be suffixed with `Exception`. +- Use grammatically correct error messages including ending punctuation, + that's most exceptions must end with a period. +- `\InvalidArgumentException` must be used directly. There should be no + exceptions inherited from it. +- `\InvalidArgumentException` must never be caught. + +## References + +- [International community discussion and + poll](https://forum.yiiframework.com/t/naming-exceptions/126613/6) +- [Russian community discussion and + poll](https://yiiframework.ru/forum/viewtopic.php?f=39&t=51290) diff --git a/src/it/internals/008-interfaces.md b/src/it/internals/008-interfaces.md new file mode 100644 index 00000000..bfe91968 --- /dev/null +++ b/src/it/internals/008-interfaces.md @@ -0,0 +1,10 @@ +# 008 — Interfaces + +- Interface name should be suffixed with `Interface`. + +## References + +- [International community discussion and + poll](https://forum.yiiframework.com/t/naming-interfaces/126612/5) +- [Russian community discussion and + poll](https://yiiframework.ru/forum/viewtopic.php?f=39&t=51289) diff --git a/src/it/internals/009-design-decisions.md b/src/it/internals/009-design-decisions.md new file mode 100644 index 00000000..a9e0f54b --- /dev/null +++ b/src/it/internals/009-design-decisions.md @@ -0,0 +1,89 @@ +# 009 — Design Decisions + +In this document, we list important design decisions taken during Yii3 +development. + +## Remove magic properties + +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. + +The main reason for removal in Yii 3 is that it resulted in using public +properties everywhere, thus lack of encapsulation and code fragility. + +## Remove the service locator + +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. + +Yii 3 relies on dependency injection only lowering coupling significantly +and making code way more testable. + +## Extract general packages + +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. + +As part of Yii 3 packages such as cache, RBAC, view, etc. were extracted +into framework-independent packages. Benefits are: + +- Increased usage and contribution +- Yii team could delegate maintenance +- Independent releases are possible + +## Adopt PSRs + +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. + +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. + +By implementing PSRs in general packages, we allow these to be used in more +projects, thus raising the contribution level. + +## Improve DI container + +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. + +In Yii3, we ensured that container can be used to conveniently configure any +PHP class. + +That should result in the absence of Yii-specific wrapper packages and more +direct usages of Composer packages. + +## Adopt strict types + +Strict types were introduced because: + +- PHP 7 is now mainstream +- While they solve no significant Yii 2 problems, they help to avoid many + day-to-day development issues + +## Adopt SemVer + +Yii 2 has its own version policy. Problems: + +- It wasn't standard +- Composer relies on SemVer +- It's hard to support a framework built on top of packages if the + versioning policy isn't strict + +## Prevent validators mutating data + +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. + +[See related +discussion](https://forum.yiiframework.com/t/saving-or-killing-non-validation-in-validators/126086). diff --git a/src/it/internals/010-code-style.md b/src/it/internals/010-code-style.md new file mode 100644 index 00000000..6cacc4e9 --- /dev/null +++ b/src/it/internals/010-code-style.md @@ -0,0 +1,198 @@ +# 010 — Code style + +Code formatting used in Yii 3 packages is based on +[PSR-1](https://www.php-fig.org/psr/psr-1/) and +[PSR-12](https://www.php-fig.org/psr/psr-12/) with extra rules added on top +of it. + +## Names + +- Use English only. +- Use camelCase notation, including abbreviations (e.g., `enableIdn`). +- Use the shortest possible, but an explanatory name. +- Never trim or abbreviate a name. +- Postfix classes, interfaces, traits and variables, which is a + [collection](https://en.wikipedia.org/wiki/Collection_(abstract_data_type)), + with `Collection`. + +## Types + +- Declare [argument and return + types](https://www.php.net/manual/en/migration70.new-features.php) where + possible. +- [Use types for properties](https://wiki.php.net/rfc/typed_properties_v2). +- Use strict typing. Avoid mixed and union types where possible except + compatible types such as `string|Stringable`. + +## Comments + +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. + +Method comment is necessary except it adds nothing to what method name and +signature already has. + +Class comment should describe the purpose of the class. + +[See +PHPDoc](https://github.com/yiisoft/docs/blob/master/014-docs.md#phpdoc). + +## Formatting + +### No alignment + +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. + +```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; + } +} +``` + +### Chain calls + +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: + +```php +$object + ->withName('test') + ->withValue(87) + ->withStatus(Status::NEW) + ->withAuthor($author) + ->withDeadline($deadline); +``` + +If it's a short chain, it's alright for it to be on a single line: + +```php +$object = $object->withName('test'); +``` + +## Strings + +- When no variables involved, use `'Hello!'` +- To get variables into string prefer `"Hello, $username!"` + +## Classes and interfaces + +### Final by default + +Classes should be `final` by default. + +### Private by default + +Constants, properties and methods should be private by default. + +### Composition over inheritance + +Prefer [composition to inheritance](guide/en/concept/di-container.md). + +### Property, constant and method order + +Order should be the following: + +- Constants +- Properties +- Methods + +Within each category, items should be sorted by visibility: + +- public +- protected +- private + +### Abstract classes + +Abstract classes *shouldn't* be prefixed or postfixed with `Abstract`. + +#### Immutable methods + +Immutable method convention is the following: + +```php +public function withName(string $name): self +{ + $new = clone $this; + $new->name = $name; + return $new; +} +``` + +1. Cloned object name is `$new`. +2. Return type is `self`. + +#### Boolean check methods + +Methods that are there to check if something is true should be named like +the following: + +```php +public function isDeleted(): bool; +public function hasName(): bool; +public function canDoIt(): bool; +``` + +#### Flags in methods + +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. + +```php +public function login(bool $refreshPage = true): void; +``` + +It is better to be two methods: + +```php +public function login(): void; +public function refreshPage(): void; +``` + +## Variables + +Add an underscore (`_`) prefix for unused variables. For example: + +```php +foreach ($items as $key => $_value) { + echo $key; +} +``` + +## Imports + +Prefer importing classes and functions to using fully qualified names: + +```php +use Yiisoft\Arrays\ArrayHelper; +use Yiisoft\Validator\DataSetInterface; +use Yiisoft\Validator\HasValidationErrorMessage; +use Yiisoft\Validator\Result; + +use function is_iterable; +``` + +## Additional conventions + +- [Namespaces](004-namespaces.md) +- [Exceptions](007-exceptions.md) +- [Interfaces](008-interfaces.md) + diff --git a/src/it/internals/011-error-correction.md b/src/it/internals/011-error-correction.md new file mode 100644 index 00000000..8e2f2b46 --- /dev/null +++ b/src/it/internals/011-error-correction.md @@ -0,0 +1,5 @@ +# 011 — Error correction + +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. diff --git a/src/it/internals/012-tests.md b/src/it/internals/012-tests.md new file mode 100644 index 00000000..e09aa6d2 --- /dev/null +++ b/src/it/internals/012-tests.md @@ -0,0 +1,18 @@ +# 012 — Tests + +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. + +- Test class should be marked as `final` by default. +- `@test` annotation must not be used, prefix methods with `test`. +- The test method name must reflect the purpose of the test. +- "should" must not be used in the test method name. +- If necessary, the test method phpdoc may describe the desired behavior. +- The test must follow AAA: first arrange the necessary preconditions, then + act, then assert expected results. +- There must be one test case per test method that's a single AAA. +- Test must use public API. Private properties or methods shouldn't be + accessed, assumptions on internals of the class tested shouldn't be made. +- Tests shouldn't rely on composer-config-plugin and DI container unless + necessary. diff --git a/src/it/internals/013-code-review.md b/src/it/internals/013-code-review.md new file mode 100644 index 00000000..a363f954 --- /dev/null +++ b/src/it/internals/013-code-review.md @@ -0,0 +1,33 @@ +# 013 — Code review + +Code reviews are essential for the success of the project and are as +important as contributing code. + +Reviews are handled via GitHub pull requests. When the request is ready for +review, the "status: code review" label is added to it. + +[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. + +## Guidelines + +- Check out the pull request branch, open the project in the IDE, get a big + picture. +- Does the pull request make sense overall? +- Run tests and/or application using code from the pull request. Are these + OK? +- Read all lines of code in the pull request. +- Could it be done simpler? +- Are there security issues? +- Are there performance issues? +- When leaving comments, be polite. +- Avoid code-formatting comments. + +## Mandatory parts + +- [ ] Tests that fail without code and pass with code. +- [ ] Type hints. +- [ ] `declare(strict_types=1)`. +- [ ] Documentation: phpdoc, yiisoft/docs. +- [ ] Changelog entry (if package is stable). diff --git a/src/it/internals/014-docs.md b/src/it/internals/014-docs.md new file mode 100644 index 00000000..f344647b --- /dev/null +++ b/src/it/internals/014-docs.md @@ -0,0 +1,194 @@ +# 014 — Documentation + +Documentation is one of the most important parts of Yii. + +## Package documentation + +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. + +Some indicators that it's time to create `docs`: + +1. There is a need for translation. +2. Many topics exist. Each of these is big by itself. + +If the total length of readme is less than about 200 lines, it's fine to +keep documentation in the readme. + +## Definitive guide + +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. + +The guide should follow [Micosoft style +guide](https://learn.microsoft.com/en-us/style-guide/welcome/). + +### Translation + +The definitive guide uses [po4a](https://github.com/mquinson/po4a) in GitHub Action for translations. + +Translation algorithm: + +- 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. +- 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. +- 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. +- Translate necessary strings and push the changes +- Open a pull request to the main repository + +> [!CAUTION] +> Do not change the translation in files in `/guide/{lang}` manually. + +If you have changed English and want to update translations: + +- Open a pull request to the main repository +- Pull updated branch after successful completion of workflow `Update docs + translation` in GitHub Action +- Update translation in `.po` files by `Poedit` +- Push changes + +## Blocks + +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): + +``` +> [!NOTE] +> Useful information that users should know, even when skimming content. + +> [!TIP] +> Helpful advice for doing things better or more easily. + +> [!IMPORTANT] +> Key information users need to know to achieve their goal. + +> [!WARNING] +> Urgent info that needs immediate user attention to avoid problems. + +> [!CAUTION] +> Advises about risks or negative outcomes of certain actions. +``` + +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: + +```json +{ + "Note": "Hinweis", + "Tip": "Tipp", + "Important": "Wichtig", + "Warning": "Achtung", + "Caution": "Vorsicht" +} +``` + +## PHPDoc + +PHPDoc mustn't be added if it doesn't add anything to what it describes. The +following is a bad example: + +```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(); + } +} +``` + +PHPDoc, if present, should describe the purpose of the element it's added +for. + +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. + +Example of incorrect code: + +```php +/** + * @see SOME_CONST + * @see $prop + * @see doSomething() + */ +final class Example +{ + public const SOME_CONST = ''; + public int $prop; + public function doSomething(): void {} +} +``` + +Example of a valid code: + +```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 {} +} +``` + +## Readme checklist + +Each package readme should be placed into `README.md` and contain the +following: + +- [ ] Logo. +- [ ] Short description of the package. What does it do? +- [ ] Quality badges (build, code coverage). +- [ ] Screenshot (if applicable). +- [ ] Requirements. +- [ ] Installation. Usually `composer require`. +- [ ] Getting started. One or two common usage examples are demonstrated. +- [ ] Configuration. +- [ ] Contributing. It should contain a link to guidelines. +- [ ] Running tests. +- [ ] License. diff --git a/src/it/internals/015-phpstorm.md b/src/it/internals/015-phpstorm.md new file mode 100644 index 00000000..7995ffc6 --- /dev/null +++ b/src/it/internals/015-phpstorm.md @@ -0,0 +1,70 @@ +# 015 — PhpStorm metadata and attributes + +## PhpStorm metadata + +[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. + +We use the following set of coding styles for metadata. + +### Metadata location + +- Metadata should be placed in `/.phpstorm.meta.php` directory. +- Configuration should be split into files. Each file should be named after + a class it configures. + +> [!NOTE] +> There is no support for subdirectories in PhpStorm yet. + +### Constants + +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: + +```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, +); +``` + +## PhpStorm attributes + +[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: + +```shell +composer require --dev jetbrains/phpstorm-attributes +``` + +### Using with ComposerRequireChecker + +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: + +```json +{ + "symbol-whitelist": [ + "JetBrains\\PhpStorm\\ExpectedValues", + "JetBrains\\PhpStorm\\Pure" + ] +} +``` diff --git a/src/it/internals/016-security-workflow.md b/src/it/internals/016-security-workflow.md new file mode 100644 index 00000000..64e3184d --- /dev/null +++ b/src/it/internals/016-security-workflow.md @@ -0,0 +1,50 @@ +# 016 — Security workflow + +Security issues are typically sent via [a security +form](https://www.yiiframework.com/security). + +If an issue is reported directly to a public page such as a repository issue or a forum topic, get the message +and delete the issue. Say thanks to the reporter and point to the security form for next time. + +## Verify + +Verify that the issue is valid. Request more information if needed. + +## Add security advisory + +Create a draft GitHub security advisory. + +### Find out severity + +1. Get CVSS score using [NVD + calculator](https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator). +2. Choose severity based on the [rating + scale](https://www.first.org/cvss/specification-document#Qualitative-Severity-Rating-Scale). + +### Give credit to the reporter + +Ask the reporter if he wants a credit for finding the issue. If so, point to +his GitHub account. + +## Request a CVE number + +When you're ready, request a CVE. + +## Prepare a patch + +Prepare a pull request fixing the issue. GitHub allows doing it in a private +fork. + +## Wait till the CVE number is allocated + +It usually takes several days. + +## Release + +- Merge the patch pull request right before tagging the next package + release. +- Publish security advisory. +- 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. diff --git a/src/it/internals/017-tags.md b/src/it/internals/017-tags.md new file mode 100644 index 00000000..637e1805 --- /dev/null +++ b/src/it/internals/017-tags.md @@ -0,0 +1,43 @@ +# 017 - Tags + +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. + +## Class names + +- Tags aren't postfixed or prefixed unless it's an abstract base class. +- If the tag represents a specification, use a name used in the + specification. + +## Inheritance + +Inheritance is allowed with some restrictions: + +- If a class isn't abstract, it should be final. +- Hierarchy should be kept as linear as possible. + +## Immutability + +Tags should: + +- Have no state. +- Be immutable. Every method that modifies a setting returns a clone with + the setting changed. +- Be free of side effects. Many calls of the same method with the same + argument should give the same result. + +## Methods + +### Names + +- Unlike other classes, methods that return a clone of the object with some + properties modified aren't prefixed. +- Keep method names as short as possible but don't hurt readability. +- If the tag represents a specification, use a name used in the + specification. + +### Boolean flags + +The method that corresponds to the boolean attribute should be named after +the attribute and accept a boolean flag argument. diff --git a/src/it/internals/018-widgets.md b/src/it/internals/018-widgets.md new file mode 100644 index 00000000..4fb6bec2 --- /dev/null +++ b/src/it/internals/018-widgets.md @@ -0,0 +1,36 @@ +# 018 - Widgets + +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. + +## Class names + +Widgets aren't postfixed or prefixed. + +## Inheritance + +Inheritance is allowed with some restrictions: + +- If a class isn't abstract, it should be final. +- Hierarchy should be kept as linear as possible. + +## Immutability + +Widgets should: + +- Have no state. +- Be immutable. + +## Methods + +### Names + +- Unlike other classes, methods that return a clone of the object with some + properties modified aren't prefixed. +- Keep method names as short as possible but don't hurt readability. + +### Boolean flags + +The method that corresponds to the boolean attribute should be named after +the attribute and accept a boolean flag argument. diff --git a/src/it/internals/019-view-code-style.md b/src/it/internals/019-view-code-style.md new file mode 100644 index 00000000..c5a19173 --- /dev/null +++ b/src/it/internals/019-view-code-style.md @@ -0,0 +1,46 @@ +# 019 — View code style + +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. + +## Heading + +View file heading is used to place phpdoc describing variables available and +to import classes: + +```php + +

getTitle()) ?>

+

getDescription()) ?>

+ +``` + +## Short echo + +Short echo is preferred: + +```php + +``` + +## Class methods + +All class methods used in view files must be public regardless if the view +is rendered by the class itself. diff --git a/src/it/internals/020-package-release.md b/src/it/internals/020-package-release.md new file mode 100644 index 00000000..de037e15 --- /dev/null +++ b/src/it/internals/020-package-release.md @@ -0,0 +1,44 @@ +# 020 — Package release + +## Criteria + +- No critical issues. +- Public API changes aren't likely. Some time passed w/o issues reported + that may require API changes. +- All dependencies are stable. +- Close to 100% test coverage with, ideally, a 100% MSI score. +- README is alright. +- Everything is type-hinted unless special cases. +- Psalm analysis passes on at least level 2. +- phpdoc is alright. +- Public API is alright. + +## Release instruction + +Release a package via [Yii Development Tool](005-development-tool.md). + +1. Check that you can sign commits locally (see +[Signing commits](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits)). + +2. Pull last changes from the `master` branch: + +```shell +./yii-dev git/checkout master package-name +./yii-dev git/pull package-name +``` + +3. Check the package for compliance with the criteria above. + +4. Run `release/make` command: + +```shell +./yii-dev release/make package-name +``` + +5. Select the version type (major, minor or path). + +6. On the question "Push commits and tags, and release on GitHub?" check a + diff. If the diff is alright, answer "yes." + +7. For major and minor releases, add a record with release notes on [Yii + Framework News](https://www.yiiframework.com/news). diff --git a/src/it/internals/021-changelog-upgrade.md b/src/it/internals/021-changelog-upgrade.md new file mode 100644 index 00000000..ee291e73 --- /dev/null +++ b/src/it/internals/021-changelog-upgrade.md @@ -0,0 +1,67 @@ +# 021 — Changelog and upgrade + +For all released packages, we've a detailed changelog and upgrade guide. + +## Changelog + +Changelog is written for each version released. The file name is +`CHANGELOG.md`. The format is the following: + +```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. +``` + +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: + +- New — New features. +- Chg — General changes. +- Enh — Existing feature enhancements. +- Bug — Bug fixes. + +In the changelog file lines should be ordered as New, Chg, Enh, Bug. + +"#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 `@`. + +## Upgrade + +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. + +The file name is `UPGRADE.md`. The format is the following: + +```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/it/internals/022-config-groups.md b/src/it/internals/022-config-groups.md new file mode 100644 index 00000000..8193bf82 --- /dev/null +++ b/src/it/internals/022-config-groups.md @@ -0,0 +1,73 @@ +# 022 — Config groups + +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`. + +## Config group name postfixes + +- "web" postfix applies to web only that's classic server HTML generation, + REST, RPC, etc. +- "console" postfix applies to console +- If there's no postfix, it's "common" and applies to both web and console +- "web" and "console" may override what's defined in "common" + +## Parameters + +Application config parameters that are used in all configs. + +- `params` — common parameters +- `params-web` — web application parameters +- `params-console` — console application parameters + +## Container + +Configuration for [yiisoft/di](https://github.com/yiisoft/di). + +### Definitions + +- `di` — common container definitions +- `di-web` — web container definitions +- `di-console` — console container definitions + +### Providers + +- `di-providers` — common container providers +- `di-providers-web` — web container providers +- `di-providers-console` — console container providers + +### Delegates + +- `di-delegates` — common container delegates +- `di-delegates-web` — web container delegates +- `di-delegates-console` — console container delegates + +### Tags + +- `di-tags` — common container tags +- `di-tags-web` — web container tags +- `di-tags-console` — console container tags + +## Events + +Configuration for [yiisoft/yii-event](https://github.com/yiisoft/yii-event). + +- `events` — common events +- `events-web` — web events +- `events-console` — console events + +## Bootstrap + +Application bootstrapping for +[yiisoft/yii-runner](https://github.com/yiisoft/yii-runner). + +- `bootstrap` — common bootstrap +- `bootstrap-web` — web bootstrap +- `bootstrap-console` — console bootstrap + +## Others + +- `routes` — [yiisoft/router](https://github.com/yiisoft/router) routes +- `widgets` — [yiisoft/widget](https://github.com/yiisoft/widget) default + widgets configuration diff --git a/src/it/internals/index.md b/src/it/internals/index.md new file mode 100644 index 00000000..e512a121 --- /dev/null +++ b/src/it/internals/index.md @@ -0,0 +1,44 @@ +# Yii Framework Internals + +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. + +## Table of Contents + +- [000 — Packages](000-packages.md) - Package structure and naming + conventions +- [001 — Yii goal and values](001-yii-values.md) - Project goals and core + values +- [002 — Issue workflow](002-issue-workflow.md) - How to handle issues +- [003 — Roadmap](003-roadmap.md) - Development roadmap and future plans +- [004 — Namespaces](004-namespaces.md) - Namespace conventions +- [005 — Yii development tool](005-development-tool.md) - Development tools + for Yii packages +- [006 — Git commit messages](006-git-commit-messages.md) - Commit message + format +- [007 — Exceptions](007-exceptions.md) - Exception handling guidelines +- [008 — Interfaces](008-interfaces.md) - Interface design principles +- [009 — Design Decisions](009-design-decisions.md) - Architectural and + design decisions +- [010 — Code style](010-code-style.md) - PHP code style guidelines +- [011 — Error correction](011-error-correction.md) - Error handling and + correction +- [012 — Tests](012-tests.md) - Testing guidelines and practices +- [013 — Code review](013-code-review.md) - Code review process and + guidelines +- [014 — Documentation](014-docs.md) - Documentation writing guidelines +- [015 — PhpStorm metadata and attributes](015-phpstorm.md) - PhpStorm + integration +- [016 — Security workflow](016-security-workflow.md) - Security issue + handling +- [017 — Tags](017-tags.md) - Git tagging conventions +- [018 — Widgets](018-widgets.md) - Widget development guidelines +- [019 — View code style](019-view-code-style.md) - Code style for view + templates +- [020 — Package release](020-package-release.md) - Release process for + packages +- [021 — Changelog and upgrade](021-changelog-upgrade.md) - Maintaining + changelogs and upgrade notes +- [022 — Config groups](022-config-groups.md) - Configuration group + organization