diff --git a/application/bg/ajax.texy b/application/bg/ajax.texy
index 3b98231de7..04cc36448d 100644
--- a/application/bg/ajax.texy
+++ b/application/bg/ajax.texy
@@ -77,6 +77,12 @@ npm install naja
```
+Първо трябва да [инициализирате |https://naja.js.org/#/guide/01-install-setup-naja?id=initialization] библиотеката:
+
+```js
+naja.initialize();
+```
+
За да превърнете обикновена връзка (сигнал) или подаване на форма в AJAX заявка, просто маркирайте съответната връзка, форма или бутон с класа `ajax`:
```html
diff --git a/application/bg/bootstrap.texy b/application/bg/bootstrap.texy
index a7989b2d15..2ac3dc2e99 100644
--- a/application/bg/bootstrap.texy
+++ b/application/bg/bootstrap.texy
@@ -20,18 +20,44 @@ use Nette\Bootstrap\Configurator;
class Bootstrap
{
- public static function boot(): Configurator
+ private Configurator $configurator;
+ private string $rootDir;
+
+ public function __construct()
+ {
+ $this->rootDir = dirname(__DIR__);
+ // Конфигураторът отговаря за настройката на средата на приложението и услугите.
+ $this->configurator = new Configurator;
+ // Задайте директорията за временни файлове, генерирани от Nette (напр. компилирани шаблони)
+ $this->configurator->setTempDirectory($this->rootDir . '/temp');
+ }
+
+ public function bootWebApplication(): Nette\DI\Container
{
- $appDir = dirname(__DIR__);
- $configurator = new Configurator;
- //$configurator->setDebugMode('secret@23.75.345.200');
- $configurator->enableTracy($appDir . '/log');
- $configurator->setTempDirectory($appDir . '/temp');
- $configurator->createRobotLoader()
+ $this->initializeEnvironment();
+ $this->setupContainer();
+ return $this->configurator->createContainer();
+ }
+
+ private function initializeEnvironment(): void
+ {
+ // Nette е интелигентен и режимът за разработка се включва автоматично,
+ // или можете да го включите за определен IP адрес, като разкоментирате следния ред:
+ // $this->configurator->setDebugMode('secret@23.75.345.200');
+
+ // Активира Tracy: най-добрият инструмент за отстраняване на грешки "швейцарско ножче".
+ $this->configurator->enableTracy($this->rootDir . '/log');
+
+ // RobotLoader: автоматично зарежда всички класове в дадената директория
+ $this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
- $configurator->addConfig($appDir . '/config/common.neon');
- return $configurator;
+ }
+
+ private function setupContainer(): void
+ {
+ // Зареждане на конфигурационни файлове
+ $this->configurator->addConfig($this->rootDir . '/config/common.neon');
}
}
```
@@ -40,16 +66,15 @@ class Bootstrap
index.php .[#toc-index-php]
===========================
-В случая на уеб приложения началният файл е `index.php`, който се намира в публичната директория `www/`. Той позволява на класа `Bootstrap` да инициализира средата и връща `$configurator`, който създава контейнера DI. След това тя извлича услугата `Application`, която стартира уеб приложението:
+Началният файл за уеб приложенията е `index.php`, разположен в публичната директория `www/`. Той използва класа `Bootstrap` за инициализиране на средата и създаване на контейнер DI. След това получава услугата `Application` от контейнера, която стартира уеб приложението:
```php
-// инициализиране на средата + получаване на обект Configurator
-$configurator = App\Bootstrap::boot();
-// създаване на DI-контейнер
-$container = $configurator->createContainer();
-// DI-контейнерът ще създаде обект Nette\Application\Application
+$bootstrap = new App\Bootstrap;
+// Иницииране на средата + създаване на контейнер DI
+$container = $bootstrap->bootWebApplication();
+// Контейнерът DI създава обект Nette\Application\Application
$application = $container->getByType(Nette\Application\Application::class);
-//стартиране на приложението Nette
+// Стартирайте приложението Nette и обработете входящата заявка
$application->run();
```
@@ -66,19 +91,19 @@ Nette прави разграничение между два основни р
Ако искате да активирате режима за разработка в други случаи, например за програмисти, които имат достъп от определен IP адрес, можете да използвате `setDebugMode()`:
```php
-$configurator->setDebugMode('23.75.345.200'); // един или повече IP адреси
+$this->configurator->setDebugMode('23.75.345.200'); // един или повече IP адреси
```
Определено препоръчваме да комбинирате IP адреса с "бисквитка". Ще съхраним тайния токен в "бисквитката" `nette-debug', например, `secret1234`, а режимът за разработка ще бъде активиран за програмистите с тази комбинация от IP и "бисквитка".
```php
-$configurator->setDebugMode('secret1234@23.75.345.200');
+$this->configurator->setDebugMode('secret1234@23.75.345.200');
```
Можете да деактивирате напълно режима за разработчици, дори за localhost:
```php
-$configurator->setDebugMode(false);
+$this->configurator->setDebugMode(false);
```
Обърнете внимание, че стойността `true` активира плътно режима за разработчици, което никога не трябва да се случва на производствен сървър.
@@ -90,7 +115,7 @@ $configurator->setDebugMode(false);
За да улесним дебъгването, ще включим чудесния инструмент [Tracy |tracy:]. В режим за разработчици той визуализира грешките, а в производствен режим записва грешките в определена директория:
```php
-$configurator->enableTracy($appDir . '/log');
+$this->configurator->enableTracy($this->rootDir . '/log');
```
@@ -100,7 +125,7 @@ $configurator->enableTracy($appDir . '/log');
Nette използва кеш за DI-контейнер, RobotLoader, шаблони и др. Затова е необходимо да се зададе пътят до директорията, в която се съхранява кешът:
```php
-$configurator->setTempDirectory($appDir . '/temp');
+$this->configurator->setTempDirectory($this->rootDir . '/temp');
```
В Linux или macOS задайте [разрешения за запис |nette:troubleshooting#Setting-Directory-Permissions] за директориите `log/` и `temp/`.
@@ -112,7 +137,7 @@ RobotLoader .[#toc-robotloader]
Обикновено искаме да заредим класовете автоматично с помощта на [RobotLoader |robot-loader:], така че трябва да го стартираме и да му позволим да зареди класовете от директорията, в която се намира `Bootstrap.php` (т.е. `__DIR__`) и всички негови поддиректории:
```php
-$configurator->createRobotLoader()
+$this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
```
@@ -126,7 +151,7 @@ $configurator->createRobotLoader()
Конфигураторът ви позволява да зададете часовата зона за вашето приложение.
```php
-$configurator->setTimeZone('Europe/Prague');
+$this->configurator->setTimeZone('Europe/Prague');
```
@@ -143,16 +168,17 @@ $configurator->setTimeZone('Europe/Prague');
Файловете за конфигурация се зареждат с помощта на `addConfig()`:
```php
-$configurator->addConfig($appDir . '/config/common.neon');
+$this->configurator->addConfig($this->rootDir . '/config/common.neon');
```
Методът `addConfig()` може да се извика няколко пъти, за да се добавят няколко файла.
```php
-$configurator->addConfig($appDir . '/config/common.neon');
-$configurator->addConfig($appDir . '/config/services.neon');
+$configDir = $this->rootDir . '/config';
+$this->configurator->addConfig($configDir . '/common.neon');
+$this->configurator->addConfig($configDir . '/services.neon');
if (PHP_SAPI === 'cli') {
- $configurator->addConfig($appDir . '/config/cli.php');
+ $this->configurator->addConfig($configDir . '/cli.php');
}
```
@@ -169,7 +195,7 @@ if (PHP_SAPI === 'cli') {
Параметрите, използвани в конфигурационните файлове, могат да бъдат дефинирани [в раздела `parameters` |dependency-injection:configuration#parameters] и да бъдат взети (или презаписани) от метода `addStaticParameters()` (той има псевдоним `addParameters()`). Важно е, че различните стойности на параметрите водят до генериране на допълнителни DI-контейнери, т.е. допълнителни класове.
```php
-$configurator->addStaticParameters([
+$this->configurator->addStaticParameters([
'projectId' => 23,
]);
```
@@ -183,7 +209,7 @@ $configurator->addStaticParameters([
Възможно е също така да се добавят динамични параметри към контейнер. Различните им стойности, за разлика от статичните параметри, не генерират нови контейнери DI.
```php
-$configurator->addDynamicParameters([
+$this->configurator->addDynamicParameters([
'remoteIp' => $_SERVER['REMOTE_ADDR'],
]);
```
@@ -191,7 +217,7 @@ $configurator->addDynamicParameters([
Достъпът до променливите на средата е лесен с помощта на динамични параметри. Достъпът до тях се осъществява чрез `%env.variable%` в конфигурационните файлове.
```php
-$configurator->addDynamicParameters([
+$this->configurator->addDynamicParameters([
'env' => getenv(),
]);
```
@@ -206,6 +232,7 @@ $configurator->addDynamicParameters([
- `%wwwDir%` е абсолютният път до директорията, съдържаща входния файл `index.php`
- `%tempDir%` е абсолютният път до директорията за временни файлове
- `%vendorDir%` е абсолютният път до директорията, в която Composer инсталира библиотеки
+- `%rootDir%` е абсолютният път до главната директория на проекта
- `%debugMode%` показва дали приложението е в режим на отстраняване на грешки
- `%consoleMode%` показва дали заявката е постъпила от командния ред
@@ -225,7 +252,7 @@ services:
Създайте нов екземпляр и го вмъкнете в Bootstrap:
```php
-$configurator->addServices([
+$this->configurator->addServices([
'myservice' => new App\Model\MyCustomService('foobar'),
]);
```
@@ -234,13 +261,21 @@ $configurator->addServices([
Различни среди .[#toc-different-environments]
=============================================
-Не се колебайте да персонализирате класа `Bootstrap` според нуждите си. Можете да добавите параметри към метода `boot()`, за да разделите уеб проектите, или да добавите други методи, като например `bootForTests()`, който инициализира средата за тестове на единици, `bootForCli()` за скриптове, извикани от командния ред, и т.н.
+Не се колебайте да персонализирате класа `Bootstrap` според нуждите си. Можете да добавите параметри към метода `bootWebApplication()`, за да разграничите отделните уеб проекти. Като алтернатива можете да добавите и други методи, например `bootTestEnvironment()` за инициализиране на средата за unit тестове, `bootConsoleApplication()` за скриптове, извикани от командния ред, и т.н.
```php
-public static function bootForTests(): Configurator
+public function bootTestEnvironment(): Nette\DI\Container
+{
+ Tester\Environment::setup(); // Инициализация на Nette Tester
+ $this->setupContainer();
+ return $this->configurator->createContainer();
+}
+
+public function bootConsoleApplication(): Nette\DI\Container
{
- $configurator = self::boot();
- Tester\Environment::setup(); // Инициализация Nette Tester
- return $configurator;
+ $this->configurator->setDebugMode(false);
+ $this->initializeEnvironment();
+ $this->setupContainer();
+ return $this->configurator->createContainer();
}
```
diff --git a/application/bg/components.texy b/application/bg/components.texy
index e5ccab94e7..ab5c216e1c 100644
--- a/application/bg/components.texy
+++ b/application/bg/components.texy
@@ -230,6 +230,28 @@ $this->redirect(/* ... */); // пренасочване
```
+Пренасочване след сигнал .[#toc-redirection-after-a-signal]
+===========================================================
+
+След обработката на сигнал от компонент често следва пренасочване. Тази ситуация е подобна на формулярите - след изпращане на формуляр също пренасочваме, за да предотвратим повторното изпращане на данни, когато страницата се опреснява в браузъра.
+
+```php
+$this->redirect('this') // redirects to the current presenter and action
+```
+
+Тъй като компонентът е елемент за многократна употреба и обикновено не трябва да има пряка зависимост от конкретни презентатори, методите `redirect()` и `link()` автоматично интерпретират параметъра като сигнал за компонент:
+
+```php
+$this->redirect('click') // redirects to the 'click' signal of the same component
+```
+
+Ако трябва да пренасочите към друг презентатор или действие, можете да го направите чрез презентатора:
+
+```php
+$this->getPresenter()->redirect('Product:show'); // redirects to a different presenter/action
+```
+
+
Постоянни параметри .[#toc-persistent-parameters]
=================================================
diff --git a/application/bg/configuration.texy b/application/bg/configuration.texy
index 30bc0d30c0..0e2aeb11b1 100644
--- a/application/bg/configuration.texy
+++ b/application/bg/configuration.texy
@@ -95,6 +95,9 @@ latte:
# позволява [проверка на генерирания код |latte:develop#Checking Generated Code]
phpLinter: ... # (string) по подразбиране е null
+ # задава локала
+ locale: cs_CZ # (string) по подразбиране е null
+
# клас $this->template
templateClass: App\MyTemplateClass # по подразбиране Nette\Bridges\ApplicationLatte\DefaultTemplate
```
@@ -104,7 +107,7 @@ latte:
```neon
latte:
расширения:
- - Latte\Essential\TranslatorExtension
+ - Latte\Essential\TranslatorExtension(@Nette\Localization\Translator)
```
/--comment
diff --git a/application/bg/how-it-works.texy b/application/bg/how-it-works.texy
index 3cdb0786e2..5ca8332a47 100644
--- a/application/bg/how-it-works.texy
+++ b/application/bg/how-it-works.texy
@@ -22,13 +22,13 @@
/--pre
web-project/
├── app/ ← каталог с приложением
-│ ├── Presenters/ ← классы презентеров
-│ │ ├── HomePresenter.php ← Класс презентера главной страницы
-│ │ └── templates/ ← директория шаблонов
-│ │ ├── @layout.latte ← шаблон общего макета
-│ │ └── Home/ ← шаблоны презентера главной страницы
-│ │ └── default.latte ← шаблон действия `default`
-│ ├── Router/ ← конфигурация URL-адресов
+│ ├── Основни/ ← основни необходими класове
+│ │ └── RouterFactory.php ← конфигуриране на URL адреси
+│ ├── UI/ ← презентатори, шаблони и др.
+│ │ ├── @layout.latte ← шаблон на споделено оформление
+│ │ └── Home/ ← Директория за водещи
+│ │ ├── HomePresenter.php ← Клас на Home Presenter
+│ │ └── default.latte ← шаблон за действие default
│ └── Bootstrap.php ← загрузочный класс Bootstrap
├── bin/ ← скрипты командной строки
├── config/ ← файлы конфигурации
@@ -91,7 +91,7 @@ Nette е наставник, който ви напътства да пишет
Приложението започва с искане към т.нар. маршрутизатор да реши на кой от презентаторите да изпрати текущата заявка за обработка. Маршрутизаторът решава чия е отговорността. Той разглежда входния URL адрес `https://example.com/product/123`, който иска продукт `показать` с `id: 123` като действие. Добър навик е да записвате двойките водещ + действие, разделени с двоеточие: `Продукт:показать`.
-Следователно маршрутизаторът е преобразувал URL адреса в двойка `Presenter:action` + параметри, в нашия случай `Product:show` + `id`: 123`. Вы можете увидеть, как выглядит маршрутизатор в файле `app/Router/RouterFactory.php`, и ще го опишем подробно в главата [Маршрутизация |routing].
+Следователно маршрутизаторът е преобразувал URL адреса в двойка `Presenter:action` + параметри, в нашия случай `Product:show` + `id`: 123`. Вы можете увидеть, как выглядит маршрутизатор в файле `app/Core/RouterFactory.php`, и ще го опишем подробно в главата [Маршрутизация |routing].
Да продължим. Приложението вече знае името на водещия и може да продължи. Чрез създаване на обект `ProductPresenter`, който е кодът на предентера `Product`. По-точно, той иска от контейнера DI да създаде презентатора, тъй като създаването на обекти е негова работа.
@@ -121,12 +121,9 @@ class ProductPresenter extends Nette\Application\UI\Presenter
След това водещият връща отговор. Това може да бъде HTML страница, изображение, XML документ, файл, изпратен от диска, JSON или пренасочване към друга страница. Важно е да се отбележи, че ако не посочим изрично как да се отговори (какъвто е случаят с `ProductPresenter`), отговорът ще бъде шаблон, показващ HTML страница. Защо? Ами защото в 99% от случаите искаме да покажем шаблон, водещият приема това поведение по подразбиране и иска да улесни работата ни. Това е гледната точка на Нете.
-Дори не е необходимо да указваме кой шаблон да се покаже, той сам извежда пътя до него според проста логика. В случая с водещия `Product` и действието `show`, той се опитва да провери дали някой от тези файлове с шаблони съществува спрямо директорията, в която се намира класът `ProductPresenter`:
+Дори не е необходимо да посочваме кой шаблон да се визуализира; рамката сама ще определи пътя. В случая с действието `show` тя просто се опитва да зареди шаблона `show.latte` в директорията с класа `ProductPresenter`. Тя също така се опитва да намери оформлението във файла `@layout.latte` (повече за [търсенето на шаблони |templates#Template Lookup]).
-- `templates/Product/show.latte`
-- `templates/Product.show.latte`
-
-След това се показва шаблонът. Задачата на водещия и на цялото приложение вече е изпълнена. Ако шаблонът не съществува, ще бъде върната страница за грешка 404. Можете да прочетете повече за водещите на страницата [Водещи |presenters].
+Впоследствие шаблоните се визуализират. С това задачата на презентатора и на цялото приложение е изпълнена и работата е приключила. Ако шаблонът не съществува, ще бъде върната страница с грешка 404. Можете да прочетете повече за презентаторите на страницата [Презентатори |presenters].
[* request-flow.svg *]
@@ -137,7 +134,7 @@ class ProductPresenter extends Nette\Application\UI\Presenter
3) маршрутизаторът декодира URL адреса като двойка `Home:default`
4) обектът е създаден `HomePresenter`
5) извиква се методът `renderDefault()` (ако съществува)
-6) шаблонът `templates/Home/default.latte` с оформлението `templates/@layout.latte` се визуализира
+6) шаблонът `default.latte` с оформлението `@layout.latte` се визуализира
Може би сега ще се сблъскате с много нови концепции, но ние смятаме, че те имат смисъл. Създаването на приложения в Nette е лесно.
diff --git a/application/bg/modules.texy b/application/bg/modules.texy
index ddecd3f1a8..b675e91dd1 100644
--- a/application/bg/modules.texy
+++ b/application/bg/modules.texy
@@ -2,29 +2,31 @@
******
.[perex]
-В Nette модулите са логическите единици, от които се състои едно приложение. Те включват главни модули, шаблони, евентуално компоненти и класове модели.
+Модулите внасят яснота в приложенията на Nette, като улесняват лесното им разделяне на логически единици.
-Един компонент за презентатори и един за шаблони няма да са достатъчни за реални проекти. Натрупването на десетки файлове в една папка е меко казано неорганизирано. Как да излезем от тази ситуация? Просто ги разделяме на поддиректории на диска и на пространства от имена в кода. Точно това правят модулите Nette.
-
-Така че нека забравим за една папка за презентатори и шаблони и вместо това да създадем модули като `Admin` и `Front`.
+Подобно на организирането на файловете в папки на твърдия диск, в Nette можем да разделим презентатори, шаблони и други спомагателни класове на модули. Как работи това на практика? Просто чрез включване на нови поддиректории в структурата. Ето един пример за структура с два модула - Front и Admin:
/--pre
-app/
-├── Presenters/
-├── Modules/ ← директория с модулями
-│ ├── Admin/ ← модуль Admin
-│ │ ├── Presenters/ ← его презентеры
-│ │ │ ├── DashboardPresenter.php
-│ │ │ └── templates/
-│ └── Front/ ← модуль Front
-│ └── Presenters/ ← его презентеры
-│ └── ...
+app/
+├── UI/
+│ ├── Admin/ ← Admin module
+│ │ ├── @layout.latte
+│ │ ├── Dashboard/
+│ │ │ ├── DashboardPresenter.php
+│ │ │ └── default.latte
+│ │ └── ...
+│ ├── Front/ ← Front module
+│ │ ├── @layout.latte
+│ │ ├── Home/
+│ │ │ ├── HomePresenter.php
+│ │ │ └── default.latte
+│ │ └── ...
\--
-Тази структура на директориите ще бъде отразена в пространствата за имена на класовете, така че например `DashboardPresenter` ще бъде в пространството `App\Modules\Admin\Presenters`:
+Тази структура на директориите е отразена в пространствата от имена на класовете, така че например `DashboardPresenter` се намира в пространството от имена `App\UI\Admin\Dashboard`:
```php
-namespace App\Modules\Admin\Presenters;
+namespace App\UI\Admin\Dashboard;
class DashboardPresenter extends Nette\Application\UI\Presenter
{
@@ -32,35 +34,49 @@ class DashboardPresenter extends Nette\Application\UI\Presenter
}
```
-Главното устройство `Dashboard` в модула `Admin` се обозначава в приложението с помощта на запис с двойна точка като `Admin:Dashboard`, а неговото действие `default` се обозначава като `Admin:Dashboard:default`.
-И откъде Nette знае, че `Admin:Dashboard` представлява класа `App\Modules\Admin\Presenters\DashboardPresenter`? Говорим за това, като използваме [картографирането |#Mapping] в конфигурацията.
-Така че дадената структура не е фиксирана и можете да я променяте по свое усмотрение.
+В приложението се позоваваме на презентатора `Dashboard` в рамките на модула `Admin`, като използваме запис с двоеточие като `Admin:Dashboard`. За неговото действие `default` го наричаме `Admin:Dashboard:default`.
-Модулите, разбира се, могат да съдържат всички други части, освен презентатори и шаблони, като компоненти, класове модели и др.
+Представената структура не е твърда; в конфигурацията можете [напълно |#mapping] да [я адаптирате към вашите нужди |#mapping]. .[tip]
+
+Модулите могат да включват всички други файлове, като компоненти и спомагателни класове, в допълнение към презентаторите и шаблоните. Ако обмисляте къде да ги поставите, помислете за използването на папка `Accessory`:
+
+/--pre
+app/
+├── UI/
+│ ├── Admin/
+│ │ ├── Accessory/
+│ │ │ ├── FormFactory.php
+│ │ │ └── AdminLayout.php
+│ │ ├── Dashboard/
+│ │ └── ...
+\--
Вложени модули .[#toc-nested-modules]
-------------------------------------
-Модулите не трябва да образуват само плоска структура, можете да създавате и подмодули, например:
+Модулите могат да имат няколко нива на влагане, подобно на структурата на директориите на диска:
/--pre
-app/
-├── Modules/ ← директория с модулями
-│ ├── Blog/ ← модуль Blog
-│ │ ├── Admin/ ← подмодуль Admin
-│ │ │ ├── Presenters/
+app/
+├── UI/
+│ ├── Blog/ ← Blog module
+│ │ ├── Admin/ ← Admin submodule
+│ │ │ ├── Dashboard/
+│ │ │ └── ...
+│ │ ├── Front/ ← Front submodule
+│ │ │ ├── @layout.latte
+│ │ │ ├── Home/
│ │ │ └── ...
-│ │ └── Front/ ← подмодуль Front
-│ │ ├── Presenters/
-│ │ └── ...
-│ ├── Forum/ ← модуль Forum
+│ ├── Forum/ ← Forum module
│ │ └── ...
\--
-Така модулът `Blog` се разделя на подмодули `Admin` и `Front`. Това отново ще бъде отразено в пространствата от имена, които ще бъдат `App\Modules\Blog\Admin\Presenters` и т.н. Главният модул `Dashboard` в рамките на подмодула се нарича `Blog:Admin:Dashboard`.
+Модулът `Blog` е разделен на подмодули `Admin` и `Front`. Това е отразено и в пространствата от имена, които след това се появяват като `App\UI\Blog\Admin` и по подобен начин. За да се позовем на презентатора `Dashboard` в рамките на подмодула `Admin`, го наричаме `Blog:Admin:Dashboard`.
-Разклоненията могат да бъдат толкова дълбоки, колкото искате, така че можете да създавате подмодули.
+Влагането може да бъде толкова дълбоко, колкото е необходимо, като позволява създаването на подмодули.
+
+Например, ако в администрацията имате много презентатори, свързани с управлението на поръчки, като `OrderDetail`, `OrderEdit`, `OrderDispatch` и т.н., може да създадете модул `Order`, в който ще бъдат организирани презентатори като `Detail`, `Edit`, `Dispatch` и други.
Създаване на връзки .[#toc-creating-links]
@@ -102,46 +118,66 @@ class DashboardPresenter extends Nette\Application\UI\Presenter
Картографиране .[#toc-mapping]
------------------------------
-Определя правилата, по които името на класа се извежда от главното име. Записваме ги в [конфигурацията |configuration] под ключа `application › mapping`.
+Съпоставянето определя правилата за извеждане на името на класа от името на водещия. Тези правила се посочват в [конфигурацията |configuration] под ключа `application › mapping`.
+
+Структурите на директориите, споменати по-рано на тази страница, се основават на следното съпоставяне:
+
+```neon
+application:
+ mapping: App\UI\*\**Presenter
+```
-Нека започнем с пример, при който не се използват модули. Искаме само главните класове да имат пространството от имена `App\Presenters`. Това означава, че искаме главното име, например `Home`, да се съпостави с класа `App\Presenters\HomePresenter`. Това може да се постигне със следната конфигурация:
+Как работи картографирането? За по-добро разбиране нека първо си представим приложение без модули. Искаме класовете на презентаторите да попадат в пространството от имена `App\UI`, така че презентаторът `Home` да се съпостави с класа `App\UI\HomePresenter`. Това може да се постигне с тази конфигурация:
```neon
application:
- mapping: App\Presenters\*Presenter
+ mapping: App\UI\*Presenter
```
-Името на водещия се заменя със звездичка и резултатът е името на класа. Лесно!
+Това съпоставяне се извършва чрез замяна на звездичката в маската `App\UI\*Presenter` с името на презентатора `Home`, в резултат на което се получава крайното име на класа `App\UI\HomePresenter`. Просто!
+
+Въпреки това, както можете да видите в примерите в тази и други глави, ние поставяме класовете на водещите в едноименни поддиректории, например водещият `Home` е картографиран към клас `App\UI\Home\HomePresenter`. Това се постига чрез удвояване на звездичката (изисква Nette Application 3.2):
+
+```neon
+application:
+ mapping: App\UI\**Presenter
+```
-Ако разделим презентаторите на модули, можем да използваме различни карти за всеки модул:
+Сега нека преминем към картографиране на презентатори в модули. Можем да дефинираме специфични съпоставки за всеки модул:
```neon
application:
mapping:
- Front: App\Modules\Front\Presenters\*Presenter
- Admin: App\Modules\Admin\Presenters\*Presenter
+ Front: App\UI\Front\**Presenter
+ Admin: App\UI\Admin\**Presenter
Api: App\Api\*Presenter
```
-Сега водещият `Front:Home` е определен от класа `App\Modules\Front\HomePresenter`, а презентер `Admin:Dashboard` - `App\AdminModule\DashboardPresenter`.
+Според тази конфигурация презентаторът `Front:Home` се съотнася към класа `App\UI\Front\Home\HomePresenter`, а презентаторът `Api:OAuth` се съотнася към класа `App\Api\OAuthPresenter`.
-Би било по-удобно да се създаде общо правило (звездичка), което да замени първите две правила, и да се добави допълнителна звездичка само за модула:
+Тъй като модулите `Front` и `Admin` имат сходен подход на картографиране и вероятно има повече такива модули, е възможно да се създаде общо правило, което да ги замени. Към маската на класа се добавя нова звездичка за модула:
```neon
application:
mapping:
- *: App\Modules\*\Presenters\*Presenter
+ *: App\UI\*\**Presenter
Api: App\Api\*Presenter
```
-Но какво става, ако използваме няколко вложени модула и имаме например главен модул `Admin:User:Edit`? В този случай сегментът със звездичка, представляващ модула за всяко ниво, просто ще се повтори и резултатът ще бъде класът `App\Modules\Admin\User\Presenters\EditPresenter`.
+За вложени модули на няколко нива, като например водещия `Admin:User:Edit`, сегментът със звездичка се повтаря за всяко ниво, в резултат на което се получава клас `App\UI\Admin\User\Edit\EditPresenter`.
-Алтернативен начин за записване е използването на масив от три сегмента вместо низ. Този запис е еквивалентен на предишния:
+Алтернативен запис е да се използва масив, съставен от три сегмента, вместо низ. Този запис е еквивалентен на предишния:
```neon
application:
mapping:
- *: [App\Modules, *, Presenters\*Presenter]
+ *: [App\UI, *, **Presenter]
+ Api: [App\Api, '', *Presenter]
```
-Стойността по подразбиране е `*Module\*Presenter`.
+Ако имаме само едно правило в конфигурацията, общото, можем да го напишем накратко:
+
+```neon
+application:
+ mapping: App\UI\*\**Presenter
+```
diff --git a/application/bg/presenters.texy b/application/bg/presenters.texy
index efcce1d904..bf2aeb04fc 100644
--- a/application/bg/presenters.texy
+++ b/application/bg/presenters.texy
@@ -60,7 +60,7 @@ class ArticlePresenter extends Nette\Application\UI\Presenter
Важното е, че `action()` се извиква преди `render()`, така че в него можем евентуално да променим следващия жизнен цикъл, т.е. да променим шаблона за визуализиране и метода `render()`която ще бъде извикана с помощта на `setView('otherView')`.
-Параметрите от заявката се предават на метода. Възможно и препоръчително е да се посочат типове за параметрите, например `actionShow(int $id, string $slug = null)` - ако параметърът `id` липсва или ако не е цяло число, презентаторът ще върне [грешка 404 |#Error-404-etc] и ще прекрати операцията.
+Параметрите от заявката се предават на метода. Възможно и препоръчително е да се посочат типове за параметрите, например `actionShow(int $id, ?string $slug = null)` - ако параметърът `id` липсва или ако не е цяло число, презентаторът ще върне [грешка 404 |#Error-404-etc] и ще прекрати операцията.
`handle(args...)` .{toc: handle()}
@@ -205,7 +205,7 @@ $this->redirect(/* ... */);
Грешка 404 и т.н. .[#toc-error-404-etc]
=======================================
-Когато не можем да изпълним дадена заявка, защото например статията, която искаме да покажем, не съществува в базата данни, ще хвърлим грешка 404, като използваме метода `error(string $message = null, int $httpCode = 404)`, който представлява HTTP грешка 404:
+Когато не можем да изпълним дадена заявка, защото например статията, която искаме да покажем, не съществува в базата данни, ще хвърлим грешка 404, като използваме метода `error(?string $message = null, int $httpCode = 404)`, който представлява HTTP грешка 404:
```php
public function renderShow(int $id): void
@@ -384,7 +384,7 @@ class ProductPresenter extends Nette\Application\UI\Presenter
Можете също така да извикате канонизацията ръчно с метода `canonicalize()`, който, както и методът `link()`, приема като аргументи водещия, действията и параметрите. Тя създава връзка и я сравнява с текущия URL адрес. Ако те са различни, се пренасочва към генерираната връзка.
```php
-public function actionShow(int $id, string $slug = null): void
+public function actionShow(int $id, ?string $slug = null): void
{
$realSlug = $this->facade->getSlugForId($id);
// пренасочва, ако $slug е различен от $realSlug
@@ -452,17 +452,6 @@ $this->sendResponse(new Responses\CallbackResponse($callback));
В `#[Requires]` предоставя разширени опции за ограничаване на достъпа до презентаторите и техните методи. Той може да се използва за определяне на HTTP методи, изискване на AJAX заявки, ограничаване на достъпа до същия произход и ограничаване на достъпа само до препращане. Атрибутът може да се прилага към класове на презентатори, както и към отделни методи, като например `action()`, `render()`, `handle()`, и `createComponent()`.
-Ето един пример за използването му за ограничаване на достъпа само до метода HTTP `POST`:
-
-```php
-use Nette\Application\Attributes\Requires;
-
-#[Requires(methods: 'POST')]
-class MyPresenter extends Nette\Application\UI\Presenter
-{
-}
-```
-
Можете да зададете тези ограничения:
- на HTTP методите: `#[Requires(methods: ['GET', 'POST'])]`
- изискващи AJAX заявка: `#[Requires(ajax: true)]`
@@ -470,22 +459,7 @@ class MyPresenter extends Nette\Application\UI\Presenter
- достъп само чрез препращане: `#[Requires(forward: true)]`
- ограничения за конкретни действия: `#[Requires(actions: 'default')]`
-Условията могат да се комбинират чрез изброяване на няколко атрибута или чрез обединяването им в един:
-
-```php
-#[Requires(methods: 'POST', ajax: true)]
-public function actionDelete(int $id)
-{
-}
-
-// or
-
-#[Requires(methods: 'POST')]
-#[Requires(ajax: true)]
-public function actionDelete(int $id)
-{
-}
-```
+За подробности вижте [Как да използвате Requires атрибут |best-practices:attribute-requires].
Проверка на метода HTTP .[#toc-http-method-check]
diff --git a/application/bg/routing.texy b/application/bg/routing.texy
index 300a7755e2..26abc2fb5d 100644
--- a/application/bg/routing.texy
+++ b/application/bg/routing.texy
@@ -216,7 +216,7 @@ $router->addRoute('//www.%sld%.%tld%/%basePath%//addRoute('/[/]', [
@@ -225,7 +225,7 @@ $router->addRoute('/[/]', [
]);
```
-Или можем да използваме тази форма, като отбележим пренаписването на израза за регулярна проверка:
+За по-подробна спецификация може да се използва още по-разширена форма, в която освен стойностите по подразбиране могат да се задават и други свойства на параметъра, например регулярен израз за валидиране (вж. параметъра `id` ):
```php
use Nette\Routing\Route;
@@ -243,7 +243,7 @@ $router->addRoute('/[/]', [
]);
```
-Тези по-подробни формати са полезни за добавяне на повече метаданни.
+Важно е да се отбележи, че ако параметрите, дефинирани в масива, не са включени в маската на пътя, техните стойности не могат да бъдат променени, дори и чрез използване на параметри на заявката, зададени след въпросителен знак в URL адреса.
Филтри и преводи .[#toc-filters-and-translations]
@@ -477,10 +477,10 @@ $router->addRoute('index.html \.html?|\.php|>', /* ... */);
Интеграция .[#toc-integration]
==============================
-За да свържем маршрутизатора си с приложението, трябва да информираме за това контейнера DI. Най-лесният начин е да се подготви фабрика, която ще създаде обект маршрутизатор, и да се каже на конфигурацията на контейнера да го използва. Да предположим, че напишем метод за това, `App\Router\RouterFactory::createRouter()`:
+За да свържем маршрутизатора си с приложението, трябва да информираме за това контейнера DI. Най-лесният начин е да се подготви фабрика, която ще създаде обект маршрутизатор, и да се каже на конфигурацията на контейнера да го използва. Да предположим, че напишем метод за това, `App\Core\RouterFactory::createRouter()`:
```php
-namespace App\Router;
+namespace App\Core;
use Nette\Application\Routers\RouteList;
@@ -499,7 +499,7 @@ class RouterFactory
```neon
services:
- - App\Router\RouterFactory::createRouter
+ - App\Core\RouterFactory::createRouter
```
Всички зависимости, като например връзки към бази данни и т.н., се предават на метода на фабриката като параметри, като се използва [автоматично свързване |dependency-injection:autowiring]:
@@ -663,7 +663,7 @@ $router->addRoute(/* ... */);
Затова отново ще добавим метод, който ще създаде например маршрутизатор:
```php
-namespace App\Router;
+namespace App\Core;
use Nette\Routing\RouteList;
@@ -694,7 +694,7 @@ $httpRequest = $container->getByType(Nette\Http\IRequest::class);
Или ще създадем обектите директно:
```php
-$router = App\Router\RouterFactory::createRouter();
+$router = App\Core\RouterFactory::createRouter();
$httpRequest = (new Nette\Http\RequestFactory)->fromGlobals();
```
diff --git a/application/bg/templates.texy b/application/bg/templates.texy
index 850d3e2ecd..0be4f81857 100644
--- a/application/bg/templates.texy
+++ b/application/bg/templates.texy
@@ -34,35 +34,81 @@ Nette използва системата за шаблони [Latte |latte:]. L
Той дефинира блок `content`, който се вмъква вместо `{include content}` в оформлението, и замества блока `title`, който презаписва `{block title}` в оформлението. Опитайте се да си представите резултата.
-Търсене на шаблони .[#toc-search-for-templates]
------------------------------------------------
+Търсене на шаблони .[#toc-template-lookup]
+------------------------------------------
+
+В презентаторите не е необходимо да посочвате кой шаблон трябва да бъде визуализиран; рамката автоматично ще определи пътя, което ще ви улесни при кодирането.
+
+Ако използвате структура от директории, в която всеки презентатор има своя собствена директория, просто поставете шаблона в тази директория под името на действието (т.е. изглед). Например, за действието `default` използвайте шаблона `default.latte`:
-Пътят към шаблоните се определя от главния модул с помощта на проста логика. Той ще се опита да провери дали има някой от тези файлове, разположен спрямо главната директория на класа, където `` е името на текущия главен модул, а `` е името на текущото събитие:
+/--pre
+app/
+└── UI/
+ └── Home/
+ ├── HomePresenter.php
+ └── default.latte
+\--
-- `templates//.latte`
-- `templates/..latte`
+Ако използвате структура, в която презентаторите са заедно в една директория, а шаблоните - в папка `templates`, запишете я или във файл `..latte` или `/.latte`:
-Ако шаблонът не бъде намерен, ще се опита да търси в директорията `templates` едно ниво по-нагоре, т.е. на същото ниво като директорията с класа на водещия.
+/--pre
+app/
+└── Presenters/
+ ├── HomePresenter.php
+ └── templates/
+ ├── Home.default.latte ← 1st variant
+ └── Home/
+ └── default.latte ← 2nd variant
+\--
-Ако шаблонът не бъде намерен и там, отговорът ще бъде [грешка 404 |presenters#Error 404 etc.].
+Директорията `templates` може да бъде поставена и едно ниво по-нагоре, на същото ниво като директорията с класовете на водещите.
-Можете също така да промените изгледа с помощта на `$this->setView('jineView')`. Или вместо да търсите директно, посочете името на файла с шаблона, като използвате `$this->template->setFile('/path/to/template.latte')`.
+Ако шаблонът не бъде намерен, презентаторът отговаря с [грешка 404 - страница не е намерена |presenters#Error 404 etc].
+
+Можете да промените изгледа, като използвате `$this->setView('anotherView')`. Възможно е също така директно да посочите файла с шаблона с помощта на `$this->template->setFile('/path/to/template.latte')`.
.[note]
-Файловете, които се търсят за шаблони, могат да се променят чрез наслагване на метода [formatTemplateFiles() |api:Nette\Application\UI\Presenter::formatTemplateFiles()], който връща масив от възможни имена на файлове.
+Файловете, в които се търсят шаблони, могат да се променят чрез надграждане на метода [formatTemplateFiles() |api:Nette\Application\UI\Presenter::formatTemplateFiles()], който връща масив от възможни имена на файлове.
+
+
+Търсене на шаблони за оформление .[#toc-layout-template-lookup]
+---------------------------------------------------------------
+
+Nette също така автоматично търси файла с оформлението.
+
+Ако използвате структура на директориите, в която всеки водещ има своя собствена директория, поставете макета или в папката с водещия, ако е специфичен само за него, или на по-високо ниво, ако е общ за няколко водещи:
+
+/--pre
+app/
+└── UI/
+ ├── @layout.latte ← common layout
+ └── Home/
+ ├── @layout.latte ← only for Home presenter
+ ├── HomePresenter.php
+ └── default.latte
+\--
+
+Ако използвате структура, в която презентаторите са групирани в една директория, а шаблоните са в папка `templates`, макетът ще се очаква на следните места:
-В тези файлове се очаква оформление:
+/--pre
+app/
+└── Presenters/
+ ├── HomePresenter.php
+ └── templates/
+ ├── @layout.latte ← common layout
+ ├── Home.@layout.latte ← only for Home, 1st variant
+ └── Home/
+ └── @layout.latte ← only for Home, 2nd variant
+\--
-- `templates//@.latte`
-- `templates/.@.latte`
-- `templates/@.latte` Разположение, общо за няколко високоговорителя
+Ако презентаторът е в [модул |modules], той ще търси и по-нагоре в дървото на директориите според вложеността на модула.
-Къде: `` е името на текущия водещ, а `` е името на оформлението, което по подразбиране е `'layout'`. Името може да бъде променено с помощта на `$this->setLayout('jinyLayout')`, така че ще бъдат изпробвани файлове `@jinyLayout.latte`.
+Името на макета може да бъде променено с помощта на `$this->setLayout('layoutAdmin')` и тогава то ще бъде очаквано във файла `@layoutAdmin.latte`. Можете също така директно да посочите файла с шаблона на оформлението, като използвате `$this->setLayout('/path/to/template.latte')`.
-Можете също така директно да посочите името на файла на шаблона за оформление, като използвате `$this->setLayout('/path/to/template.latte')`. Използването на `$this->setLayout(false)` деактивира проследяването на оформлението.
+Използването на `$this->setLayout(false)` или на тага `{layout none}` вътре в шаблона деактивира търсенето на оформление.
.[note]
-Файловете, в които се търсят шаблоните за оформление, могат да се променят чрез наслагване на метода [formatLayoutTemplateFiles() |api:Nette\Application\UI\Presenter::formatLayoutTemplateFiles()], който връща масив от възможни имена на файлове.
+Файловете, в които се търсят шаблони за оформление, могат да бъдат променяни чрез надграждане на метода [formatLayoutTemplateFiles() |api:Nette\Application\UI\Presenter::formatLayoutTemplateFiles()], който връща масив от възможни имена на файлове.
Променливи в шаблона .[#toc-variables-in-the-template]
@@ -104,7 +150,7 @@ class ArticleTemplate extends Nette\Bridges\ApplicationLatte\Template
Можете също така да си позволите лукса да шепнете в шаблоните, просто инсталирайте плъгина Latte в PhpStorm и поставете името на класа в началото на шаблона, за повече информация вижте статията "Latte: как да въведем системата":https://blog.nette.org/bg/latte-kak-da-izpolzvame-sistemata-ot-tipove:
```latte
-{templateType App\Presenters\ArticleTemplate}
+{templateType App\UI\Article\ArticleTemplate}
...
```
@@ -176,7 +222,7 @@ public function beforeRender(): void
Версия 3 на Latte предлага по-усъвършенстван начин за създаване на [разширение за |latte:creating-extension] всеки уеб проект. Ето кратък пример за такъв клас:
```php
-namespace App\Templating;
+namespace App\UI\Accessory;
final class LatteExtension extends Latte\Extension
{
@@ -214,7 +260,7 @@ final class LatteExtension extends Latte\Extension
```neon
latte:
extensions:
- - App\Templating\LatteExtension
+ - App\UI\Accessory\LatteExtension
```
@@ -239,7 +285,7 @@ protected function beforeRender(): void
```neon
latte:
extensions:
- - Latte\Essential\TranslatorExtension
+ - Latte\Essential\TranslatorExtension(@Nette\Localization\Translator)
```
След това транслаторът може да се използва например като филтър `|translate`, като на метода `translate()` се предават допълнителни параметри (вж. `foo, bar`):
diff --git a/application/cs/ajax.texy b/application/cs/ajax.texy
index 407622ab95..327977ea19 100644
--- a/application/cs/ajax.texy
+++ b/application/cs/ajax.texy
@@ -77,6 +77,12 @@ npm install naja
```
+Nejprve je potřeba knihovnu [inicializovat |https://naja.js.org/#/guide/01-install-setup-naja?id=initialization]:
+
+```js
+naja.initialize();
+```
+
Aby se z obyčejného odkazu (signálu) nebo odeslání formuláře vytvořil AJAXový požadavek, stačí označit příslušný odkaz, formulář nebo tlačítko třídou `ajax`:
```html
diff --git a/application/cs/bootstrap.texy b/application/cs/bootstrap.texy
index a0b9db0792..6357fe0d4d 100644
--- a/application/cs/bootstrap.texy
+++ b/application/cs/bootstrap.texy
@@ -20,18 +20,44 @@ use Nette\Bootstrap\Configurator;
class Bootstrap
{
- public static function boot(): Configurator
+ private Configurator $configurator;
+ private string $rootDir;
+
+ public function __construct()
+ {
+ $this->rootDir = dirname(__DIR__);
+ // Konfigurátor je zodpovědný za nastavení prostředí aplikace a služeb.
+ $this->configurator = new Configurator;
+ // Nastaví adresář pro dočasné soubory generované Nette (např. zkompilované šablony)
+ $this->configurator->setTempDirectory($this->rootDir . '/temp');
+ }
+
+ public function bootWebApplication(): Nette\DI\Container
{
- $appDir = dirname(__DIR__);
- $configurator = new Configurator;
- //$configurator->setDebugMode('secret@23.75.345.200');
- $configurator->enableTracy($appDir . '/log');
- $configurator->setTempDirectory($appDir . '/temp');
- $configurator->createRobotLoader()
+ $this->initializeEnvironment();
+ $this->setupContainer();
+ return $this->configurator->createContainer();
+ }
+
+ private function initializeEnvironment(): void
+ {
+ // Nette je chytré a vývojový režim se zapíná automaticky,
+ // nebo jej můžete povolit pro konkrétní IP adresu odkomentováním následujícího řádku:
+ // $this->configurator->setDebugMode('secret@23.75.345.200');
+
+ // Aktivuje Tracy: ultimátní "švýcarský nůž" pro ladění.
+ $this->configurator->enableTracy($this->rootDir . '/log');
+
+ // RobotLoader: automaticky načítá všechny třídy ve zvoleném adresáři
+ $this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
- $configurator->addConfig($appDir . '/config/common.neon');
- return $configurator;
+ }
+
+ private function setupContainer(): void
+ {
+ // Načte konfigurační soubory
+ $this->configurator->addConfig($this->rootDir . '/config/common.neon');
}
}
```
@@ -40,16 +66,15 @@ class Bootstrap
index.php
=========
-Prvotní soubor je v případě webových aplikací `index.php`, který se nachází ve veřejném adresáři `www/`. Ten si nechá od třídy Bootstrap inicializovat prostředí a vrátit `$configurator` a následně vyrobí DI kontejner. Poté z něj získá službu `Application`, kterou spustí webovou aplikaci:
+Prvotní soubor je v případě webových aplikací `index.php`, který se nachází ve veřejném adresáři `www/`. Ten si nechá od třídy Bootstrap inicializovat prostředí a vyrobit DI kontejner. Poté z něj získá službu `Application`, která spustí webovou aplikaci:
```php
-// inicializace prostředí + získání objektu Configurator
-$configurator = App\Bootstrap::boot();
-// vytvoření DI kontejneru
-$container = $configurator->createContainer();
+$bootstrap = new App\Bootstrap;
+// Inicializace prostředí + vytvoření DI kontejneru
+$container = $bootstrap->bootWebApplication();
// DI kontejner vytvoří objekt Nette\Application\Application
$application = $container->getByType(Nette\Application\Application::class);
-// spuštění Nette aplikace
+// Spuštění aplikace Nette a zpracování příchozího požadavku
$application->run();
```
@@ -66,19 +91,19 @@ Volba režimu se provádí autodetekcí, takže obvykle není potřeba nic konfi
Pokud chceme vývojářský režim povolit i v dalších případech, například programátorům přistupujícím z konkrétní IP adresy, použijeme `setDebugMode()`:
```php
-$configurator->setDebugMode('23.75.345.200'); // lze uvést i pole IP adres
+$this->configurator->setDebugMode('23.75.345.200'); // lze uvést i pole IP adres
```
Rozhodně doporučujeme kombinovat IP adresu s cookie. Do cookie `nette-debug` uložíme tajný token, např. `secret1234`, a tímto způsobem aktivujeme vývojářský režim pro programátory přistupující z konkrétní IP adresy a zároveň mající v cookie zmíněný token:
```php
-$configurator->setDebugMode('secret1234@23.75.345.200');
+$this->configurator->setDebugMode('secret1234@23.75.345.200');
```
Vývojářský režim můžeme také vypnout úplně, i pro localhost:
```php
-$configurator->setDebugMode(false);
+$this->configurator->setDebugMode(false);
```
Pozor, hodnota `true` zapne vývojářský režim natvrdo, což se nikdy nesmí stát na produkčním serveru.
@@ -90,7 +115,7 @@ Debugovací nástroj Tracy
Pro snadné debugování ještě zapneme skvělý nástroj [Tracy |tracy:]. Ve vývojářském režimu chyby vizualizuje a v produkčním režimu chyby loguje do uvedeného adresáře:
```php
-$configurator->enableTracy($appDir . '/log');
+$this->configurator->enableTracy($this->rootDir . '/log');
```
@@ -100,7 +125,7 @@ Dočasné soubory
Nette využívá cache pro DI kontejner, RobotLoader, šablony atd. Proto je nutné nastavit cestu k adresáři, kam se bude cache ukládat:
```php
-$configurator->setTempDirectory($appDir . '/temp');
+$this->configurator->setTempDirectory($this->rootDir . '/temp');
```
Na Linuxu nebo macOS nastavte adresářům `log/` a `temp/` [práva pro zápis |nette:troubleshooting#Nastavení práv adresářů].
@@ -112,7 +137,7 @@ RobotLoader
Zpravidla budeme chtít automaticky načítat třídy pomocí [RobotLoaderu |robot-loader:], musíme ho tedy nastartovat a necháme jej načítat třídy z adresáře, kde je umístěný `Bootstrap.php` (tj. `__DIR__`), a všech podadresářů:
```php
-$configurator->createRobotLoader()
+$this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
```
@@ -126,7 +151,7 @@ Timezone
Přes konfigurátor můžete nastavit výchozí časovou zónu.
```php
-$configurator->setTimeZone('Europe/Prague');
+$this->configurator->setTimeZone('Europe/Prague');
```
@@ -143,16 +168,17 @@ Ve vývojářském režimu se kontejner automaticky aktualizuje při každé zm
Konfigurační soubory načteme pomocí `addConfig()`:
```php
-$configurator->addConfig($appDir . '/config/common.neon');
+$this->configurator->addConfig($this->rootDir . '/config/common.neon');
```
Pokud chceme přidat více konfiguračních souborů, můžeme funkci `addConfig()` zavolat vícekrát.
```php
-$configurator->addConfig($appDir . '/config/common.neon');
-$configurator->addConfig($appDir . '/config/services.neon');
+$configDir = $this->rootDir . '/config';
+$this->configurator->addConfig($configDir . '/common.neon');
+$this->configurator->addConfig($configDir . '/services.neon');
if (PHP_SAPI === 'cli') {
- $configurator->addConfig($appDir . '/config/cli.php');
+ $this->configurator->addConfig($configDir . '/cli.php');
}
```
@@ -169,7 +195,7 @@ Statické parametry
Parametry používané v konfiguračních souborech můžeme definovat [v sekci `parameters`|dependency-injection:configuration#parametry] a také je předávat (či přepisovat) metodou `addStaticParameters()` (má alias `addParameters()`). Důležité je, že různé hodnoty parametrů způsobí vygenerování dalších DI kontejnerů, tedy dalších tříd.
```php
-$configurator->addStaticParameters([
+$this->configurator->addStaticParameters([
'projectId' => 23,
]);
```
@@ -183,7 +209,7 @@ Dynamické parametry
Do kontejneru můžeme přidat i dynamické parametry, jejichž různé hodnoty na rozdíl od statických parameterů nezpůsobí generování nových DI kontejnerů.
```php
-$configurator->addDynamicParameters([
+$this->configurator->addDynamicParameters([
'remoteIp' => $_SERVER['REMOTE_ADDR'],
]);
```
@@ -191,7 +217,7 @@ $configurator->addDynamicParameters([
Jednoduše tak můžeme přidat např. environmentální proměnné, na které se pak lze v konfiguraci odkázat zápisem `%env.variable%`.
```php
-$configurator->addDynamicParameters([
+$this->configurator->addDynamicParameters([
'env' => getenv(),
]);
```
@@ -206,6 +232,7 @@ V konfiguračních souborech můžete využít tyto statické parametry:
- `%wwwDir%` je absolutní cesta k adresáři se vstupním souborem `index.php`
- `%tempDir%` je absolutní cesta k adresáři pro dočasné soubory
- `%vendorDir%` je absolutní cesta k adresáři, kam Composer instaluje knihovny
+- `%rootDir%` je absolutní cesta ke kořenovému adresáři projektu
- `%debugMode%` udává, zda je aplikace v debugovacím režimu
- `%consoleMode%` udává, zda request přišel přes příkazovou řádku
@@ -225,7 +252,7 @@ services:
A v bootstrapu do kontejneru vložíme objekt:
```php
-$configurator->addServices([
+$this->configurator->addServices([
'myservice' => new App\Model\MyCustomService('foobar'),
]);
```
@@ -234,13 +261,21 @@ $configurator->addServices([
Odlišné prostředí
=================
-Nebojte se upravit třídu Bootstrap podle svých potřeb. Metodě `boot()` můžete přidat parametry pro rozlišení webových projektů nebo doplnit další metody, například `bootForTests()`, která inicializuje prostředí pro jednotkové testy, `bootForCli()` pro skripty volané z příkazové řádky atd.
+Nebojte se upravit třídu Bootstrap podle svých potřeb. Metodě `bootWebApplication()` můžete přidat parametry pro rozlišení webových projektů. Nebo můžeme doplnit další metody, například `bootTestEnvironment()`, která inicializuje prostředí pro jednotkové testy, `bootConsoleApplication()` pro skripty volané z příkazové řádky atd.
```php
-public static function bootForTests(): Configurator
+public function bootTestEnvironment(): Nette\DI\Container
{
- $configurator = self::boot();
Tester\Environment::setup(); // inicializace Nette Testeru
- return $configurator;
+ $this->setupContainer();
+ return $this->configurator->createContainer();
+}
+
+public function bootConsoleApplication(): Nette\DI\Container
+{
+ $this->configurator->setDebugMode(false);
+ $this->initializeEnvironment();
+ $this->setupContainer();
+ return $this->configurator->createContainer();
}
```
diff --git a/application/cs/components.texy b/application/cs/components.texy
index d60ee2b7fd..db86af248c 100644
--- a/application/cs/components.texy
+++ b/application/cs/components.texy
@@ -198,7 +198,7 @@ Odkaz, který zavolá signál, vytvoříme obvyklým způsobem, tedy v šabloně
click here
```
-Signál se vždy volá na aktuálním presenteru a view, tudíž není možné jej vyvolat na jiném presenteru nebo view.
+Signál se vždy volá na aktuálním presenteru a action, není možné jej vyvolat na jiném presenteru nebo jiné action.
Signál tedy způsobí znovunačtení stránky úplně stejně jako při původním požadavku, jen navíc zavolá obslužnou metodu signálu s příslušnými parametry. Pokud metoda neexistuje, vyhodí se výjimka [api:Nette\Application\UI\BadSignalException], která se uživateli zobrazí jako chybová stránka 403 Forbidden.
@@ -230,6 +230,28 @@ $this->redirect(/* ... */); // a přesměrujeme
```
+Přesměrování po signálu
+=======================
+
+Po zpracování signálu komponenty často následuje přesměrování. Je to podobná situace jako u formulářů - po jejich odeslání také přesměrováváme, aby při obnovení stránky v prohlížeči nedošlo k opětovnému odeslání dat.
+
+```php
+$this->redirect('this') // přesměruje na aktuální presenter a action
+```
+
+Protože komponenta je znovupoužitelný prvek a obvykle by neměla mít přímou vazbu na konkrétní presentery, metody `redirect()` a `link()` automaticky interpretují parametr jako signál komponenty:
+
+```php
+$this->redirect('click') // přesměruje na signál 'click' téže komponenty
+```
+
+Pokud potřebujete přesměrovat na jiný presenter či akci, můžete to udělat prostřednictvím presenteru:
+
+```php
+$this->getPresenter()->redirect('Product:show'); // přesměruje na jiný presenter/action
+```
+
+
Persistentní parametry
======================
@@ -430,7 +452,7 @@ class PaginatingControl extends Control
}
```
-Opačný proces, tedy sesbírání hodnot z persistentních properites, má na starosti metoda `saveState()`.
+Opačný proces, tedy sesbírání hodnot z persistentních properties, má na starosti metoda `saveState()`.
Signály do hloubky
@@ -444,7 +466,7 @@ Signál může přijímat jakákoliv komponenta, presenter nebo objekt, který i
Mezi hlavní příjemce signálů budou patřit `Presentery` a vizuální komponenty dědící od `Control`. Signál má sloužit jako znamení pro objekt, že má něco udělat – anketa si má započítat hlas od uživatele, blok s novinkami se má rozbalit a zobrazit dvakrát tolik novinek, formulář byl odeslán a má zpracovat data a podobně.
-URL pro signál vytváříme pomocí metody [Component::link() |api:Nette\Application\UI\Component::link()]. Jako parametr `$destination` předáme řetězec `{signal}!` a jako `$args` pole argumentů, které chceme signálu předat. Signál se vždy volá na aktuální view s aktuálními parametry, parametry signálu se jen přidají. Navíc se přidává hned na začátku **parametr `?do`, který určuje signál**.
+URL pro signál vytváříme pomocí metody [Component::link() |api:Nette\Application\UI\Component::link()]. Jako parametr `$destination` předáme řetězec `{signal}!` a jako `$args` pole argumentů, které chceme signálu předat. Signál se vždy volá na aktuálním presenteru a action s aktuálními parametry, parametry signálu se jen přidají. Navíc se přidává hned na začátku **parametr `?do`, který určuje signál**.
Jeho formát je buď `{signal}`, nebo `{signalReceiver}-{signal}`. `{signalReceiver}` je název komponenty v presenteru. Proto nemůže být v názvu komponenty pomlčka – používá se k oddělení názvu komponenty a signálu, je ovšem možné takto zanořit několik komponent.
diff --git a/application/cs/configuration.texy b/application/cs/configuration.texy
index acab7d7adf..84954e2e59 100644
--- a/application/cs/configuration.texy
+++ b/application/cs/configuration.texy
@@ -95,6 +95,9 @@ latte:
# aktivuje [kontrolu vygenerovaného kódu |latte:develop#Kontrola vygenerovaného kódu]
phpLinter: ... # (string) výchozí je null
+ # nastaví locale
+ locale: cs_CZ # (string) výchozí je null
+
# třída objektu $this->template
templateClass: App\MyTemplateClass # výchozí je Nette\Bridges\ApplicationLatte\DefaultTemplate
```
@@ -104,7 +107,7 @@ Pokud používáte Latte verze 3, můžete přidávat nové [rozšíření |latt
```neon
latte:
extensions:
- - Latte\Essential\TranslatorExtension
+ - Latte\Essential\TranslatorExtension(@Nette\Localization\Translator)
```
Pokud používáte Latte verze 2, můžete registrovat nové tagy (makra) buď uvedením jména třídy, nebo referencí na službu. Jako výchozí je zavolána metoda `install()`, ale to lze změnit tím, že uvedeme jméno jiné metody:
diff --git a/application/cs/how-it-works.texy b/application/cs/how-it-works.texy
index 92ff5e9d9b..d58cd6c833 100644
--- a/application/cs/how-it-works.texy
+++ b/application/cs/how-it-works.texy
@@ -22,13 +22,13 @@ Adresářová struktura vypadá nějak takto:
/--pre
web-project/
├── app/ ← adresář s aplikací
-│ ├── Presenters/ ← presentery a šablony
-│ │ ├── HomePresenter.php ← třída presenteru Home
-│ │ └── templates/ ← adresář se šablonami
-│ │ ├── @layout.latte ← šablona layoutu
-│ │ └── Home/ ← šablony presenteru Home
-│ │ └── default.latte ← šablona akce 'default'
-│ ├── Router/ ← konfigurace URL adres
+│ ├── Core/ ← základní třídy nutné pro chod
+│ │ └── RouterFactory.php ← konfigurace URL adres
+│ ├── UI/ ← presentery, šablony & spol.
+│ │ ├── @layout.latte ← šablona layoutu
+│ │ └── Home/ ← adresář presenteru Home
+│ │ ├── HomePresenter.php ← třída presenteru Home
+│ │ └── default.latte ← šablona akce default
│ └── Bootstrap.php ← zaváděcí třída Bootstrap
├── bin/ ← skripty spouštěné z příkazové řádky
├── config/ ← konfigurační soubory
@@ -91,7 +91,7 @@ Aplikace psané v Nette se člení do spousty tzv. presenterů (v jiných framew
Application začne tím, že požádá tzv. router, aby rozhodl, kterému z presenterů předat aktuální požadavek k vyřízení. Router rozhodne, čí je to zodpovědnost. Podívá se na vstupní URL `https://example.com/product/123` a na základě toho, jak je nastavený, rozhodne, že tohle je práce např. pro **presenter** `Product`, po kterém bude chtít jako **akci** zobrazení (`show`) produktu s `id: 123`. Dvojici presenter + akce je dobrým zvykem zapisovat oddělené dvojtečkou jako `Product:show`.
-Tedy router transformoval URL na dvojici `Presenter:action` + parametry, v našem případě `Product:show` + `id: 123`. Jak takový router vypadá se můžete podívat v souboru `app/Router/RouterFactory.php` a podrobně ho popisujeme v kapitole [Routing].
+Tedy router transformoval URL na dvojici `Presenter:action` + parametry, v našem případě `Product:show` + `id: 123`. Jak takový router vypadá se můžete podívat v souboru `app/Core/RouterFactory.php` a podrobně ho popisujeme v kapitole [Routing].
Pojďme dál. Application už zná jméno presenteru a může pokračovat dál. Tím že vyrobí objekt třídy `ProductPresenter`, což je kód presenteru `Product`. Přesněji řečeno, požádá DI kontejner, aby presenter vyrobil, protože od vyrábění je tu on.
@@ -121,12 +121,9 @@ Takže, zavolala se metoda `renderShow(123)`, jejíž kód je sice smyšlený p
Následně presenter vrátí odpověď. Tou může být HTML stránka, obrázek, XML dokument, odeslání souboru z disku, JSON nebo třeba přesměrování na jinou stránku. Důležité je, že pokud explicitně neřekneme, jak má odpovědět (což je případ `ProductPresenter`), bude odpovědí vykreslení šablony s HTML stránkou. Proč? Protože v 99 % případů chceme vykreslit šablonu, tudíž presenter tohle chování bere jako výchozí a chce nám ulehčit práci. To je smyslem Nette.
-Nemusíme ani uvádět, jakou šablonu vykreslit, cestu k ní si odvodí podle jednoduché logiky. V případě presenteru `Product` a akce `show` zkusí, zda existuje jeden z těchto souborů se šablonou uložených relativně od adresáře s třídou `ProductPresenter`:
+Nemusíme ani uvádět, jakou šablonu vykreslit, cestu k ní si odvodí sám. V případě akce `show` jednodušše zkusí načíst šablonu `show.latte` v adresáři s třídou `ProductPresenter`. Taktéž se pokusí dohledat layout v souboru `@layout.latte` (podrobněji o [dohledávání šablon|templates#hledani-sablon]).
-- `templates/Product/show.latte`
-- `templates/Product.show.latte`
-
-Taktéž se pokusí dohledat layout v souboru `@layout.latte` a následně šablonu vykreslí. Tím je úkol presenteru i celé aplikace dokonán a dílo jest završeno. Pokud by šablona neexistovala, vrátí se stránka s chybou 404. Více se o presenterech dočtete na stránce [Presentery|presenters].
+A následně šablony vykreslí. Tím je úkol presenteru i celé aplikace dokonán a dílo jest završeno. Pokud by šablona neexistovala, vrátí se stránka s chybou 404. Více se o presenterech dočtete na stránce [Presentery|presenters].
[* request-flow.svg *]
@@ -137,7 +134,7 @@ Pro jistotu, zkusme si zrekapitulovat celý proces s trošku jinou URL:
3) router URL dekóduje jako dvojici `Home:default`
4) vytvoří se objekt třídy `HomePresenter`
5) zavolá se metoda `renderDefault()` (pokud existuje)
-6) vykreslí se šablona např. `templates/Home/default.latte` s layoutem např. `templates/@layout.latte`
+6) vykreslí se šablona např. `default.latte` s layoutem např. `@layout.latte`
Možná jste se teď setkali s velkou spoustou nových pojmů, ale věříme, že dávají smysl. Tvorba aplikací v Nette je ohromná pohodička.
diff --git a/application/cs/modules.texy b/application/cs/modules.texy
index dd58b910d4..f215baec63 100644
--- a/application/cs/modules.texy
+++ b/application/cs/modules.texy
@@ -2,29 +2,31 @@ Moduly
******
.[perex]
-Moduly představují v Nette logické celky, ze kterých se aplikace skládá. Jejich součástí jsou presentery, šablony, případně i komponenty a modelové třídy.
+Moduly vnášejí do Nette aplikací přehlednost díky snadnému členění do logických celků.
-S jednou složkou pro presentery a jednou pro šablony bychom si u reálných projektů nevystačili. Mít v jedné složce desítky souborů je minimálně nepřehledné. Jak z toho ven? Jednoduše je na disku rozdělíme do podadresářů a v kódu do jmenných prostorů. A přesně to jsou v Nette moduly.
-
-Zapomeňme tedy na jednu složku pro presentery a šablony a místo toho vytvoříme moduly, například `Admin` a `Front`.
+Podobně jako na pevném disku organizujeme soubory do jednotlivých složek, tak i v Nette můžeme presentery, šablony a další pomocné třídy rozdělovat do modulů. Jak to funguje v praxi? Jednoduše začleníme do struktury nové podadresáře. Příklad takové struktury se dvěma moduly Front a Admin:
/--pre
-app/
-├── Presenters/
-├── Modules/ ← adresář s moduly
+app/
+├── UI/
│ ├── Admin/ ← modul Admin
-│ │ ├── Presenters/ ← jeho presentery
-│ │ │ ├── DashboardPresenter.php
-│ │ │ └── templates/
-│ └── Front/ ← modul Front
-│ └── Presenters/ ← jeho presentery
-│ └── ...
+│ │ ├── @layout.latte
+│ │ ├── Dashboard/
+│ │ │ ├── DashboardPresenter.php
+│ │ │ └── default.latte
+│ │ └── ...
+│ ├── Front/ ← modul Front
+│ │ ├── @layout.latte
+│ │ ├── Home/
+│ │ │ ├── HomePresenter.php
+│ │ │ └── default.latte
+│ │ └── ...
\--
-Tuto adresářovou strukturu budou reflektovat jmenné prostory tříd, takže třeba `DashboardPresenter` bude v prostoru `App\Modules\Admin\Presenters`:
+Tato adresářová struktura se odráží ve jmenných prostorech tříd, takže například `DashboardPresenter` se nachází ve jmenném prostoru `App\UI\Admin\Dashboard`:
```php
-namespace App\Modules\Admin\Presenters;
+namespace App\UI\Admin\Dashboard;
class DashboardPresenter extends Nette\Application\UI\Presenter
{
@@ -32,35 +34,49 @@ class DashboardPresenter extends Nette\Application\UI\Presenter
}
```
-Na presenter `Dashboard` uvnitř modulu `Admin` se v rámci aplikace odkazujeme pomocí dvojtečkové notace jako na `Admin:Dashboard`, na jeho akci `default` potom jako na `Admin:Dashboard:default`.
-A jak Nette vlastní ví, že `Admin:Dashboard` představuje třídu `App\Modules\Admin\Presenters\DashboardPresenter`? To mu řekneme pomocí [#mapování] v konfiguraci.
-Tedy uvedená struktura není pevná a můžete si ji upravit podle potřeb.
+Na presenter `Dashboard` uvnitř modulu `Admin` odkazujeme v aplikaci pomocí dvojtečkové notace jako na `Admin:Dashboard`. Na jeho akci `default` potom jako na `Admin:Dashboard:default`.
-Moduly mohou kromě presenterů a šablon samozřejmě obsahovat všechny další součásti, jako jsou třeba komponenty, modelové třídy, atd.
+Představená struktura není pevná; můžete si ji zcela [přizpůsobit dle svých potřeb|#mapování] v konfiguraci. .[tip]
+
+Moduly mohou kromě presenterů a šablon samozřejmě zahrnovat všechny ostatní soubory, jako jsou například komponenty a pomocné třídy. Pokud uvažujete, kam je zařadit, zvažte využití složky `Accessory`:
+
+/--pre
+app/
+├── UI/
+│ ├── Admin/
+│ │ ├── Accessory/
+│ │ │ ├── FormFactory.php
+│ │ │ └── AdminLayout.php
+│ │ ├── Dashboard/
+│ │ └── ...
+\--
Vnořené moduly
--------------
-Moduly nemusí tvořit jen plochou strukturu, lze vytvářet i submoduly, například:
+Moduly mohou mít více úrovní zanoření, podobně jako adresářová struktura na disku:
/--pre
-app/
-├── Modules/ ← adresář s moduly
+app/
+├── UI/
│ ├── Blog/ ← modul Blog
│ │ ├── Admin/ ← submodul Admin
-│ │ │ ├── Presenters/
+│ │ │ ├── Dashboard/
+│ │ │ └── ...
+│ │ ├── Front/ ← submodul Front
+│ │ │ ├── @layout.latte
+│ │ │ ├── Home/
│ │ │ └── ...
-│ │ └── Front/ ← submodul Front
-│ │ ├── Presenters/
-│ │ └── ...
│ ├── Forum/ ← modul Forum
│ │ └── ...
\--
-Tedy modul `Blog` je rozdělen do submodulů `Admin` a `Front`. A opět se to odrazí na jmenných prostorech, které budou `App\Modules\Blog\Admin\Presenters` apod. Na presenter `Dashboard` uvnitř submodulu se odkazujeme jako `Blog:Admin:Dashboard`.
+Modul `Blog` je rozdělen na submoduly `Admin` a `Front`. To se projeví i ve jmenných prostorech, které pak budou vypadat jako `App\UI\Blog\Admin` a podobně. Na presenter `Dashboard` v rámci submodulu odkazujeme jako na `Blog:Admin:Dashboard`.
-Zanořování může pokračovat libovolně hluboko, lze tedy vytvářet sub-submoduly.
+Zanoření může být libovolně hluboké, což umožňuje vytvářet sub-submoduly.
+
+Pokud například v administraci máte mnoho presenterů týkajících se správy objednávek, jako jsou `OrderDetail`, `OrderEdit`, `OrderDispatch` atd., můžete pro lepší organizovanost vytvořit modul `Order`, ve kterém budou presentery `Detail`, `Edit`, `Dispatch` a další.
Vytváření odkazů
@@ -102,46 +118,66 @@ Viz [kapitola o routování |routing#Moduly].
Mapování
--------
-Definuje pravidla, podle kterých se z názvu presenteru odvodí název třídy. Zapisujeme je v [konfiguraci|configuration] pod klíčem `application › mapping`.
+Mapování definuje pravidla pro odvozování názvu třídy z názvu presenteru. Specifikujeme je v [konfiguraci|configuration] pod klíčem `application › mapping`.
+
+Adresářové struktury uváděné výše na této stránce vycházejí z tohoto mapování:
+
+```neon
+application:
+ mapping: App\UI\*\**Presenter
+```
-Začněme ukázkou, která moduly nepoužívá. Budeme jen chtít, aby třídy presenterů měly jmenný prostor `App\Presenters`. Tedy aby se presenter například `Home` mapoval na třídu `App\Presenters\HomePresenter`. Toho lze docílit následující konfigurací:
+Jak mapování funguje? Pro lepší pochopení si nejprve představme aplikaci bez modulů. Chceme, aby třídy presenterů spadaly do jmenného prostoru `App\UI`, aby se presenter `Home` mapoval na třídu `App\UI\HomePresenter`. Což dosáhneme touto konfigurací:
```neon
application:
- mapping: App\Presenters\*Presenter
+ mapping: App\UI\*Presenter
```
-Název presenteru se nahradí za hvezdičku v masce třídy a výsledkem je název třídy. Snadné!
+Mapování funguje tak, že název presenteru `Home` nahradí hvězdičku v masce `App\UI\*Presenter`, čímž získáme výsledný název třídy `App\UI\HomePresenter`. Jednoduché!
+
+Jak ale vidíte v ukázkách v této a dalších kapitolách, třídy presenterů umisťujeme do eponymních podadresářů, například presenter `Home` se mapuje na třídu `App\UI\Home\HomePresenter`. Toho dosáhneme zdvojením dvojtečky (vyžaduje Nette Application 3.2):
+
+```neon
+application:
+ mapping: App\UI\**Presenter
+```
-Pokud presentery členíme do modulů, můžeme pro každý modul mít vlastní mapování:
+Nyní přistoupíme k mapování presenterů do modulů. Pro každý modul můžeme definovat specifické mapování:
```neon
application:
mapping:
- Front: App\Modules\Front\Presenters\*Presenter
- Admin: App\Modules\Admin\Presenters\*Presenter
+ Front: App\UI\Front\**Presenter
+ Admin: App\UI\Admin\**Presenter
Api: App\Api\*Presenter
```
-Nyní se presenter `Front:Home` mapuje na třídu `App\Modules\Front\Presenters\HomePresenter` a presenter `Admin:Dashboard` na třídu `App\Modules\Admin\Presenters\DashboardPresenter`.
+Podle této konfigurace se presenter `Front:Home` mapuje na třídu `App\UI\Front\Home\HomePresenter`, zatímco presenter `Api:OAuth` na třídu `App\Api\OAuthPresenter`.
-Praktičtější bude vytvořit obecné (hvězdičkové) pravidlo, které první dvě nahradí. V masce třídy přibude hvezdička navíc právě pro modul:
+Protože moduly `Front` i `Admin` mají podobný způsob mapování a takových modulů bude nejspíš více, je možné vytvořit obecné pravidlo, které je nahradí. Do masky třídy tak přibude nová hvězdička pro modul:
```neon
application:
mapping:
- *: App\Modules\*\Presenters\*Presenter
+ *: App\UI\*\**Presenter
Api: App\Api\*Presenter
```
-Ale co když používáme vícenásobně zanořené moduly a máme třeba presenter `Admin:User:Edit`? V takovém případě se segment s hvězdičkou představující modul pro každou úroveň jednoduše zopakuje a výsledkem bude třída `App\Modules\Admin\User\Presenters\EditPresenter`.
+Pro vícenásobně zanořené moduly, jako je například presenter `Admin:User:Edit`, se segment s hvězdičkou opakuje pro každou úroveň a výsledkem je třída `App\UI\Admin\User\Edit\EditPresenter`.
Alternativním zápisem je místo řetězce použít pole skládající se ze tří segmentů. Tento zápis je ekvivaletní s předchozím:
```neon
application:
mapping:
- *: [App\Modules, *, Presenters\*Presenter]
+ *: [App\UI, *, **Presenter]
+ Api: [App\Api, '', *Presenter]
```
-Výchozí hodnotou je `*Module\*Presenter`.
+Pokud bychom měli v konfiguraci jen jediné pravidlo, ono obecné, můžeme zkráceně zapsat:
+
+```neon
+application:
+ mapping: App\UI\*\**Presenter
+```
diff --git a/application/cs/presenters.texy b/application/cs/presenters.texy
index 4936a85634..06ff5d50b1 100644
--- a/application/cs/presenters.texy
+++ b/application/cs/presenters.texy
@@ -60,7 +60,7 @@ Obdoba metody `render()`. Zatímco `render()` je určená k tomu, ab
Důležité je, že `action()` se volá dříve než `render()`, takže v ní můžeme případně změnit další běh dějin, tj. změnit šablonu, která se bude kreslit, a také metodu `render()`, která se bude volat. A to pomocí `setView('jineView')`.
-Metodě se předávají parametry z požadavku. Je možné a doporučené uvést parametrům typy, např. `actionShow(int $id, string $slug = null)` - pokud bude parametr `id` chybět nebo pokud nebude integer, presenter vrátí [chybu 404|#Chyba 404 a spol.] a ukončí činnost.
+Metodě se předávají parametry z požadavku. Je možné a doporučené uvést parametrům typy, např. `actionShow(int $id, ?string $slug = null)` - pokud bude parametr `id` chybět nebo pokud nebude integer, presenter vrátí [chybu 404|#Chyba 404 a spol.] a ukončí činnost.
`handle(args...)` .{toc: handle()}
@@ -205,7 +205,7 @@ $this->redirect(/* ... */); // a přesměrujeme
Chyba 404 a spol.
=================
-Pokud nelze splnit požadavek, třeba z důvodu, že článek který chceme zobrazit neexistuje v databázi, vyhodíme chybu 404 metodou `error(string $message = null, int $httpCode = 404)`.
+Pokud nelze splnit požadavek, třeba z důvodu, že článek který chceme zobrazit neexistuje v databázi, vyhodíme chybu 404 metodou `error(?string $message = null, int $httpCode = 404)`.
```php
public function renderShow(int $id): void
@@ -384,7 +384,7 @@ K přesměrování nedojde při AJAXovém nebo POST požadavku, protože by doš
Kanonizaci můžete vyvolat i manuálně pomocí metody `canonicalize()`, které se podobně jako metodě `link()` předá presenter, akce a parametry. Vyrobí odkaz a porovná ho s aktuální URL adresou. Pokud se liší, tak přesměruje na vygenerovaný odkaz.
```php
-public function actionShow(int $id, string $slug = null): void
+public function actionShow(int $id, ?string $slug = null): void
{
$realSlug = $this->facade->getSlugForId($id);
// přesměruje, pokud $slug se liší od $realSlug
@@ -452,17 +452,6 @@ Omezení přístupu pomocí `#[Requires]` .{data-version:3.2.2}
Atribut `#[Requires]` poskytuje pokročilé možnosti pro omezení přístupu k presenterům a jejich metodám. Lze jej použít pro specifikaci HTTP metod, vyžadování AJAXového požadavku, omezení na stejný původ (same origin), a přístup pouze přes forwardování. Atribut lze aplikovat jak na třídy presenterů, tak na jednotlivé metody `action()`, `render()`, `handle()` a `createComponent()`.
-Příklad použití pro omezení přístupu pouze HTTP metodou `POST`:
-
-```php
-use Nette\Application\Attributes\Requires;
-
-#[Requires(methods: 'POST')]
-class MyPresenter extends Nette\Application\UI\Presenter
-{
-}
-```
-
Můžete určit tyto omezení:
- na HTTP metody: `#[Requires(methods: ['GET', 'POST'])]`
- vyžadování AJAXového požadavku: `#[Requires(ajax: true)]`
@@ -470,22 +459,7 @@ Můžete určit tyto omezení:
- přístup pouze přes forward: `#[Requires(forward: true)]`
- omezení na konkrétní akce: `#[Requires(actions: 'default')]`
-Kombinovat podmínky lze uvedením více atributů nebo spojením do jednoho:
-
-```php
-#[Requires(methods: 'POST', ajax: true)]
-public function actionDelete(int $id)
-{
-}
-
-// nebo
-
-#[Requires(methods: 'POST')]
-#[Requires(ajax: true)]
-public function actionDelete(int $id)
-{
-}
-```
+Podrobnosti najdete v návodu [Jak používat atribut Requires |best-practices:attribute-requires].
Kontrola HTTP metody
diff --git a/application/cs/routing.texy b/application/cs/routing.texy
index 3f58166681..ac3cc3aa7a 100644
--- a/application/cs/routing.texy
+++ b/application/cs/routing.texy
@@ -216,7 +216,7 @@ $router->addRoute('//www.%sld%.%tld%/%basePath%//addRoute('/[/]', [
@@ -225,7 +225,7 @@ $router->addRoute('/[/]', [
]);
```
-Nebo můžeme použít tuto formu, všimněte si přepisu validačního regulárního výrazu:
+Pro detailnější specifikaci lze použít ještě rozšířenější formu, kde kromě výchozích hodnot můžeme nastavit i další vlastnosti parametrů, jako třeba validační regulární výraz (viz parametr `id`):
```php
use Nette\Routing\Route;
@@ -243,7 +243,7 @@ $router->addRoute('/[/]', [
]);
```
-Tyto upovídanější formáty se hodí pro doplnění dalších metadat.
+Je důležité poznamenat, že pokud parametry definované v poli nejsou uvedeny v masce cesty, jejich hodnoty nelze změnit, ani pomocí query parametrů uvedených za otazníkem v URL.
Filtry a překlady
@@ -477,10 +477,10 @@ $router->addRoute('index.html \.html?|\.php|>', /* ... */);
Začlenění do aplikace
=====================
-Abychom vytvořený router zapojili do aplikace, musíme o něm říci DI kontejneru. Nejsnazší cesta je připravit továrnu, která objekt routeru vyrobí, a sdělit v konfiguraci kontejneru, že ji má použít. Dejme tomu, že k tomu účelu napíšeme metodu `App\Router\RouterFactory::createRouter()`:
+Abychom vytvořený router zapojili do aplikace, musíme o něm říci DI kontejneru. Nejsnazší cesta je připravit továrnu, která objekt routeru vyrobí, a sdělit v konfiguraci kontejneru, že ji má použít. Dejme tomu, že k tomu účelu napíšeme metodu `App\Core\RouterFactory::createRouter()`:
```php
-namespace App\Router;
+namespace App\Core;
use Nette\Application\Routers\RouteList;
@@ -499,7 +499,7 @@ Do [konfigurace |dependency-injection:services] pak zapíšeme:
```neon
services:
- - App\Router\RouterFactory::createRouter
+ - App\Core\RouterFactory::createRouter
```
Jakékoliv závislosti, třeba na databázi atd, se předají tovární metodě jako její parametry pomocí [autowiringu|dependency-injection:autowiring]:
@@ -663,7 +663,7 @@ Samostatným použitím myslíme využití schopností routeru v aplikaci, kter
Takže opět si vytvoříme metodu, která nám sestaví router, např.:
```php
-namespace App\Router;
+namespace App\Core;
use Nette\Routing\RouteList;
@@ -694,7 +694,7 @@ $httpRequest = $container->getByType(Nette\Http\IRequest::class);
Anebo objekty přímo vyrobíme:
```php
-$router = App\Router\RouterFactory::createRouter();
+$router = App\Core\RouterFactory::createRouter();
$httpRequest = (new Nette\Http\RequestFactory)->fromGlobals();
```
diff --git a/application/cs/templates.texy b/application/cs/templates.texy
index 5d0de8dc1a..470c68748b 100644
--- a/application/cs/templates.texy
+++ b/application/cs/templates.texy
@@ -37,29 +37,75 @@ Ta definuje blok `content`, který se vloží na místo `{include content}` v la
Hledání šablon
--------------
-Cestu k šablonám odvodí presenter podle jednoduché logiky. Zkusí, zda existuje jeden z těchto souborů umístěných relativně od adresáře s třídou presenteru, kde `` je název aktuálního presenteru a `` je název aktuální akce:
+Nemusíte v presenterech uvádět, jaká šablona se má vykreslit, framework cestu odvodí sám a ušetří vám psaní.
-- `templates//.latte`
-- `templates/..latte`
+Pokud používáte adresářovou strukturu, kde každý presenter má vlastní adresář, jednodušše umístěte šablonu do tohoto adresáře pod jménem akce (resp. view), tj. pro akci `default` použijte šablonu `default.latte`:
-Pokud šablonu nenajde, zkusí hledat ještě v adresáři `templates` o úroveň výš, tj. na stejné úrovni, jako je adresář s třídou presenteru.
+/--pre
+app/
+└── UI/
+ └── Home/
+ ├── HomePresenter.php
+ └── default.latte
+\--
-Pokud ani tam šablonu nenajde, je odpovědí [chyba 404|presenters#Chyba 404 a spol.].
+Pokud používáte strukturu, kde jsou společně presentery v jednom adresáři a šablony ve složce `templates`, uložte ji buď do souboru `..latte` nebo `/.latte`:
-Můžete také změnit view pomocí `$this->setView('jineView')`. Nebo místo dohledávání přímo určit jméno souboru se šablonou pomocí `$this->template->setFile('/path/to/template.latte')`.
+/--pre
+app/
+└── Presenters/
+ ├── HomePresenter.php
+ └── templates/
+ ├── Home.default.latte ← 1. varianta
+ └── Home/
+ └── default.latte ← 2. varianta
+\--
+
+Adresář `templates` může být umístěn také o úroveň výš, tj. na stejné úrovni, jako je adresář s třídami presenterů.
+
+Pokud se šablona nenajde, presenter odpoví [chybou 404 - page not found|presenters#Chyba 404 a spol].
+
+View změníte pomocí `$this->setView('jineView')`. Také lze přímo určit soubor se šablonou pomocí `$this->template->setFile('/path/to/template.latte')`.
.[note]
Soubory, kde se dohledávají šablony, lze změnit překrytím metody [formatTemplateFiles() |api:Nette\Application\UI\Presenter::formatTemplateFiles()], která vrací pole možných názvů souborů.
-Layout se očekává v těchto souborech:
-- `templates//@.latte`
-- `templates/.@.latte`
-- `templates/@.latte` layout společný pro více presenterů
+Hledání šablony layoutu
+-----------------------
+
+Nette také automaticky dohledává soubor s layoutem.
+
+Pokud používáte adresářovou strukturu, kde každý presenter má vlastní adresář, umístěte layout buď do složky s presenterem, pokud je specifický jen pro něj, nebo o úroveň výš, pokud je společný pro více presenterů:
+
+/--pre
+app/
+└── UI/
+ ├── @layout.latte ← společný layout
+ └── Home/
+ ├── @layout.latte ← jen pro presenter Home
+ ├── HomePresenter.php
+ └── default.latte
+\--
+
+Pokud používáte strukturu, kde jsou společně presentery v jednom adresáři a šablony ve složce `templates`, bude se layout očekávat na těchto místech:
+
+/--pre
+app/
+└── Presenters/
+ ├── HomePresenter.php
+ └── templates/
+ ├── @layout.latte ← společný layout
+ ├── Home.@layout.latte ← jen pro Home, 1. varianta
+ └── Home/
+ └── @layout.latte ← jen pro Home, 2. varianta
+\--
+
+Pokud se presenter nachází v [modulu|modules], bude se dohledávat i o další adresářové úrovně výš, podle zanoření modulu.
-Kde `` je název aktuálního presenteru a `` je název layoutu, což je standardně `'layout'`. Název lze změnit pomocí `$this->setLayout('jinyLayout')`, takže se budou zkoušet soubory `@jinyLayout.latte`.
+Název layoutu lze změnit pomocí `$this->setLayout('layoutAdmin')` a pak se bude očekávat v souboru `@layoutAdmin.latte`. Také lze přímo určit soubor se šablonou layoutu pomocí `$this->setLayout('/path/to/template.latte')`.
-Můžete také přímo určit jméno souboru se šablonou layoutu pomocí `$this->setLayout('/path/to/template.latte')`. Pomocí `$this->setLayout(false)` se dohledávání layoutu vypne.
+Pomocí `$this->setLayout(false)` nebo značky `{layout none}` uvnitř šablony se dohledávání layoutu vypne.
.[note]
Soubory, kde se dohledávají šablony layoutu, lze změnit překrytím metody [formatLayoutTemplateFiles() |api:Nette\Application\UI\Presenter::formatLayoutTemplateFiles()], která vrací pole možných názvů souborů.
@@ -104,7 +150,7 @@ Anotace `@property-read` je určená pro IDE a statickou analýzu, díky ní bud
Luxusu našeptávání si můžete dopřát i v šablonách, stačí do PhpStorm nainstalovat plugin pro Latte a uvést na začátek šablony název třídy, více v článku "Latte: jak na typový systém":https://blog.nette.org/cs/latte-jak-na-typovy-system:
```latte
-{templateType App\Presenters\ArticleTemplate}
+{templateType App\UI\Article\ArticleTemplate}
...
```
@@ -176,7 +222,7 @@ public function beforeRender(): void
Latte ve verzi 3 nabízí pokročilejší způsob a to vytvoření si [extension |latte:creating-extension] pro každý webový projekt. Kusý příklad takové třídy:
```php
-namespace App\Templating;
+namespace App\UI\Accessory;
final class LatteExtension extends Latte\Extension
{
@@ -214,7 +260,7 @@ Zaregistrujeme ji pomocí [konfigurace |configuration#Šablony Latte]:
```neon
latte:
extensions:
- - App\Templating\LatteExtension
+ - App\UI\Accessory\LatteExtension
```
@@ -239,7 +285,7 @@ Translator je alternativně možné nastavit pomocí [konfigurace |configuration
```neon
latte:
extensions:
- - Latte\Essential\TranslatorExtension
+ - Latte\Essential\TranslatorExtension(@Nette\Localization\Translator)
```
Poté lze překladač používat například jako filtr `|translate`, a to včetně doplňujících parametrů, které se předají metodě `translate()` (viz `foo, bar`):
diff --git a/application/de/ajax.texy b/application/de/ajax.texy
index 9b97c2db0e..fe36f40a83 100644
--- a/application/de/ajax.texy
+++ b/application/de/ajax.texy
@@ -77,6 +77,12 @@ npm install naja
```
+Zunächst müssen Sie die Bibliothek [initialisieren |https://naja.js.org/#/guide/01-install-setup-naja?id=initialization]:
+
+```js
+naja.initialize();
+```
+
Um einen gewöhnlichen Link (Signal) oder eine Formularübermittlung zu einer AJAX-Anfrage zu machen, markieren Sie einfach den entsprechenden Link, das Formular oder die Schaltfläche mit der Klasse `ajax`:
```html
diff --git a/application/de/bootstrap.texy b/application/de/bootstrap.texy
index a5ddc1e604..6c441bfcf9 100644
--- a/application/de/bootstrap.texy
+++ b/application/de/bootstrap.texy
@@ -20,18 +20,44 @@ use Nette\Bootstrap\Configurator;
class Bootstrap
{
- public static function boot(): Configurator
+ private Configurator $configurator;
+ private string $rootDir;
+
+ public function __construct()
+ {
+ $this->rootDir = dirname(__DIR__);
+ // Der Konfigurator ist für das Einrichten der Anwendungsumgebung und der Dienste zuständig.
+ $this->configurator = new Configurator;
+ // Legen Sie das Verzeichnis für temporäre Dateien fest, die von Nette erzeugt werden (z. B. kompilierte Vorlagen)
+ $this->configurator->setTempDirectory($this->rootDir . '/temp');
+ }
+
+ public function bootWebApplication(): Nette\DI\Container
{
- $appDir = dirname(__DIR__);
- $configurator = new Configurator;
- //$configurator->setDebugMode('secret@23.75.345.200');
- $configurator->enableTracy($appDir . '/log');
- $configurator->setTempDirectory($appDir . '/temp');
- $configurator->createRobotLoader()
+ $this->initializeEnvironment();
+ $this->setupContainer();
+ return $this->configurator->createContainer();
+ }
+
+ private function initializeEnvironment(): void
+ {
+ // Nette ist intelligent, und der Entwicklungsmodus wird automatisch aktiviert,
+ // oder Sie können ihn für eine bestimmte IP-Adresse aktivieren, indem Sie die folgende Zeile auskommentieren:
+ // $this->configurator->setDebugMode('secret@23.75.345.200');
+
+ // Aktiviert Tracy: das ultimative "Schweizer Taschenmesser" zur Fehlersuche.
+ $this->configurator->enableTracy($this->rootDir . '/log');
+
+ // RobotLoader: Lädt automatisch alle Klassen im angegebenen Verzeichnis
+ $this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
- $configurator->addConfig($appDir . '/config/common.neon');
- return $configurator;
+ }
+
+ private function setupContainer(): void
+ {
+ // Konfigurationsdateien laden
+ $this->configurator->addConfig($this->rootDir . '/config/common.neon');
}
}
```
@@ -40,16 +66,15 @@ class Bootstrap
index.php .[#toc-index-php]
===========================
-Im Falle von Webanwendungen ist die Ausgangsdatei `index.php`, die sich im öffentlichen Verzeichnis `www/` befindet. Sie überlässt es der Klasse `Bootstrap`, die Umgebung zu initialisieren und den `$configurator` zurückzugeben, der den DI-Container erstellt. Dann wird der Dienst `Application` aufgerufen, der die Webanwendung ausführt:
+Die Ausgangsdatei für Webanwendungen ist `index.php`, die sich im öffentlichen Verzeichnis `www/` befindet. Sie verwendet die Klasse `Bootstrap`, um die Umgebung zu initialisieren und einen DI-Container zu erstellen. Anschließend wird der Dienst `Application` aus dem Container abgerufen, der die Webanwendung startet:
```php
-// Initialisieren der Umgebung + Abrufen des Configurator-Objekts
-$configurator = App\Bootstrap::boot();
-// Erstellen eines DI-Containers
-$container = $configurator->createContainer();
-// DI-Container erstellt ein Nette\Application\Application-Objekt
+$bootstrap = new App\Bootstrap;
+// Initialisierung der Umgebung + Erstellung eines DI-Containers
+$container = $bootstrap->bootWebApplication();
+// DI-Container erstellt ein Nette\Anwendung\Anwendungsobjekt
$application = $container->getByType(Nette\Application\Application::class);
-// Nette-Anwendung starten
+// Starten Sie die Nette-Anwendung und bearbeiten Sie die eingehende Anfrage
$application->run();
```
@@ -66,19 +91,19 @@ Die Auswahl des Modus erfolgt durch automatische Erkennung, so dass in der Regel
Wenn Sie den Entwicklungsmodus in anderen Fällen aktivieren möchten, z. B. für Programmierer, die von einer bestimmten IP-Adresse aus zugreifen, können Sie `setDebugMode()` verwenden:
```php
-$configurator->setDebugMode('23.75.345.200'); // eine oder mehrere IP-Adressen
+$this->configurator->setDebugMode('23.75.345.200'); // eine oder mehrere IP-Adressen
```
Wir empfehlen auf jeden Fall, eine IP-Adresse mit einem Cookie zu kombinieren. Wir speichern ein geheimes Token im `nette-debug` Cookie, z.B. `secret1234`, und der Entwicklungsmodus wird für Programmierer mit dieser Kombination von IP und Cookie aktiviert.
```php
-$configurator->setDebugMode('secret1234@23.75.345.200');
+$this->configurator->setDebugMode('secret1234@23.75.345.200');
```
Wir können den Entwicklermodus auch komplett abschalten, sogar für localhost:
```php
-$configurator->setDebugMode(false);
+$this->configurator->setDebugMode(false);
```
Beachten Sie, dass der Wert `true` den Entwicklermodus standardmäßig einschaltet, was auf einem Produktionsserver niemals passieren sollte.
@@ -90,7 +115,7 @@ Debugging-Werkzeug Tracy .[#toc-debugging-tool-tracy]
Zur einfachen Fehlersuche werden wir das großartige Tool [Tracy |tracy:] einschalten. Im Entwicklermodus zeigt es Fehler an und im Produktionsmodus protokolliert es Fehler in das angegebene Verzeichnis:
```php
-$configurator->enableTracy($appDir . '/log');
+$this->configurator->enableTracy($this->rootDir . '/log');
```
@@ -100,7 +125,7 @@ Temporäre Dateien .[#toc-temporary-files]
Nette verwendet den Cache für DI-Container, RobotLoader, Vorlagen usw. Daher ist es notwendig, den Pfad zu dem Verzeichnis festzulegen, in dem der Cache gespeichert werden soll:
```php
-$configurator->setTempDirectory($appDir . '/temp');
+$this->configurator->setTempDirectory($this->rootDir . '/temp');
```
Unter Linux oder macOS setzen Sie die [Schreibrechte |nette:troubleshooting#Setting directory permissions] für die Verzeichnisse `log/` und `temp/`.
@@ -112,7 +137,7 @@ RobotLoader .[#toc-robotloader]
Normalerweise wollen wir die Klassen automatisch mit [RobotLoader |robot-loader:] laden, also müssen wir ihn starten und ihn Klassen aus dem Verzeichnis laden lassen, in dem sich `Bootstrap.php` befindet (d.h. `__DIR__`) und aus allen seinen Unterverzeichnissen:
```php
-$configurator->createRobotLoader()
+$this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
```
@@ -126,7 +151,7 @@ Zeitzone .[#toc-timezone]
Configurator ermöglicht es Ihnen, eine Zeitzone für Ihre Anwendung festzulegen.
```php
-$configurator->setTimeZone('Europe/Prague');
+$this->configurator->setTimeZone('Europe/Prague');
```
@@ -143,16 +168,17 @@ Im Entwicklungsmodus wird der Container jedes Mal automatisch aktualisiert, wenn
Konfigurationsdateien werden mit `addConfig()` geladen:
```php
-$configurator->addConfig($appDir . '/config/common.neon');
+$this->configurator->addConfig($this->rootDir . '/config/common.neon');
```
Die Methode `addConfig()` kann mehrfach aufgerufen werden, um mehrere Dateien hinzuzufügen.
```php
-$configurator->addConfig($appDir . '/config/common.neon');
-$configurator->addConfig($appDir . '/config/services.neon');
+$configDir = $this->rootDir . '/config';
+$this->configurator->addConfig($configDir . '/common.neon');
+$this->configurator->addConfig($configDir . '/services.neon');
if (PHP_SAPI === 'cli') {
- $configurator->addConfig($appDir . '/config/cli.php');
+ $this->configurator->addConfig($configDir . '/cli.php');
}
```
@@ -169,7 +195,7 @@ Statische Parameter .[#toc-static-parameters]
Parameter, die in Konfigurationsdateien verwendet werden, können [im Abschnitt `parameters` |dependency-injection:configuration#parameters] definiert und auch von der Methode `addStaticParameters()` übergeben (oder überschrieben) werden (sie hat den Alias `addParameters()`). Wichtig ist, dass unterschiedliche Parameterwerte die Erzeugung zusätzlicher DI-Container, d.h. zusätzlicher Klassen, bewirken.
```php
-$configurator->addStaticParameters([
+$this->configurator->addStaticParameters([
'projectId' => 23,
]);
```
@@ -183,7 +209,7 @@ Dynamische Parameter .[#toc-dynamic-parameters]
Wir können dem Container auch dynamische Parameter hinzufügen, deren unterschiedliche Werte, im Gegensatz zu statischen Parametern, nicht die Erzeugung neuer DI-Container verursachen.
```php
-$configurator->addDynamicParameters([
+$this->configurator->addDynamicParameters([
'remoteIp' => $_SERVER['REMOTE_ADDR'],
]);
```
@@ -191,7 +217,7 @@ $configurator->addDynamicParameters([
Umgebungsvariablen können mit dynamischen Parametern leicht verfügbar gemacht werden. Wir können über `%env.variable%` in Konfigurationsdateien auf sie zugreifen.
```php
-$configurator->addDynamicParameters([
+$this->configurator->addDynamicParameters([
'env' => getenv(),
]);
```
@@ -206,6 +232,7 @@ Sie können die folgenden statischen Parameter in den Konfigurationsdateien verw
- `%wwwDir%` ist der absolute Pfad zu dem Verzeichnis, das die `index.php` Eintragsdatei enthält
- `%tempDir%` ist der absolute Pfad zu dem Verzeichnis für temporäre Dateien
- `%vendorDir%` ist der absolute Pfad zu dem Verzeichnis, in dem Composer die Bibliotheken installiert
+- `%rootDir%` ist der absolute Pfad zum Stammverzeichnis des Projekts
- `%debugMode%` gibt an, ob sich die Anwendung im Debug-Modus befindet
- `%consoleMode%` zeigt an, ob die Anfrage über die Befehlszeile kam
@@ -225,7 +252,7 @@ services:
Erstellen Sie eine neue Instanz und fügen Sie sie in Bootstrap ein:
```php
-$configurator->addServices([
+$this->configurator->addServices([
'myservice' => new App\Model\MyCustomService('foobar'),
]);
```
@@ -234,13 +261,21 @@ $configurator->addServices([
Verschiedene Umgebungen .[#toc-different-environments]
======================================================
-Es steht Ihnen frei, die Klasse `Bootstrap` an Ihre Bedürfnisse anzupassen. Sie können der Methode `boot()` Parameter hinzufügen, um Webprojekte zu unterscheiden, oder andere Methoden hinzufügen, wie `bootForTests()`, die die Umgebung für Unit-Tests initialisiert, `bootForCli()` für Skripte, die von der Befehlszeile aus aufgerufen werden, und so weiter.
+Zögern Sie nicht, die Klasse `Bootstrap` nach Ihren Bedürfnissen anzupassen. Sie können der Methode `bootWebApplication()` Parameter hinzufügen, um zwischen Webprojekten zu unterscheiden. Alternativ können Sie auch andere Methoden hinzufügen, z. B. `bootTestEnvironment()`, um die Umgebung für Unit-Tests zu initialisieren, `bootConsoleApplication()` für Skripte, die von der Befehlszeile aus aufgerufen werden, und so weiter.
```php
-public static function bootForTests(): Configurator
+public function bootTestEnvironment(): Nette\DI\Container
+{
+ Tester\Environment::setup(); // Initialisierung des Nette-Testers
+ $this->setupContainer();
+ return $this->configurator->createContainer();
+}
+
+public function bootConsoleApplication(): Nette\DI\Container
{
- $configurator = self::boot();
- Tester\Environment::setup(); // Nette Tester Initialisierung
- return $configurator;
+ $this->configurator->setDebugMode(false);
+ $this->initializeEnvironment();
+ $this->setupContainer();
+ return $this->configurator->createContainer();
}
```
diff --git a/application/de/components.texy b/application/de/components.texy
index a335f73618..d47cc5bd78 100644
--- a/application/de/components.texy
+++ b/application/de/components.texy
@@ -230,6 +230,28 @@ In der Vorlage stehen diese Meldungen in der Variablen `$flashes` als Objekte `s
```
+Umleitung nach einem Signal .[#toc-redirection-after-a-signal]
+==============================================================
+
+Nach der Verarbeitung eines Komponentensignals folgt oft eine Umleitung. Diese Situation ist ähnlich wie bei Formularen - nach dem Absenden eines Formulars leiten wir ebenfalls um, um eine erneute Übermittlung von Daten zu verhindern, wenn die Seite im Browser aktualisiert wird.
+
+```php
+$this->redirect('this') // redirects to the current presenter and action
+```
+
+Da eine Komponente ein wiederverwendbares Element ist und in der Regel keine direkte Abhängigkeit von bestimmten Presentern haben sollte, interpretieren die Methoden `redirect()` und `link()` den Parameter automatisch als Komponentensignal:
+
+```php
+$this->redirect('click') // redirects to the 'click' signal of the same component
+```
+
+Wenn Sie zu einem anderen Präsentator oder einer Aktion umleiten müssen, können Sie dies über den Präsentator tun:
+
+```php
+$this->getPresenter()->redirect('Product:show'); // redirects to a different presenter/action
+```
+
+
Dauerhafte Parameter .[#toc-persistent-parameters]
==================================================
diff --git a/application/de/configuration.texy b/application/de/configuration.texy
index d5b665b684..848f7abb64 100644
--- a/application/de/configuration.texy
+++ b/application/de/configuration.texy
@@ -95,6 +95,9 @@ Latte:
# aktiviert die [Überprüfung von generiertem Code |latte:develop#Checking Generated Code]
phpLinter: ... # (string) Voreinstellung ist null
+ # legt das Gebietsschema fest
+ locale: cs_CZ # (string) Voreinstellung ist null
+
# Klasse von $this->template
templateClass: App\MyTemplateClass # Standardwert ist Nette\Bridges\ApplicationLatte\DefaultTemplate
```
@@ -104,7 +107,7 @@ Wenn Sie Latte Version 3 verwenden, können Sie neue [Erweiterungen |latte:creat
```neon
latte:
extensions:
- - Latte\Essential\TranslatorExtension
+ - Latte\Essential\TranslatorExtension(@Nette\Localization\Translator)
```
/--comment
diff --git a/application/de/how-it-works.texy b/application/de/how-it-works.texy
index 010ba04907..fde1735364 100644
--- a/application/de/how-it-works.texy
+++ b/application/de/how-it-works.texy
@@ -22,13 +22,13 @@ Die Verzeichnisstruktur sieht in etwa so aus:
/--pre
web-project/
├── app/ ← Verzeichnis mit Anwendung
-│ ├── Presenters/ ← Presenter-Klassen
-│ │ ├── HomePresenter.php ← Home presenterklasse
-│ │ └── templates/ ← Vorlagenverzeichnis
-│ │ ├── @layout.latte ← Vorlage für gemeinsames Layout
-│ │ └── Home/ ← Vorlagen für Home-presenter
-│ │ └── default.latte ← Vorlage für Aktion `default`
-│ ├── Router/ ← Konfiguration von URL-Adressen
+│ ├── Core/ ← grundlegende notwendige Klassen
+│ │ └── RouterFactory.php ← Konfiguration der URL-Adressen
+│ ├── UI/ ← Moderatoren, Vorlagen & Co.
+│ │ ├── @layout.latte ← Vorlage für gemeinsames Layout
+│ │ └── Home/ ← Home Presenter Verzeichnis
+│ │ ├── HomePresenter.php ← Home Presenter Klasse
+│ │ └── default.latte ← Vorlage für Aktion default
│ └── Bootstrap.php ← bootende Klasse Bootstrap
├── bin/ ← Skripte für die Kommandozeile
├── config/ ← Konfigurationsdateien
@@ -91,7 +91,7 @@ In Nette geschriebene Anwendungen sind in viele so genannte Presenter unterteilt
Die Anwendung beginnt damit, dass sie den so genannten Router bittet, zu entscheiden, an welchen der Presenter die aktuelle Anfrage zur Bearbeitung weitergeleitet werden soll. Der Router entscheidet, wer dafür zuständig ist. Er sieht sich die Eingabe-URL `https://example.com/product/123` handelt, der ein Produkt mit `id: 123` als Aktion an `show` weiterleiten möchte. Es ist eine gute Angewohnheit, ein durch einen Doppelpunkt getrenntes Paar aus Präsentator + Aktion als `Product:show` zu schreiben.
-Der Router verwandelt also die URL in ein Paar `Presenter:action` + Parameter, in unserem Fall `Product:show` + `id: 123`. Sie können sehen, wie ein Router in der Datei `app/Router/RouterFactory.php` aussieht, und wir werden ihn im Kapitel [Routing] ausführlich beschreiben.
+Der Router verwandelt also die URL in ein Paar `Presenter:action` + Parameter, in unserem Fall `Product:show` + `id: 123`. Sie können sehen, wie ein Router in der Datei `app/Core/RouterFactory.php` aussieht, und wir werden ihn im Kapitel [Routing] ausführlich beschreiben.
Machen wir weiter. Die Anwendung kennt bereits den Namen des Präsentators und kann fortfahren. Sie erstellt ein Objekt `ProductPresenter`, das den Code des Presenters `Product` darstellt. Genauer gesagt, sie bittet den DI-Container um die Erstellung des Presenters, denn die Erstellung von Objekten ist seine Aufgabe.
@@ -121,12 +121,9 @@ So wurde die Methode `renderShow(123)` aufgerufen, deren Code ein fiktives Beisp
Anschließend gibt der Präsentator die Antwort zurück. Dies kann eine HTML-Seite, ein Bild, ein XML-Dokument, das Senden einer Datei von der Festplatte, JSON oder die Routing zu einer anderen Seite sein. Wichtig ist, dass, wenn wir nicht ausdrücklich sagen, wie zu antworten ist (was bei `ProductPresenter` der Fall ist), die Antwort darin besteht, die Vorlage mit einer HTML-Seite wiederzugeben. Und warum? Nun, weil wir in 99 % der Fälle eine Vorlage zeichnen wollen, so dass der Präsentator dieses Verhalten als Standard annimmt und uns die Arbeit erleichtern will. Das ist der Punkt von Nette.
-Wir müssen nicht einmal angeben, welche Vorlage gezeichnet werden soll, er leitet den Pfad dorthin nach einer einfachen Logik ab. Im Fall von presenter `Product` und action `show` versucht er zu sehen, ob eine dieser Vorlagendateien relativ zu dem Verzeichnis existiert, in dem sich die Klasse `ProductPresenter` befindet:
+Wir müssen nicht einmal angeben, welche Vorlage gerendert werden soll; das Framework wird den Pfad selbst ermitteln. Im Fall der Aktion `show` versucht es einfach, die Vorlage `show.latte` im Verzeichnis mit der Klasse `ProductPresenter` zu laden. Es versucht auch, das Layout in der Datei `@layout.latte` zu finden (mehr über die [Vorlagensuche |templates#Template Lookup]).
-- `templates/Product/show.latte`
-- `templates/Product.show.latte`
-
-Außerdem wird versucht, das Layout in der Datei `@layout.latte` zu finden, und dann wird die Vorlage gerendert. Nun ist die Aufgabe des Präsentators und der gesamten Anwendung abgeschlossen. Wenn die Vorlage nicht existiert, wird eine Seite mit dem Fehler 404 zurückgegeben. Weitere Informationen über Präsentatoren finden Sie auf der Seite [Präsentatoren |Presenters].
+Anschließend werden die Vorlagen gerendert. Damit ist die Aufgabe des Präsentators und der gesamten Anwendung abgeschlossen, und die Arbeit ist getan. Wenn die Vorlage nicht vorhanden wäre, würde eine 404-Fehlerseite zurückgegeben werden. Weitere Informationen über Präsentatoren finden Sie auf der Seite [Präsentatoren |presenters].
[* request-flow.svg *]
@@ -137,7 +134,7 @@ Um sicherzugehen, versuchen wir, den gesamten Prozess mit einer etwas anderen UR
3) der Router dekodiert die URL als ein Paar `Home:default`
4) ein `HomePresenter` Objekt wird erstellt
5) die Methode `renderDefault()` wird aufgerufen (falls vorhanden)
-6) eine Vorlage `templates/Home/default.latte` mit einem Layout `templates/@layout.latte` wird gerendert
+6) eine Vorlage `default.latte` mit einem Layout `@layout.latte` wird gerendert
Vielleicht sind Sie jetzt auf eine Menge neuer Konzepte gestoßen, aber wir glauben, dass sie sinnvoll sind. Das Erstellen von Anwendungen in Nette ist ein Kinderspiel.
diff --git a/application/de/modules.texy b/application/de/modules.texy
index 090bd4702e..75981ac23a 100644
--- a/application/de/modules.texy
+++ b/application/de/modules.texy
@@ -2,29 +2,31 @@ Module
******
.[perex]
-In Nette stellen Module die logischen Einheiten dar, aus denen eine Anwendung besteht. Sie umfassen Presenter, Templates, eventuell auch Komponenten und Modellklassen.
+Module bringen Klarheit in Nette-Anwendungen, indem sie eine einfache Unterteilung in logische Einheiten ermöglichen.
-Ein Verzeichnis für Presenter und eines für Templates würde für echte Projekte nicht ausreichen. Dutzende von Dateien in einem Ordner zu haben, ist zumindest unorganisiert. Wie kommt man da wieder raus? Wir teilen sie einfach in Unterverzeichnisse auf der Festplatte und in Namensräume im Code auf. Und das ist genau das, was die Nette-Module tun.
-
-Vergessen wir also einen einzigen Ordner für Präsentatoren und Vorlagen und erstellen wir stattdessen Module, zum Beispiel `Admin` und `Front`.
+Ähnlich wie bei der Organisation von Dateien in Ordnern auf einer Festplatte, können wir in Nette Presenter, Vorlagen und andere Hilfsklassen in Module unterteilen. Wie funktioniert das in der Praxis? Ganz einfach, indem man neue Unterverzeichnisse in die Struktur einfügt. Hier ist ein Beispiel für eine Struktur mit zwei Modulen, Front und Admin:
/--pre
-app/
-├── Presenters/
-├── Modules/ ← Verzeichnis mit Modulen
-│ ├── Admin/ ← Modul Admin
-│ │ ├── Presenters/ ← seine Presenters
-│ │ │ ├── DashboardPresenter.php
-│ │ │ └── templates/
-│ └── Front/ ← Modul Front
-│ └── Presenters/ ← seine Presenters
-│ └── ...
+app/
+├── UI/
+│ ├── Admin/ ← Admin module
+│ │ ├── @layout.latte
+│ │ ├── Dashboard/
+│ │ │ ├── DashboardPresenter.php
+│ │ │ └── default.latte
+│ │ └── ...
+│ ├── Front/ ← Front module
+│ │ ├── @layout.latte
+│ │ ├── Home/
+│ │ │ ├── HomePresenter.php
+│ │ │ └── default.latte
+│ │ └── ...
\--
-Diese Verzeichnisstruktur spiegelt sich in den Klassennamensräumen wider, so dass z. B. `DashboardPresenter` im Namensraum `App\Modules\Admin\Presenters` liegt:
+Diese Verzeichnisstruktur spiegelt sich in den Namespaces der Klassen wider, so befindet sich z.B. `DashboardPresenter` im Namespace `App\UI\Admin\Dashboard`:
```php
-namespace App\Modules\Admin\Presenters;
+namespace App\UI\Admin\Dashboard;
class DashboardPresenter extends Nette\Application\UI\Presenter
{
@@ -32,35 +34,49 @@ class DashboardPresenter extends Nette\Application\UI\Presenter
}
```
-Der Präsentator `Dashboard` innerhalb des Moduls `Admin` wird innerhalb der Anwendung mit der Doppelpunktschreibweise als `Admin:Dashboard` referenziert, und seine Aktion `default` als `Admin:Dashboard:default`.
-Und woher weiß Nette selbst, dass `Admin:Dashboard` die Klasse `App\Modules\Admin\Presenters\DashboardPresenter` repräsentiert? Dies wird durch ein [Mapping |#mapping] in der Konfiguration festgelegt.
-Die vorgegebene Struktur ist also nicht fest vorgegeben und kann nach Belieben verändert werden.
+In der Anwendung wird der Presenter `Dashboard` innerhalb des Moduls `Admin` mit Doppelpunkt als `Admin:Dashboard` bezeichnet. Für die Aktion `default` wird er als `Admin:Dashboard:default` bezeichnet.
-Module können neben Presentern und Templates natürlich auch alle anderen Elemente enthalten, wie z.B. Komponenten, Modellklassen, etc.
+Die vorgestellte Struktur ist nicht starr; Sie können [sie |#mapping] in der Konfiguration [vollständig an Ihre Bedürfnisse anpassen |#mapping]. .[tip]
+
+Module können neben Presentern und Vorlagen auch alle anderen Dateien, wie Komponenten und Hilfsklassen, enthalten. Wenn Sie überlegen, wo Sie diese ablegen wollen, sollten Sie einen Ordner `Accessory` verwenden:
+
+/--pre
+app/
+├── UI/
+│ ├── Admin/
+│ │ ├── Accessory/
+│ │ │ ├── FormFactory.php
+│ │ │ └── AdminLayout.php
+│ │ ├── Dashboard/
+│ │ └── ...
+\--
Verschachtelte Module .[#toc-nested-modules]
--------------------------------------------
-Module müssen nicht nur eine flache Struktur bilden, Sie können auch Untermodule erstellen, zum Beispiel:
+Module können mehrere Verschachtelungsebenen haben, ähnlich wie eine Verzeichnisstruktur auf einer Festplatte:
/--pre
-app/
-├── Modules/ ← Verzeichnis mit Modulen
-│ ├── Blog/ ← Modul Blog
-│ │ ├── Admin/ ← Submodul Admin
-│ │ │ ├── Presenters/
+app/
+├── UI/
+│ ├── Blog/ ← Blog module
+│ │ ├── Admin/ ← Admin submodule
+│ │ │ ├── Dashboard/
+│ │ │ └── ...
+│ │ ├── Front/ ← Front submodule
+│ │ │ ├── @layout.latte
+│ │ │ ├── Home/
│ │ │ └── ...
-│ │ └── Front/ ← Submodul Front
-│ │ ├── Presenters/
-│ │ └── ...
-│ ├── Forum/ ← Modul Forum
+│ ├── Forum/ ← Forum module
│ │ └── ...
\--
-So wird das Modul `Blog` in die Untermodule `Admin` und `Front` aufgeteilt. Dies spiegelt sich auch in den Namensräumen wider, die dann `App\Modules\Blog\Admin\Presenters` usw. lauten. Der Präsentator `Dashboard` innerhalb des Submoduls wird als `Blog:Admin:Dashboard` bezeichnet.
+Das Modul `Blog` ist in die Untermodule `Admin` und `Front` unterteilt. Dies spiegelt sich auch in den Namespaces wider, die dann als `App\UI\Blog\Admin` und ähnlich erscheinen. Um auf den Präsentator `Dashboard` innerhalb des Submoduls `Admin` zu verweisen, wird er als `Blog:Admin:Dashboard` bezeichnet.
-Die Verschachtelung kann beliebig tief gehen, so dass Sub-Submodule erstellt werden können.
+Die Verschachtelung kann so tief wie nötig sein und erlaubt die Erstellung von Sub-Submodulen.
+
+Wenn Sie zum Beispiel in der Verwaltung viele Präsentatoren haben, die mit der Auftragsverwaltung zusammenhängen, wie `OrderDetail`, `OrderEdit`, `OrderDispatch`, usw., könnten Sie ein `Order` Modul erstellen, in dem Präsentatoren wie `Detail`, `Edit`, `Dispatch` und andere organisiert werden.
Erstellen von Links .[#toc-creating-links]
@@ -99,49 +115,69 @@ Routing .[#toc-routing]
Siehe [Kapitel über Routing |routing#Modules].
-Abbildung .[#toc-mapping]
--------------------------
+Kartierung .[#toc-mapping]
+--------------------------
+
+Mapping definiert die Regeln für die Ableitung des Klassennamens aus dem Presenter-Namen. Diese Regeln werden in der [Konfiguration |configuration] unter dem Schlüssel `application › mapping` angegeben.
+
+Die oben auf dieser Seite erwähnten Verzeichnisstrukturen basieren auf der folgenden Zuordnung:
-Legt die Regeln fest, nach denen der Klassenname aus dem Namen des Präsentators abgeleitet wird. Wir schreiben sie in die [Konfiguration |configuration] unter dem Schlüssel `application › mapping`.
+```neon
+application:
+ mapping: App\UI\*\**Presenter
+```
-Beginnen wir mit einem Beispiel, das keine Module verwendet. Wir wollen nur, dass die Presenter-Klassen den Namespace `App\Presenters` haben. Das bedeutet, dass ein Presenter wie `Home` auf die Klasse `App\Presenters\HomePresenter` abgebildet werden soll. Dies kann durch die folgende Konfiguration erreicht werden:
+Wie funktioniert das Mapping? Zum besseren Verständnis stellen wir uns zunächst eine Anwendung ohne Module vor. Wir wollen, dass die Presenter-Klassen in den Namensraum `App\UI` fallen, so dass der Presenter `Home` auf die Klasse `App\UI\HomePresenter` abgebildet wird. Dies kann mit dieser Konfiguration erreicht werden:
```neon
application:
- mapping: App\Presenters\*Presenter
+ mapping: App\UI\*Presenter
```
-Der Name des Presenters wird durch das Sternchen in der Klassenmaske ersetzt und das Ergebnis ist der Klassenname. Einfach!
+Diese Zuordnung funktioniert, indem das Sternchen in der Maske `App\UI\*Presenter` durch den Presenter-Namen `Home` ersetzt wird, was zu dem endgültigen Klassennamen `App\UI\HomePresenter` führt. Einfach!
+
+Wie Sie jedoch in den Beispielen in diesem und anderen Kapiteln sehen können, platzieren wir Presenter-Klassen in gleichnamigen Unterverzeichnissen, z. B. wird der Presenter `Home` der Klasse `App\UI\Home\HomePresenter` zugeordnet. Dies wird durch die Verdoppelung des Sternchens erreicht (erfordert Nette Application 3.2):
+
+```neon
+application:
+ mapping: App\UI\**Presenter
+```
-Wenn wir die Vortragenden in Module unterteilen, können wir für jedes Modul eine eigene Zuordnung vornehmen:
+Gehen wir nun dazu über, Presenter in Modulen abzubilden. Für jedes Modul können wir spezifische Zuordnungen definieren:
```neon
application:
mapping:
- Front: App\Modules\Front\Presenters\*Presenter
- Admin: App\Modules\Admin\Presenters\*Presenter
+ Front: App\UI\Front\**Presenter
+ Admin: App\UI\Admin\**Presenter
Api: App\Api\*Presenter
```
-Der Referent `Front:Home` wird der Klasse `App\Modules\Front\Presenters\HomePresenter` zugeordnet und der Referent `Admin:Dashboard` der Klasse `App\Modules\Admin\Presenters\DashboardPresenter`.
+Nach dieser Konfiguration wird der Präsentator `Front:Home` der Klasse `App\UI\Front\Home\HomePresenter` zugeordnet, während der Präsentator `Api:OAuth` der Klasse `App\Api\OAuthPresenter` zugeordnet wird.
-Es ist praktischer, eine allgemeine (Stern-)Regel zu erstellen, um die ersten beiden zu ersetzen. Das zusätzliche Sternchen wird der Klassenmaske nur für dieses Modul hinzugefügt:
+Da die Module `Front` und `Admin` einen ähnlichen Zuordnungsansatz haben und es wahrscheinlich noch mehr solcher Module gibt, ist es möglich, eine allgemeine Regel zu erstellen, die sie ersetzt. In der Klassenmaske wird ein neues Sternchen für das Modul hinzugefügt:
```neon
application:
mapping:
- *: App\Modules\*\Presenters\*Presenter
+ *: App\UI\*\**Presenter
Api: App\Api\*Presenter
```
-Was aber, wenn wir verschachtelte Module verwenden und einen Präsentator `Admin:User:Edit` haben? In diesem Fall wird das Segment mit dem Sternchen, das das Modul für jede Ebene darstellt, einfach wiederholt und das Ergebnis ist die Klasse `App\Modules\Admin\User\Presenters\EditPresenter`.
+Bei mehrstufig verschachtelten Modulen, wie z. B. dem Moderator `Admin:User:Edit`, wird das Sternchen-Segment für jede Stufe wiederholt, was zu der Klasse `App\UI\Admin\User\Edit\EditPresenter` führt.
-Eine alternative Schreibweise ist die Verwendung eines Arrays, das aus drei Segmenten anstelle einer Zeichenkette besteht. Diese Notation ist gleichwertig mit der vorherigen:
+Eine alternative Schreibweise ist die Verwendung eines Arrays, das aus drei Segmenten besteht, anstelle einer Zeichenkette. Diese Notation ist äquivalent zur vorherigen:
```neon
application:
mapping:
- *: [App\Modules, *, Presenters\*Presenter]
+ *: [App\UI, *, **Presenter]
+ Api: [App\Api, '', *Presenter]
```
-Der Standardwert ist `*Module\*Presenter`.
+Wenn wir nur eine Regel in der Konfiguration haben, die allgemeine, können wir kurz schreiben:
+
+```neon
+application:
+ mapping: App\UI\*\**Presenter
+```
diff --git a/application/de/presenters.texy b/application/de/presenters.texy
index 2407021005..8622224006 100644
--- a/application/de/presenters.texy
+++ b/application/de/presenters.texy
@@ -60,7 +60,7 @@ Unmittelbar nach Erhalt der Anfrage wird die Methode `startup ()` aufgerufen. Si
Es ist wichtig, dass `action()` vor aufgerufen wird `render()`aufgerufen wird, damit wir darin möglicherweise den weiteren Verlauf des Lebenszyklus ändern können, d. h. die Vorlage, die gerendert wird, und auch die Methode `render()` die aufgerufen wird, mit `setView('otherView')`.
-Die Parameter der Anfrage werden an die Methode übergeben. Es ist möglich und empfehlenswert, Typen für die Parameter anzugeben, z. B. `actionShow(int $id, string $slug = null)` - wenn der Parameter `id` fehlt oder keine ganze Zahl ist, gibt der Präsentator den [Fehler 404 |#Error 404 etc.] zurück und bricht die Operation ab.
+Die Parameter der Anfrage werden an die Methode übergeben. Es ist möglich und empfehlenswert, Typen für die Parameter anzugeben, z. B. `actionShow(int $id, ?string $slug = null)` - wenn der Parameter `id` fehlt oder keine ganze Zahl ist, gibt der Präsentator den [Fehler 404 |#Error 404 etc.] zurück und bricht die Operation ab.
`handle(args...)` .{toc: handle()}
@@ -205,7 +205,7 @@ In der Vorlage sind diese Meldungen in der Variablen `$flashes` als Objekte `std
Fehler 404 usw. .[#toc-error-404-etc]
=====================================
-Wenn wir die Anfrage nicht erfüllen können, weil z.B. der Artikel, den wir anzeigen wollen, nicht in der Datenbank existiert, werden wir den Fehler 404 mit der Methode `error(string $message = null, int $httpCode = 404)` ausgeben, die den HTTP-Fehler 404 darstellt:
+Wenn wir die Anfrage nicht erfüllen können, weil z.B. der Artikel, den wir anzeigen wollen, nicht in der Datenbank existiert, werden wir den Fehler 404 mit der Methode `error(?string $message = null, int $httpCode = 404)` ausgeben, die den HTTP-Fehler 404 darstellt:
```php
public function renderShow(int $id): void
@@ -384,7 +384,7 @@ Eine Umleitung findet bei einer AJAX- oder POST-Anfrage nicht statt, da dies zu
Sie können die Kanonisierung auch manuell mit der Methode `canonicalize()` aufrufen, die wie die Methode `link()` den Präsentator, Aktionen und Parameter als Argumente erhält. Sie erstellt einen Link und vergleicht ihn mit der aktuellen URL. Wenn sie sich unterscheidet, wird sie auf den erzeugten Link umgeleitet.
```php
-public function actionShow(int $id, string $slug = null): void
+public function actionShow(int $id, ?string $slug = null): void
{
$realSlug = $this->facade->getSlugForId($id);
// leitet um, wenn $slug nicht mit $realSlug übereinstimmt
@@ -452,17 +452,6 @@ Zugangsbeschränkung mit `#[Requires]` .[#toc-access-restriction-using-requires]
Das Attribut `#[Requires]` Attribut bietet erweiterte Optionen zur Einschränkung des Zugriffs auf Präsentatoren und ihre Methoden. Es kann verwendet werden, um HTTP-Methoden zu spezifizieren, AJAX-Anfragen zu verlangen, den Zugriff auf denselben Ursprung zu beschränken und den Zugriff nur auf Weiterleitungen zu beschränken. Das Attribut kann sowohl auf Presenter-Klassen als auch auf einzelne Methoden angewendet werden, z. B. `action()`, `render()`, `handle()`, und `createComponent()`.
-Hier ein Beispiel für die Beschränkung des Zugriffs nur auf die Methode HTTP `POST`:
-
-```php
-use Nette\Application\Attributes\Requires;
-
-#[Requires(methods: 'POST')]
-class MyPresenter extends Nette\Application\UI\Presenter
-{
-}
-```
-
Sie können diese Einschränkungen angeben:
- auf HTTP-Methoden: `#[Requires(methods: ['GET', 'POST'])]`
- die eine AJAX-Anfrage erfordern: `#[Requires(ajax: true)]`
@@ -470,22 +459,7 @@ Sie können diese Einschränkungen angeben:
- Zugriff nur über Weiterleitung: `#[Requires(forward: true)]`
- Einschränkungen für bestimmte Aktionen: `#[Requires(actions: 'default')]`
-Bedingungen können kombiniert werden, indem mehrere Attribute aufgelistet oder zu einem einzigen zusammengefasst werden:
-
-```php
-#[Requires(methods: 'POST', ajax: true)]
-public function actionDelete(int $id)
-{
-}
-
-// or
-
-#[Requires(methods: 'POST')]
-#[Requires(ajax: true)]
-public function actionDelete(int $id)
-{
-}
-```
+Für Einzelheiten siehe [Verwendung des Requires Attributs |best-practices:attribute-requires].
HTTP-Methodenprüfung .[#toc-http-method-check]
diff --git a/application/de/routing.texy b/application/de/routing.texy
index dac42c271d..f3b4ae88de 100644
--- a/application/de/routing.texy
+++ b/application/de/routing.texy
@@ -216,7 +216,7 @@ $router->addRoute('//www.%sld%.%tld%/%basePath%//addRoute('/[/]', [
@@ -225,7 +225,7 @@ $router->addRoute('/[/]', [
]);
```
-Oder wir können diese Form verwenden, beachten Sie die Umschreibung des regulären Ausdrucks für die Validierung:
+Für eine detailliertere Spezifikation kann eine noch umfangreichere Form verwendet werden, bei der zusätzlich zu den Standardwerten weitere Parametereigenschaften festgelegt werden können, wie z. B. ein regulärer Ausdruck für die Validierung (siehe den Parameter `id` ):
```php
use Nette\Routing\Route;
@@ -243,7 +243,7 @@ $router->addRoute('/[/]', [
]);
```
-Diese gesprächigeren Formate sind nützlich, um andere Metadaten hinzuzufügen.
+Es ist wichtig zu beachten, dass, wenn die im Array definierten Parameter nicht in der Pfadmaske enthalten sind, ihre Werte nicht geändert werden können, auch nicht mit Abfrageparametern, die nach einem Fragezeichen in der URL angegeben werden.
Filter und Übersetzungen .[#toc-filters-and-translations]
@@ -477,10 +477,10 @@ $router->addRoute('index.html \.html?|\.php|>', /* ... */);
Einbindung .[#toc-integration]
==============================
-Um unseren Router in die Anwendung einzubinden, müssen wir ihn dem DI-Container mitteilen. Am einfachsten ist es, die Fabrik vorzubereiten, die das Router-Objekt erstellt, und der Container-Konfiguration mitzuteilen, dass sie es verwenden soll. Schreiben wir also eine Methode für diesen Zweck `App\Router\RouterFactory::createRouter()`:
+Um unseren Router in die Anwendung einzubinden, müssen wir ihn dem DI-Container mitteilen. Am einfachsten ist es, die Fabrik vorzubereiten, die das Router-Objekt erstellt, und der Container-Konfiguration mitzuteilen, dass sie es verwenden soll. Schreiben wir also eine Methode für diesen Zweck `App\Core\RouterFactory::createRouter()`:
```php
-namespace App\Router;
+namespace App\Core;
use Nette\Application\Routers\RouteList;
@@ -499,7 +499,7 @@ Dann schreiben wir in [configuration |dependency-injection:services]:
```neon
services:
- - App\Router\RouterFactory::createRouter
+ - App\Core\RouterFactory::createRouter
```
Alle Abhängigkeiten, wie z. B. eine Datenbankverbindung usw., werden der Factory-Methode als Parameter über [Autowiring |dependency-injection:autowiring] übergeben:
@@ -663,7 +663,7 @@ Unter getrennter Nutzung verstehen wir die Verwendung der Router-Funktionen in e
Wir werden also wieder eine Methode erstellen, die einen Router aufbaut, zum Beispiel:
```php
-namespace App\Router;
+namespace App\Core;
use Nette\Routing\RouteList;
@@ -694,7 +694,7 @@ $httpRequest = $container->getByType(Nette\Http\IRequest::class);
Oder wir erstellen die Objekte direkt:
```php
-$router = App\Router\RouterFactory::createRouter();
+$router = App\Core\RouterFactory::createRouter();
$httpRequest = (new Nette\Http\RequestFactory)->fromGlobals();
```
diff --git a/application/de/templates.texy b/application/de/templates.texy
index a21bd7266f..466cb501c3 100644
--- a/application/de/templates.texy
+++ b/application/de/templates.texy
@@ -34,35 +34,81 @@ Und dies könnte die Aktionsvorlage sein:
Sie definiert den Block `content`, der anstelle von `{include content}` in das Layout eingefügt wird, und definiert auch den Block `title` neu, der `{block title}` im Layout überschreibt. Versuchen Sie, sich das Ergebnis vorzustellen.
-Suche nach Templates .[#toc-search-for-templates]
--------------------------------------------------
+Vorlage nachschlagen .[#toc-template-lookup]
+--------------------------------------------
+
+In Presentern müssen Sie nicht angeben, welche Vorlage gerendert werden soll; das Framework bestimmt den Pfad automatisch, was die Codierung für Sie einfacher macht.
+
+Wenn Sie eine Verzeichnisstruktur verwenden, in der jeder Präsentator sein eigenes Verzeichnis hat, legen Sie die Vorlage einfach in diesem Verzeichnis unter dem Namen der Aktion (d. h. der Ansicht) ab. Verwenden Sie zum Beispiel für die Aktion `default` die Vorlage `default.latte`:
-Der Pfad zu den Vorlagen wird nach einer einfachen Logik hergeleitet. Es wird versucht zu sehen, ob eine dieser Vorlagendateien relativ zu dem Verzeichnis existiert, in dem sich die Presenter-Klasse befindet, wobei `` der Name des aktuellen Präsentators ist und `` der Name der aktuellen Aktion ist:
+/--pre
+app/
+└── UI/
+ └── Home/
+ ├── HomePresenter.php
+ └── default.latte
+\--
-- `templates//.latte`
-- `templates/..latte`
+Wenn Sie eine Struktur verwenden, bei der sich die Präsentatoren in einem Verzeichnis und die Vorlagen in einem Ordner `templates` befinden, speichern Sie sie entweder in einer Datei `..latte` oder `/.latte`:
-Wird die Vorlage nicht gefunden, wird versucht, im Verzeichnis `templates` eine Ebene höher zu suchen, d. h. auf der gleichen Ebene wie das Verzeichnis mit der Presenter-Klasse.
+/--pre
+app/
+└── Presenters/
+ ├── HomePresenter.php
+ └── templates/
+ ├── Home.default.latte ← 1st variant
+ └── Home/
+ └── default.latte ← 2nd variant
+\--
-Wenn die Vorlage auch dort nicht gefunden wird, ist die Antwort ein [404-Fehler |presenters#Error 404 etc.].
+Das Verzeichnis `templates` kann auch eine Ebene höher platziert werden, auf derselben Ebene wie das Verzeichnis mit den Presenter-Klassen.
-Sie können die Ansicht auch mit `$this->setView('otherView')` ändern. Oder geben Sie statt der Suche direkt den Namen der Vorlagendatei mit `$this->template->setFile('/path/to/template.latte')` an.
+Wenn die Vorlage nicht gefunden wird, antwortet der Präsentator mit dem [Fehler 404 - Seite nicht gefunden |presenters#Error 404 etc].
+
+Sie können die Ansicht mit `$this->setView('anotherView')` ändern. Es ist auch möglich, die Vorlagendatei direkt mit `$this->template->setFile('/path/to/template.latte')` anzugeben.
.[note]
-Sie können die Pfade, in denen Vorlagen gesucht werden, ändern, indem Sie die Methode [formatTemplateFiles |api:Nette\Application\UI\Presenter::formatTemplateFiles()] überschreiben, die ein Array mit möglichen Dateipfaden zurückgibt.
+Dateien, in denen Vorlagen gesucht werden, können durch Überschreiben der Methode [formatTemplateFiles() |api:Nette\Application\UI\Presenter::formatTemplateFiles()] geändert werden, die ein Array mit möglichen Dateinamen zurückgibt.
+
+
+Layout-Vorlagen-Suche .[#toc-layout-template-lookup]
+----------------------------------------------------
+
+Nette sucht auch automatisch nach der Layout-Datei.
+
+Wenn Sie eine Verzeichnisstruktur verwenden, in der jeder Präsentator sein eigenes Verzeichnis hat, legen Sie das Layout entweder in dem Ordner mit dem Präsentator ab, wenn es nur für diesen spezifisch ist, oder eine Ebene höher, wenn es für mehrere Präsentatoren gemeinsam ist:
+
+/--pre
+app/
+└── UI/
+ ├── @layout.latte ← common layout
+ └── Home/
+ ├── @layout.latte ← only for Home presenter
+ ├── HomePresenter.php
+ └── default.latte
+\--
+
+Wenn Sie eine Struktur verwenden, bei der die Vortragenden in einem Verzeichnis zusammengefasst sind und sich die Vorlagen in einem Ordner `templates` befinden, wird das Layout an den folgenden Stellen erwartet:
-Das Layout wird in den folgenden Dateien erwartet:
+/--pre
+app/
+└── Presenters/
+ ├── HomePresenter.php
+ └── templates/
+ ├── @layout.latte ← common layout
+ ├── Home.@layout.latte ← only for Home, 1st variant
+ └── Home/
+ └── @layout.latte ← only for Home, 2nd variant
+\--
-- `templates//@.latte`
-- `templates/.@.latte`
-- `templates/@.latte` gemeinsames Layout für mehrere Präsentatoren
+Befindet sich der Präsentator in einem [Modul |modules], wird er auch weiter oben im Verzeichnisbaum entsprechend der Verschachtelung des Moduls gesucht.
-`` ist der Name des aktuellen Präsentators und `` ist der Name des Layouts, der standardmäßig `'layout'` lautet. Der Name kann mit `$this->setLayout('otherLayout')` geändert werden, so dass `@otherLayout.latte` Dateien ausprobiert werden.
+Der Name des Layouts kann mit `$this->setLayout('layoutAdmin')` geändert werden und wird dann in der Datei `@layoutAdmin.latte` erwartet. Sie können die Layout-Vorlagendatei auch direkt mit `$this->setLayout('/path/to/template.latte')` angeben.
-Sie können auch direkt den Dateinamen der Layoutvorlage mit `$this->setLayout('/path/to/template.latte')` angeben. Durch die Verwendung von `$this->setLayout(false)` wird die Layout-Suche deaktiviert.
+Die Verwendung von `$this->setLayout(false)` oder des Tags `{layout none}` innerhalb der Vorlage deaktiviert die Layout-Suche.
.[note]
-Sie können die Pfade, in denen Vorlagen gesucht werden, ändern, indem Sie die Methode [formatLayoutTemplateFiles |api:Nette\Application\UI\Presenter::formatLayoutTemplateFiles()] überschreiben, die ein Array mit möglichen Dateipfaden zurückgibt.
+Die Dateien, in denen Layoutvorlagen gesucht werden, können durch Überschreiben der Methode [formatLayoutTemplateFiles() |api:Nette\Application\UI\Presenter::formatLayoutTemplateFiles()] geändert werden, die ein Array mit möglichen Dateinamen zurückgibt.
Variablen in der Vorlage .[#toc-variables-in-the-template]
@@ -104,7 +150,7 @@ Die `@property-read` Annotation ist für die IDE und die statische Analyse, sie
Sie können sich auch den Luxus gönnen, in Vorlagen zu flüstern. Installieren Sie einfach das Latte-Plugin in PhpStorm und geben Sie den Klassennamen am Anfang der Vorlage an, siehe den Artikel "Latte: how to type system":https://blog.nette.org/de/latte-wie-benutzt-man-das-typensystem:
```latte
-{templateType App\Presenters\ArticleTemplate}
+{templateType App\UI\Article\ArticleTemplate}
...
```
@@ -176,7 +222,7 @@ public function beforeRender(): void
Latte Version 3 bietet einen fortgeschritteneren Weg, indem es eine [Erweiterung |latte:creating-extension] für jedes Webprojekt erstellt. Hier ist ein grobes Beispiel für eine solche Klasse:
```php
-namespace App\Templating;
+namespace App\UI\Accessory;
final class LatteExtension extends Latte\Extension
{
@@ -214,7 +260,7 @@ Wir registrieren sie mit [configuration |configuration#Latte]:
```neon
latte:
extensions:
- - App\Templating\LatteExtension
+ - App\UI\Accessory\LatteExtension
```
@@ -239,7 +285,7 @@ Alternativ kann der Übersetzer auch über die [Konfiguration |configuration#Lat
```neon
latte:
extensions:
- - Latte\Essential\TranslatorExtension
+ - Latte\Essential\TranslatorExtension(@Nette\Localization\Translator)
```
Der Übersetzer kann dann z.B. als Filter `|translate` verwendet werden, wobei zusätzliche Parameter an die Methode `translate()` übergeben werden (siehe `foo, bar`):
diff --git a/application/el/ajax.texy b/application/el/ajax.texy
index de4975d290..ab0e2f48f5 100644
--- a/application/el/ajax.texy
+++ b/application/el/ajax.texy
@@ -77,6 +77,12 @@ npm install naja
```
+Πρώτα πρέπει να [αρχικοποιήσετε |https://naja.js.org/#/guide/01-install-setup-naja?id=initialization] τη βιβλιοθήκη:
+
+```js
+naja.initialize();
+```
+
Για να μετατρέψετε έναν συνηθισμένο σύνδεσμο (σήμα) ή την υποβολή φόρμας σε αίτηση AJAX, απλά σημειώστε τον αντίστοιχο σύνδεσμο, φόρμα ή κουμπί με την κλάση `ajax`:
```html
diff --git a/application/el/bootstrap.texy b/application/el/bootstrap.texy
index 7ee2f81c13..f71018bac5 100644
--- a/application/el/bootstrap.texy
+++ b/application/el/bootstrap.texy
@@ -20,18 +20,44 @@ use Nette\Bootstrap\Configurator;
class Bootstrap
{
- public static function boot(): Configurator
+ private Configurator $configurator;
+ private string $rootDir;
+
+ public function __construct()
+ {
+ $this->rootDir = dirname(__DIR__);
+ // Ο διαμορφωτής είναι υπεύθυνος για τη ρύθμιση του περιβάλλοντος και των υπηρεσιών της εφαρμογής.
+ $this->configurator = new Configurator;
+ // Ορίστε τον κατάλογο για τα προσωρινά αρχεία που παράγονται από τη Nette (π.χ. μεταγλωττισμένα πρότυπα)
+ $this->configurator->setTempDirectory($this->rootDir . '/temp');
+ }
+
+ public function bootWebApplication(): Nette\DI\Container
{
- $appDir = dirname(__DIR__);
- $configurator = new Configurator;
- //$configurator->setDebugMode('secret@23.75.345.200');
- $configurator->enableTracy($appDir . '/log');
- $configurator->setTempDirectory($appDir . '/temp');
- $configurator->createRobotLoader()
+ $this->initializeEnvironment();
+ $this->setupContainer();
+ return $this->configurator->createContainer();
+ }
+
+ private function initializeEnvironment(): void
+ {
+ // Η Nette είναι έξυπνη και η λειτουργία ανάπτυξης ενεργοποιείται αυτόματα,
+ // ή μπορείτε να την ενεργοποιήσετε για μια συγκεκριμένη διεύθυνση IP ξεσχολιάζοντας την ακόλουθη γραμμή:
+ // $this->configurator->setDebugMode('secret@23.75.345.200'),
+
+ // Ενεργοποιεί το Tracy: το απόλυτο εργαλείο αποσφαλμάτωσης "ελβετικό μαχαίρι του στρατού".
+ $this->configurator->enableTracy($this->rootDir . '/log');
+
+ // RobotLoader: αυτόματη φόρτωση όλων των κλάσεων στον δεδομένο κατάλογο
+ $this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
- $configurator->addConfig($appDir . '/config/common.neon');
- return $configurator;
+ }
+
+ private function setupContainer(): void
+ {
+ // Φόρτωση αρχείων διαμόρφωσης
+ $this->configurator->addConfig($this->rootDir . '/config/common.neon');
}
}
```
@@ -40,16 +66,15 @@ class Bootstrap
index.php .[#toc-index-php]
===========================
-Στην περίπτωση των διαδικτυακών εφαρμογών, το αρχικό αρχείο είναι το `index.php`, το οποίο βρίσκεται στον δημόσιο κατάλογο `www/`. Επιτρέπει στην κλάση `Bootstrap` να αρχικοποιήσει το περιβάλλον και να επιστρέψει το `$configurator` που δημιουργεί το DI container. Στη συνέχεια αποκτά την υπηρεσία `Application`, η οποία εκτελεί την εφαρμογή ιστού:
+Το αρχικό αρχείο για τις διαδικτυακές εφαρμογές είναι το `index.php`, το οποίο βρίσκεται στον δημόσιο κατάλογο `www/`. Χρησιμοποιεί την κλάση `Bootstrap` για την αρχικοποίηση του περιβάλλοντος και τη δημιουργία ενός δοχείου DI. Στη συνέχεια, λαμβάνει την υπηρεσία `Application` από το δοχείο, η οποία εκκινεί την εφαρμογή ιστού:
```php
-// αρχικοποίηση του περιβάλλοντος + λήψη του αντικειμένου Configurator
-$configurator = App\Bootstrap::boot();
-// Δημιουργία ενός δοχείου DI
-$container = $configurator->createContainer();
+$bootstrap = new App\Bootstrap;
+// Αρχικοποίηση του περιβάλλοντος + δημιουργία ενός δοχείου DI
+$container = $bootstrap->bootWebApplication();
// Το δοχείο DI δημιουργεί ένα αντικείμενο Nette\Application\Application
$application = $container->getByType(Nette\Application\Application::class);
-// έναρξη της εφαρμογής Nette
+// Εκκίνηση της εφαρμογής Nette και χειρισμός της εισερχόμενης αίτησης
$application->run();
```
@@ -66,19 +91,19 @@ $application->run();
Αν θέλετε να ενεργοποιήσετε τη λειτουργία ανάπτυξης σε άλλες περιπτώσεις, για παράδειγμα, για προγραμματιστές που έχουν πρόσβαση από μια συγκεκριμένη διεύθυνση IP, μπορείτε να χρησιμοποιήσετε τη διεύθυνση `setDebugMode()`:
```php
-$configurator->setDebugMode('23.75.345.200'); // μία ή περισσότερες διευθύνσεις IP
+$this->configurator->setDebugMode('23.75.345.200'); // μία ή περισσότερες διευθύνσεις IP
```
Συνιστούμε οπωσδήποτε τον συνδυασμό μιας διεύθυνσης IP με ένα cookie. Θα αποθηκεύσουμε ένα μυστικό token στο cookie `nette-debug`, π.χ. `secret1234`, και η λειτουργία ανάπτυξης θα ενεργοποιηθεί για τους προγραμματιστές με αυτόν τον συνδυασμό IP και cookie.
```php
-$configurator->setDebugMode('secret1234@23.75.345.200');
+$this->configurator->setDebugMode('secret1234@23.75.345.200');
```
Μπορούμε επίσης να απενεργοποιήσουμε εντελώς τη λειτουργία προγραμματιστή, ακόμη και για το localhost:
```php
-$configurator->setDebugMode(false);
+$this->configurator->setDebugMode(false);
```
Σημειώστε ότι η τιμή `true` ενεργοποιεί τη λειτουργία προγραμματιστή με σκληρό τρόπο, κάτι που δεν πρέπει ποτέ να συμβαίνει σε έναν διακομιστή παραγωγής.
@@ -90,7 +115,7 @@ $configurator->setDebugMode(false);
Για εύκολη αποσφαλμάτωση, θα ενεργοποιήσουμε το σπουδαίο εργαλείο [Tracy |tracy:]. Στη λειτουργία προγραμματιστή απεικονίζει τα σφάλματα και στη λειτουργία παραγωγής καταγράφει τα σφάλματα στον καθορισμένο κατάλογο:
```php
-$configurator->enableTracy($appDir . '/log');
+$this->configurator->enableTracy($this->rootDir . '/log');
```
@@ -100,7 +125,7 @@ $configurator->enableTracy($appDir . '/log');
Η Nette χρησιμοποιεί την κρυφή μνήμη για το DI container, το RobotLoader, τα πρότυπα κ.λπ. Ως εκ τούτου, είναι απαραίτητο να ορίσετε τη διαδρομή προς τον κατάλογο όπου θα αποθηκεύεται η προσωρινή μνήμη:
```php
-$configurator->setTempDirectory($appDir . '/temp');
+$this->configurator->setTempDirectory($this->rootDir . '/temp');
```
Σε Linux ή macOS, ορίστε τα [δικαιώματα εγγραφής |nette:troubleshooting#Setting directory permissions] για τους καταλόγους `log/` και `temp/`.
@@ -112,7 +137,7 @@ RobotLoader .[#toc-robotloader]
Συνήθως, θα θέλουμε να φορτώνουμε αυτόματα τις κλάσεις χρησιμοποιώντας [τον RobotLoader |robot-loader:], οπότε πρέπει να τον εκκινήσουμε και να τον αφήσουμε να φορτώσει κλάσεις από τον κατάλογο όπου βρίσκεται το `Bootstrap.php` (δηλαδή το `__DIR__`) και όλους τους υποκαταλόγους του:
```php
-$configurator->createRobotLoader()
+$this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
```
@@ -126,7 +151,7 @@ $configurator->createRobotLoader()
Το Configurator σας επιτρέπει να καθορίσετε μια ζώνη ώρας για την εφαρμογή σας.
```php
-$configurator->setTimeZone('Europe/Prague');
+$this->configurator->setTimeZone('Europe/Prague');
```
@@ -143,16 +168,17 @@ $configurator->setTimeZone('Europe/Prague');
Τα αρχεία διαμόρφωσης φορτώνονται με τη χρήση του `addConfig()`:
```php
-$configurator->addConfig($appDir . '/config/common.neon');
+$this->configurator->addConfig($this->rootDir . '/config/common.neon');
```
Η μέθοδος `addConfig()` μπορεί να κληθεί πολλές φορές για την προσθήκη πολλών αρχείων.
```php
-$configurator->addConfig($appDir . '/config/common.neon');
-$configurator->addConfig($appDir . '/config/services.neon');
+$configDir = $this->rootDir . '/config';
+$this->configurator->addConfig($configDir . '/common.neon');
+$this->configurator->addConfig($configDir . '/services.neon');
if (PHP_SAPI === 'cli') {
- $configurator->addConfig($appDir . '/config/cli.php');
+ $this->configurator->addConfig($configDir . '/cli.php');
}
```
@@ -169,7 +195,7 @@ if (PHP_SAPI === 'cli') {
Οι παράμετροι που χρησιμοποιούνται σε αρχεία ρυθμίσεων μπορούν να οριστούν [στην ενότητα `parameters` |dependency-injection:configuration#parameters] και επίσης να μεταβιβαστούν (ή να αντικατασταθούν) από τη μέθοδο `addStaticParameters()` (έχει το ψευδώνυμο `addParameters()`). Είναι σημαντικό ότι διαφορετικές τιμές παραμέτρων προκαλούν τη δημιουργία πρόσθετων δοχείων DI, δηλαδή πρόσθετων κλάσεων.
```php
-$configurator->addStaticParameters([
+$this->configurator->addStaticParameters([
'projectId' => 23,
]);
```
@@ -183,7 +209,7 @@ $configurator->addStaticParameters([
Μπορούμε επίσης να προσθέσουμε δυναμικές παραμέτρους στο δοχείο, οι διαφορετικές τιμές τους, σε αντίθεση με τις στατικές παραμέτρους, δεν θα προκαλέσουν τη δημιουργία νέων δοχείων DI.
```php
-$configurator->addDynamicParameters([
+$this->configurator->addDynamicParameters([
'remoteIp' => $_SERVER['REMOTE_ADDR'],
]);
```
@@ -191,7 +217,7 @@ $configurator->addDynamicParameters([
Οι μεταβλητές περιβάλλοντος θα μπορούσαν εύκολα να γίνουν διαθέσιμες με τη χρήση δυναμικών παραμέτρων. Μπορούμε να έχουμε πρόσβαση σε αυτές μέσω της διεύθυνσης `%env.variable%` στα αρχεία ρυθμίσεων.
```php
-$configurator->addDynamicParameters([
+$this->configurator->addDynamicParameters([
'env' => getenv(),
]);
```
@@ -206,6 +232,7 @@ $configurator->addDynamicParameters([
- `%wwwDir%` είναι η απόλυτη διαδρομή προς τον κατάλογο που περιέχει το αρχείο καταχώρησης `index.php`
- `%tempDir%` είναι η απόλυτη διαδρομή προς τον κατάλογο για τα προσωρινά αρχεία
- `%vendorDir%` είναι η απόλυτη διαδρομή προς τον κατάλογο όπου ο Composer εγκαθιστά τις βιβλιοθήκες
+- `%rootDir%` είναι η απόλυτη διαδρομή προς τον ριζικό κατάλογο του έργου
- Το `%debugMode%` δηλώνει αν η εφαρμογή βρίσκεται σε κατάσταση αποσφαλμάτωσης.
- Το `%consoleMode%` δηλώνει αν η αίτηση υποβλήθηκε μέσω της γραμμής εντολών.
@@ -225,7 +252,7 @@ services:
Δημιουργούμε μια νέα περίπτωση και την εισάγουμε στο bootstrap:
```php
-$configurator->addServices([
+$this->configurator->addServices([
'myservice' => new App\Model\MyCustomService('foobar'),
]);
```
@@ -234,13 +261,21 @@ $configurator->addServices([
Διαφορετικά περιβάλλοντα .[#toc-different-environments]
=======================================================
-Μπορείτε να προσαρμόσετε την τάξη `Bootstrap` ανάλογα με τις ανάγκες σας. Μπορείτε να προσθέσετε παραμέτρους στη μέθοδο `boot()` για να διαφοροποιήσετε τα έργα ιστού ή να προσθέσετε άλλες μεθόδους, όπως η `bootForTests()`, η οποία αρχικοποιεί το περιβάλλον για δοκιμές μονάδας, η `bootForCli()` για σενάρια που καλούνται από τη γραμμή εντολών κ.ο.κ.
+Μη διστάσετε να προσαρμόσετε την τάξη `Bootstrap` σύμφωνα με τις ανάγκες σας. Μπορείτε να προσθέσετε παραμέτρους στη μέθοδο `bootWebApplication()` για να διαφοροποιήσετε τα διάφορα web projects. Εναλλακτικά, μπορείτε να προσθέσετε άλλες μεθόδους, όπως `bootTestEnvironment()` για την αρχικοποίηση του περιβάλλοντος για δοκιμές μονάδας, `bootConsoleApplication()` για σενάρια που καλούνται από τη γραμμή εντολών κ.ο.κ.
```php
-public static function bootForTests(): Configurator
+public function bootTestEnvironment(): Nette\DI\Container
{
- $configurator = self::boot();
Tester\Environment::setup(); // Αρχικοποίηση Nette Tester
- return $configurator;
+ $this->setupContainer();
+ return $this->configurator->createContainer();
+}
+
+public function bootConsoleApplication(): Nette\DI\Container
+{
+ $this->configurator->setDebugMode(false);
+ $this->initializeEnvironment();
+ $this->setupContainer();
+ return $this->configurator->createContainer();
}
```
diff --git a/application/el/components.texy b/application/el/components.texy
index ed46dc4e74..06fafcf4d4 100644
--- a/application/el/components.texy
+++ b/application/el/components.texy
@@ -230,6 +230,28 @@ $this->redirect(/* ... */); // και ανακατεύθυνση
```
+Επανακατεύθυνση μετά από ένα σήμα .[#toc-redirection-after-a-signal]
+====================================================================
+
+Μετά την επεξεργασία ενός σήματος συνιστωσών, ακολουθεί συχνά ανακατεύθυνση. Αυτή η κατάσταση είναι παρόμοια με τις φόρμες - μετά την υποβολή μιας φόρμας, κάνουμε επίσης ανακατεύθυνση για να αποτρέψουμε την εκ νέου υποβολή δεδομένων όταν η σελίδα ανανεώνεται στο πρόγραμμα περιήγησης.
+
+```php
+$this->redirect('this') // redirects to the current presenter and action
+```
+
+Δεδομένου ότι ένα συστατικό είναι ένα επαναχρησιμοποιήσιμο στοιχείο και συνήθως δεν πρέπει να έχει άμεση εξάρτηση από συγκεκριμένους παρουσιαστές, οι μέθοδοι `redirect()` και `link()` ερμηνεύουν αυτόματα την παράμετρο ως σήμα συστατικού:
+
+```php
+$this->redirect('click') // redirects to the 'click' signal of the same component
+```
+
+Εάν χρειάζεται να ανακατευθύνετε σε διαφορετικό παρουσιαστή ή ενέργεια, μπορείτε να το κάνετε μέσω του παρουσιαστή:
+
+```php
+$this->getPresenter()->redirect('Product:show'); // redirects to a different presenter/action
+```
+
+
Μόνιμες παράμετροι .[#toc-persistent-parameters]
================================================
@@ -430,7 +452,7 @@ class PaginatingControl extends Control
}
```
-Η αντίθετη διαδικασία, δηλαδή η συλλογή τιμών από persistent properites, αντιμετωπίζεται από τη μέθοδο `saveState()`.
+Η αντίθετη διαδικασία, δηλαδή η συλλογή τιμών από persistent properties, αντιμετωπίζεται από τη μέθοδο `saveState()`.
Σήματα σε βάθος .[#toc-signals-in-depth]
diff --git a/application/el/configuration.texy b/application/el/configuration.texy
index 99bea2563d..dcf8543ece 100644
--- a/application/el/configuration.texy
+++ b/application/el/configuration.texy
@@ -95,6 +95,9 @@ latte:
# ενεργοποιεί τον [έλεγχο του παραγόμενου κώδικα |latte:develop#Checking Generated Code]
phpLinter: ... # (string) η προεπιλογή είναι null
+ # ορίζει την τοπική γλώσσα
+ locale: cs_CZ # (string) η προεπιλογή είναι null
+
# κλάση του $this->template
templateClass: App\MyTemplateClass # προεπιλογή σε Nette\Bridges\ApplicationLatte\DefaultTemplate
```
@@ -104,7 +107,7 @@ latte:
```neon
latte:
extensions:
- - Latte\Essential\TranslatorExtension
+ - Latte\Essential\TranslatorExtension(@Nette\Localization\Translator)
```
/--comment
diff --git a/application/el/how-it-works.texy b/application/el/how-it-works.texy
index f7a4be0a0b..8593798f00 100644
--- a/application/el/how-it-works.texy
+++ b/application/el/how-it-works.texy
@@ -22,13 +22,13 @@
/--pre
web-project/
├── app/ ← directory with application
-│ ├── Presenters/ ← presenter classes
-│ │ ├── HomePresenter.php ← Home presenter class
-│ │ └── templates/ ← templates directory
-│ │ ├── @layout.latte ← template of shared layout
-│ │ └── Home/ ← templates for Home presenter
-│ │ └── default.latte ← template for action `default`
-│ ├── Router/ ← configuration of URL addresses
+│ ├── Core/ ← βασικές αναγκαίες τάξεις
+│ │ └── RouterFactory.php ← διαμόρφωση των διευθύνσεων URL
+│ ├── UI/ ← παρουσιαστές, πρότυπα και λοιπά.
+│ │ ├── @layout.latte ← πρότυπο κοινής διάταξης
+│ │ └── Home/ ← Αρχικός κατάλογος παρουσιαστών
+│ │ ├── HomePresenter.php ← Κλάση οικιακού παρουσιαστή
+│ │ └── default.latte ← πρότυπο για τη δράση default
│ └── Bootstrap.php ← booting class Bootstrap
├── bin/ ← scripts for the command line
├── config/ ← configuration files
@@ -91,7 +91,7 @@ composer create-project nette/web-project
Η εφαρμογή ξεκινά ζητώντας από τον λεγόμενο δρομολογητή να αποφασίσει ποιος από τους παρουσιαστές θα περάσει το τρέχον αίτημα για επεξεργασία. Ο δρομολογητής αποφασίζει ποιανού ευθύνη είναι. Κοιτάζει τη διεύθυνση URL εισόδου `https://example.com/product/123`, ο οποίος θέλει να `show` ένα προϊόν με `id: 123` ως ενέργεια. Είναι καλή συνήθεια να γράφετε τα ζεύγη παρουσιαστής + δράση χωρισμένα με άνω και κάτω τελεία ως `Product:show`.
-Έτσι, ο δρομολογητής μετατρέπει τη διεύθυνση URL σε ένα ζεύγος `Presenter:action` + παράμετροι, στην περίπτωσή μας `Product:show` + `id: 123`. Μπορείτε να δείτε πώς μοιάζει ένας δρομολογητής στο αρχείο `app/Router/RouterFactory.php` και θα τον περιγράψουμε αναλυτικά στο κεφάλαιο [Δρομολόγηση |Routing].
+Έτσι, ο δρομολογητής μετατρέπει τη διεύθυνση URL σε ένα ζεύγος `Presenter:action` + παράμετροι, στην περίπτωσή μας `Product:show` + `id: 123`. Μπορείτε να δείτε πώς μοιάζει ένας δρομολογητής στο αρχείο `app/Core/RouterFactory.php` και θα τον περιγράψουμε αναλυτικά στο κεφάλαιο [Δρομολόγηση |Routing].
Ας συνεχίσουμε. Η εφαρμογή γνωρίζει ήδη το όνομα του παρουσιαστή και μπορεί να συνεχίσει. Δημιουργώντας ένα αντικείμενο `ProductPresenter`, το οποίο είναι ο κώδικας του παρουσιαστή `Product`. Πιο συγκεκριμένα, ζητάει από το DI container τη δημιουργία του presenter, επειδή η παραγωγή αντικειμένων είναι η δουλειά του.
@@ -121,12 +121,9 @@ class ProductPresenter extends Nette\Application\UI\Presenter
Στη συνέχεια, ο παρουσιαστής επιστρέφει την απάντηση. Αυτό μπορεί να είναι μια σελίδα HTML, μια εικόνα, ένα έγγραφο XML, η αποστολή ενός αρχείου από το δίσκο, JSON ή η ανακατεύθυνση σε μια άλλη σελίδα. Σημαντικό είναι ότι, αν δεν πούμε ρητά πώς να απαντήσουμε (κάτι που συμβαίνει στην περίπτωση του `ProductPresenter`), η απάντηση θα είναι η απόδοση του προτύπου με μια σελίδα HTML. Γιατί; Λοιπόν, επειδή στο 99% των περιπτώσεων θέλουμε να σχεδιάσουμε ένα πρότυπο, οπότε ο παρουσιαστής θεωρεί αυτή τη συμπεριφορά ως προεπιλεγμένη και θέλει να διευκολύνει τη δουλειά μας. Αυτό είναι το νόημα της Nette.
-Δεν χρειάζεται καν να δηλώσουμε ποιο πρότυπο θέλουμε να σχεδιάσουμε, αυτός εξάγει τη διαδρομή προς αυτό σύμφωνα με απλή λογική. Στην περίπτωση του presenter `Product` και της δράσης `show`, προσπαθεί να δει αν ένα από αυτά τα αρχεία προτύπων υπάρχει σε σχέση με τον κατάλογο όπου βρίσκεται η κλάση `ProductPresenter`:
+Δεν χρειάζεται καν να καθορίσουμε ποιο πρότυπο θα αναπαραχθεί- το πλαίσιο θα βρει μόνο του τη διαδρομή. Στην περίπτωση της ενέργειας `show`, απλώς προσπαθεί να φορτώσει το πρότυπο `show.latte` στον κατάλογο με την κλάση `ProductPresenter`. Προσπαθεί επίσης να βρει τη διάταξη στο αρχείο `@layout.latte` (περισσότερα για την [αναζήτηση προτύπων |templates#Template Lookup]).
-- `templates/Product/show.latte`
-- `templates/Product.show.latte`
-
-Θα προσπαθήσει επίσης να βρει τη διάταξη στο αρχείο `@layout.latte` και στη συνέχεια θα αποδώσει το πρότυπο. Τώρα ολοκληρώνεται η εργασία του παρουσιαστή και ολόκληρης της εφαρμογής. Εάν το πρότυπο δεν υπάρχει, θα επιστραφεί μια σελίδα με σφάλμα 404. Μπορείτε να διαβάσετε περισσότερα για τους παρουσιαστές στη σελίδα [Παρουσιαστές |Presenters].
+Στη συνέχεια, τα πρότυπα αποδίδονται. Με αυτόν τον τρόπο ολοκληρώνεται η εργασία του παρουσιαστή και ολόκληρης της εφαρμογής, και η εργασία έχει τελειώσει. Εάν το πρότυπο δεν υπήρχε, θα επιστρεφόταν μια σελίδα σφάλματος 404. Μπορείτε να διαβάσετε περισσότερα για τους παρουσιαστές στη σελίδα [Παρουσιαστές |presenters].
[* request-flow.svg *]
@@ -137,7 +134,7 @@ class ProductPresenter extends Nette\Application\UI\Presenter
3) ο δρομολογητής αποκωδικοποιεί τη διεύθυνση URL ως ζεύγος `Home:default`
4) δημιουργείται ένα αντικείμενο `HomePresenter`
5) καλείται η μέθοδος `renderDefault()` (αν υπάρχει)
-6) αποδίδεται ένα πρότυπο `templates/Home/default.latte` με διάταξη `templates/@layout.latte`
+6) αποδίδεται ένα πρότυπο `default.latte` με διάταξη `@layout.latte`
Μπορεί να έχετε συναντήσει πολλές νέες έννοιες τώρα, αλλά πιστεύουμε ότι βγάζουν νόημα. Η δημιουργία εφαρμογών στη Nette είναι πανεύκολη.
diff --git a/application/el/modules.texy b/application/el/modules.texy
index 3277cccce0..5e22451dba 100644
--- a/application/el/modules.texy
+++ b/application/el/modules.texy
@@ -2,29 +2,31 @@
********
.[perex]
-Στη Nette, οι ενότητες αντιπροσωπεύουν τις λογικές μονάδες που συνθέτουν μια εφαρμογή. Περιλαμβάνουν παρουσιαστές, πρότυπα, ενδεχομένως επίσης συστατικά και κλάσεις μοντέλων.
+Οι ενότητες φέρνουν σαφήνεια στις εφαρμογές Nette διευκολύνοντας τον εύκολο διαχωρισμό σε λογικές μονάδες.
-Ένας κατάλογος για τους παρουσιαστές και ένας για τα πρότυπα δεν θα ήταν αρκετός για πραγματικά έργα. Το να έχετε δεκάδες αρχεία σε έναν φάκελο είναι τουλάχιστον ανοργάνωτο. Πώς να απαλλαγείτε από αυτό; Απλώς τα χωρίζουμε σε υποκαταλόγους στο δίσκο και σε χώρους ονομάτων στον κώδικα. Και αυτό ακριβώς κάνουν τα modules της Nette.
-
-Ας ξεχάσουμε λοιπόν έναν ενιαίο φάκελο για τους παρουσιαστές και τα πρότυπα και ας δημιουργήσουμε αντ' αυτού ενότητες, για παράδειγμα `Admin` και `Front`.
+Παρόμοια με την οργάνωση των αρχείων σε φακέλους σε ένα σκληρό δίσκο, στη Nette μπορούμε να χωρίσουμε τους παρουσιαστές, τα πρότυπα και άλλες βοηθητικές κλάσεις σε ενότητες. Πώς λειτουργεί αυτό στην πράξη; Απλά με την ενσωμάτωση νέων υποκαταλόγων στη δομή. Ακολουθεί ένα παράδειγμα δομής με δύο ενότητες, Front και Admin:
/--pre
-app/
-├── Presenters/
-├── Modules/ ← directory with modules
-│ ├── Admin/ ← module Admin
-│ │ ├── Presenters/ ← its presenters
-│ │ │ ├── DashboardPresenter.php
-│ │ │ └── templates/
-│ └── Front/ ← module Front
-│ └── Presenters/ ← its presenters
-│ └── ...
+app/
+├── UI/
+│ ├── Admin/ ← Admin module
+│ │ ├── @layout.latte
+│ │ ├── Dashboard/
+│ │ │ ├── DashboardPresenter.php
+│ │ │ └── default.latte
+│ │ └── ...
+│ ├── Front/ ← Front module
+│ │ ├── @layout.latte
+│ │ ├── Home/
+│ │ │ ├── HomePresenter.php
+│ │ │ └── default.latte
+│ │ └── ...
\--
-Αυτή η δομή καταλόγου θα αντικατοπτρίζεται από τα namespaces των κλάσεων, έτσι για παράδειγμα το `DashboardPresenter` θα βρίσκεται στο namespace `App\Modules\Admin\Presenters`:
+Αυτή η δομή καταλόγου αντικατοπτρίζεται στα namespaces των κλάσεων, έτσι για παράδειγμα, η `DashboardPresenter` βρίσκεται στο namespace `App\UI\Admin\Dashboard`:
```php
-namespace App\Modules\Admin\Presenters;
+namespace App\UI\Admin\Dashboard;
class DashboardPresenter extends Nette\Application\UI\Presenter
{
@@ -32,35 +34,49 @@ class DashboardPresenter extends Nette\Application\UI\Presenter
}
```
-Ο παρουσιαστής `Dashboard` μέσα στην ενότητα `Admin` αναφέρεται μέσα στην εφαρμογή χρησιμοποιώντας τον συμβολισμό της άνω και κάτω τελείας ως `Admin:Dashboard`, και η ενέργεια `default` ως `Admin:Dashboard:default`.
-Και πώς γνωρίζει η Nette proper ότι το `Admin:Dashboard` αντιπροσωπεύει την κλάση `App\Modules\Admin\Presenters\DashboardPresenter`; Αυτό καθορίζεται από την [αντιστοίχιση |#mapping] στη διαμόρφωση.
-Έτσι, η δεδομένη δομή δεν είναι αυστηρά καθορισμένη και μπορείτε να την τροποποιήσετε ανάλογα με τις ανάγκες σας.
+Στην εφαρμογή, αναφερόμαστε στον παρουσιαστή `Dashboard` μέσα στην ενότητα `Admin` χρησιμοποιώντας τον συμβολισμό της άνω και κάτω τελείας ως `Admin:Dashboard`. Για τη δράση του `default`, αναφερόμαστε σε αυτόν ως `Admin:Dashboard:default`.
-Οι ενότητες μπορούν φυσικά να περιέχουν όλα τα άλλα στοιχεία εκτός από τους παρουσιαστές και τα πρότυπα, όπως συστατικά, κλάσεις μοντέλων κ.λπ.
+Η δομή που παρουσιάζεται δεν είναι άκαμπτη- μπορείτε να [την προσαρμόσετε πλήρως στις ανάγκες σας |#mapping] στη διαμόρφωση. .[tip]
+
+Οι ενότητες μπορούν να περιλαμβάνουν όλα τα άλλα αρχεία, όπως συστατικά και βοηθητικές κλάσεις, εκτός από τους παρουσιαστές και τα πρότυπα. Αν σκέφτεστε πού να τα τοποθετήσετε αυτά, σκεφτείτε να χρησιμοποιήσετε έναν φάκελο `Accessory`:
+
+/--pre
+app/
+├── UI/
+│ ├── Admin/
+│ │ ├── Accessory/
+│ │ │ ├── FormFactory.php
+│ │ │ └── AdminLayout.php
+│ │ ├── Dashboard/
+│ │ └── ...
+\--
Ενσωματωμένες ενότητες .[#toc-nested-modules]
---------------------------------------------
-Οι ενότητες δεν χρειάζεται να σχηματίζουν μόνο μια επίπεδη δομή, μπορείτε επίσης να δημιουργήσετε υποενότητες, για παράδειγμα:
+Οι ενότητες μπορούν να έχουν πολλαπλά επίπεδα ένθεσης, παρόμοια με μια δομή καταλόγου σε ένα δίσκο:
/--pre
-app/
-├── Modules/ ← directory with modules
-│ ├── Blog/ ← module Blog
-│ │ ├── Admin/ ← submodule Admin
-│ │ │ ├── Presenters/
+app/
+├── UI/
+│ ├── Blog/ ← Blog module
+│ │ ├── Admin/ ← Admin submodule
+│ │ │ ├── Dashboard/
+│ │ │ └── ...
+│ │ ├── Front/ ← Front submodule
+│ │ │ ├── @layout.latte
+│ │ │ ├── Home/
│ │ │ └── ...
-│ │ └── Front/ ← submodule Front
-│ │ ├── Presenters/
-│ │ └── ...
-│ ├── Forum/ ← module Forum
+│ ├── Forum/ ← Forum module
│ │ └── ...
\--
-Έτσι, η ενότητα `Blog` χωρίζεται σε υποενότητες `Admin` και `Front`. Και πάλι, αυτό θα αντικατοπτρίζεται στα namespaces, τα οποία θα είναι `App\Modules\Blog\Admin\Presenters` κ.λπ. Ο παρουσιαστής `Dashboard` μέσα στην υποενότητα αναφέρεται ως `Blog:Admin:Dashboard`.
+Η ενότητα `Blog` χωρίζεται σε υποενότητες `Admin` και `Front`. Αυτό αντικατοπτρίζεται επίσης στα namespaces, τα οποία εμφανίζονται ως `App\UI\Blog\Admin` και παρόμοια. Για να αναφερθούμε στον παρουσιαστή `Dashboard` μέσα στην υποενότητα `Admin`, αναφερόμαστε σε αυτόν ως `Blog:Admin:Dashboard`.
-Η ένθεση μπορεί να προχωρήσει όσο βαθιά θέλετε, οπότε μπορούν να δημιουργηθούν υπο-υποενότητες.
+Η φωλεοποίηση μπορεί να είναι όσο βαθιά χρειάζεται, επιτρέποντας τη δημιουργία υπο-υπομονάδων.
+
+Για παράδειγμα, αν στη διαχείριση έχετε πολλούς παρουσιαστές που σχετίζονται με τη διαχείριση παραγγελιών, όπως `OrderDetail`, `OrderEdit`, `OrderDispatch`, κ.λπ., μπορείτε να δημιουργήσετε μια ενότητα `Order` στην οποία θα οργανωθούν παρουσιαστές όπως `Detail`, `Edit`, `Dispatch` και άλλοι.
Δημιουργία συνδέσμων .[#toc-creating-links]
@@ -102,46 +118,66 @@ class DashboardPresenter extends Nette\Application\UI\Presenter
Χαρτογράφηση .[#toc-mapping]
----------------------------
-Καθορίζει τους κανόνες με τους οποίους το όνομα της κλάσης προκύπτει από το όνομα του παρουσιαστή. Τους γράφουμε στη [διαμόρφωση |configuration] κάτω από το κλειδί `application › mapping`.
+Η αντιστοίχιση ορίζει τους κανόνες για την εξαγωγή του ονόματος της κλάσης από το όνομα του παρουσιαστή. Οι κανόνες αυτοί καθορίζονται στη [διαμόρφωση |configuration] στο κλειδί `application › mapping`.
+
+Οι δομές καταλόγων που αναφέρθηκαν νωρίτερα σε αυτή τη σελίδα βασίζονται στην ακόλουθη αντιστοίχιση:
+
+```neon
+application:
+ mapping: App\UI\*\**Presenter
+```
-Ας ξεκινήσουμε με ένα δείγμα που δεν χρησιμοποιεί ενότητες. Θα θέλουμε απλώς οι κλάσεις presenter να έχουν το namespace `App\Presenters`. Αυτό σημαίνει ότι ένας παρουσιαστής όπως το `Home` θα πρέπει να αντιστοιχίζεται στην κλάση `App\Presenters\HomePresenter`. Αυτό μπορεί να επιτευχθεί με την ακόλουθη διαμόρφωση:
+Πώς λειτουργεί η χαρτογράφηση; Για καλύτερη κατανόηση, ας φανταστούμε πρώτα μια εφαρμογή χωρίς ενότητες. Θέλουμε οι κλάσεις του παρουσιαστή να υπάγονται στο χώρο ονομάτων `App\UI`, έτσι ώστε ο παρουσιαστής `Home` να αντιστοιχίζεται στην κλάση `App\UI\HomePresenter`. Αυτό μπορεί να επιτευχθεί με αυτή τη διαμόρφωση:
```neon
application:
- mapping: App\Presenters\*Presenter
+ mapping: App\UI\*Presenter
```
-Το όνομα του παρουσιαστή αντικαθίσταται με τον αστερίσκο στη μάσκα κλάσης και το αποτέλεσμα είναι το όνομα της κλάσης. Εύκολο!
+Αυτή η αντιστοίχιση λειτουργεί αντικαθιστώντας τον αστερίσκο στη μάσκα `App\UI\*Presenter` με το όνομα του παρουσιαστή `Home`, με αποτέλεσμα το τελικό όνομα της κλάσης `App\UI\HomePresenter`. Απλό!
+
+Ωστόσο, όπως μπορείτε να δείτε στα παραδείγματα σε αυτό και σε άλλα κεφάλαια, τοποθετούμε τις κλάσεις παρουσιαστή σε επώνυμους υποκαταλόγους, π.χ. ο παρουσιαστής `Home` αντιστοιχίζεται στην κλάση `App\UI\Home\HomePresenter`. Αυτό επιτυγχάνεται με τον διπλασιασμό του αστερίσκου (απαιτεί Nette Application 3.2):
+
+```neon
+application:
+ mapping: App\UI\**Presenter
+```
-Αν χωρίσουμε τους παρουσιαστές σε ενότητες, μπορούμε να έχουμε τη δική μας χαρτογράφηση για κάθε ενότητα:
+Τώρα, ας προχωρήσουμε στην αντιστοίχιση των παρουσιαστών σε ενότητες. Μπορούμε να ορίσουμε συγκεκριμένες αντιστοιχίσεις για κάθε ενότητα:
```neon
application:
mapping:
- Front: App\Modules\Front\Presenters\*Presenter
- Admin: App\Modules\Admin\Presenters\*Presenter
+ Front: App\UI\Front\**Presenter
+ Admin: App\UI\Admin\**Presenter
Api: App\Api\*Presenter
```
-Τώρα ο παρουσιαστής `Front:Home` αντιστοιχίζεται στην κλάση `App\Modules\Front\Presenters\HomePresenter` και ο παρουσιαστής `Admin:Dashboard` στην κλάση `App\Modules\Admin\Presenters\DashboardPresenter`.
+Σύμφωνα με αυτή τη διαμόρφωση, ο παρουσιαστής `Front:Home` αντιστοιχίζεται στην κλάση `App\UI\Front\Home\HomePresenter`, ενώ ο παρουσιαστής `Api:OAuth` αντιστοιχίζεται στην κλάση `App\Api\OAuthPresenter`.
-Είναι πιο πρακτικό να δημιουργήσετε έναν γενικό κανόνα (αστέρι) για να αντικαταστήσετε τους δύο πρώτους. Ο επιπλέον αστερίσκος θα προστεθεί στη μάσκα κλάσης μόνο για την ενότητα:
+Δεδομένου ότι οι ενότητες `Front` και `Admin` έχουν παρόμοια προσέγγιση αντιστοίχισης και είναι πιθανό να υπάρχουν περισσότερες τέτοιες ενότητες, είναι δυνατόν να δημιουργηθεί ένας γενικός κανόνας που να τις αντικαθιστά. Ένας νέος αστερίσκος για την ενότητα προστίθεται στη μάσκα κλάσης:
```neon
application:
mapping:
- *: App\Modules\*\Presenters\*Presenter
+ *: App\UI\*\**Presenter
Api: App\Api\*Presenter
```
-Τι γίνεται όμως αν χρησιμοποιούμε φωλιασμένες ενότητες και έχουμε έναν παρουσιαστή `Admin:User:Edit`; Σε αυτή την περίπτωση, το τμήμα με τον αστερίσκο που αντιπροσωπεύει την ενότητα για κάθε επίπεδο απλώς επαναλαμβάνεται και το αποτέλεσμα είναι η κλάση `App\Modules\Admin\User\Presenters\EditPresenter`.
+Για πολυεπίπεδες φωλιασμένες ενότητες, όπως ο παρουσιαστής `Admin:User:Edit`, το τμήμα αστερίσκου επαναλαμβάνεται για κάθε επίπεδο, με αποτέλεσμα την κλάση `App\UI\Admin\User\Edit\EditPresenter`.
-Ένας εναλλακτικός συμβολισμός είναι η χρήση ενός πίνακα που αποτελείται από τρία τμήματα αντί για συμβολοσειρά. Αυτή η σημειογραφία είναι ισοδύναμη με την προηγούμενη:
+Ένας εναλλακτικός συμβολισμός είναι η χρήση ενός πίνακα που αποτελείται από τρία τμήματα αντί για μια συμβολοσειρά. Αυτός ο συμβολισμός είναι ισοδύναμος με τον προηγούμενο:
```neon
application:
mapping:
- *: [App\Modules, *, Presenters\*Presenter]
+ *: [App\UI, *, **Presenter]
+ Api: [App\Api, '', *Presenter]
```
-Η προεπιλεγμένη τιμή είναι `*Module\*Presenter`.
+Αν έχουμε μόνο έναν κανόνα στη διαμόρφωση, τον γενικό, μπορούμε να γράψουμε συνοπτικά:
+
+```neon
+application:
+ mapping: App\UI\*\**Presenter
+```
diff --git a/application/el/presenters.texy b/application/el/presenters.texy
index 3f55886ec4..8b7a737672 100644
--- a/application/el/presenters.texy
+++ b/application/el/presenters.texy
@@ -60,7 +60,7 @@ class ArticlePresenter extends Nette\Application\UI\Presenter
Είναι σημαντικό ότι `action()` καλείται πριν από την `render()`, ώστε μέσα σε αυτό να μπορούμε ενδεχομένως να αλλάξουμε την επόμενη πορεία του κύκλου ζωής, δηλαδή να αλλάξουμε το πρότυπο που θα αποδοθεί και επίσης τη μέθοδο `render()` που θα κληθεί, χρησιμοποιώντας το `setView('otherView')`.
-Οι παράμετροι από το αίτημα περνούν στη μέθοδο. Είναι δυνατόν και συνιστάται να καθορίσετε τύπους για τις παραμέτρους, π.χ. `actionShow(int $id, string $slug = null)` - αν η παράμετρος `id` λείπει ή αν δεν είναι ακέραιος αριθμός, ο παρουσιαστής επιστρέφει [σφάλμα 404 |#Error 404 etc.] και τερματίζει τη λειτουργία.
+Οι παράμετροι από το αίτημα περνούν στη μέθοδο. Είναι δυνατόν και συνιστάται να καθορίσετε τύπους για τις παραμέτρους, π.χ. `actionShow(int $id, ?string $slug = null)` - αν η παράμετρος `id` λείπει ή αν δεν είναι ακέραιος αριθμός, ο παρουσιαστής επιστρέφει [σφάλμα 404 |#Error 404 etc.] και τερματίζει τη λειτουργία.
`handle(args...)` .{toc: handle()}
@@ -205,7 +205,7 @@ $this->redirect(/* ... */);
Σφάλμα 404 κ.λπ. .[#toc-error-404-etc]
======================================
-Όταν δεν μπορούμε να ικανοποιήσουμε το αίτημα επειδή για παράδειγμα το άρθρο που θέλουμε να εμφανίσουμε δεν υπάρχει στη βάση δεδομένων, θα πετάξουμε το σφάλμα 404 χρησιμοποιώντας τη μέθοδο `error(string $message = null, int $httpCode = 404)`, η οποία αντιπροσωπεύει το σφάλμα HTTP 404:
+Όταν δεν μπορούμε να ικανοποιήσουμε το αίτημα επειδή για παράδειγμα το άρθρο που θέλουμε να εμφανίσουμε δεν υπάρχει στη βάση δεδομένων, θα πετάξουμε το σφάλμα 404 χρησιμοποιώντας τη μέθοδο `error(?string $message = null, int $httpCode = 404)`, η οποία αντιπροσωπεύει το σφάλμα HTTP 404:
```php
public function renderShow(int $id): void
@@ -384,7 +384,7 @@ class ProductPresenter extends Nette\Application\UI\Presenter
Μπορείτε επίσης να επικαλεστείτε την κανονικοποίηση χειροκίνητα χρησιμοποιώντας τη μέθοδο `canonicalize()`, η οποία, όπως και η μέθοδος `link()`, λαμβάνει τον παρουσιαστή, τις ενέργειες και τις παραμέτρους ως ορίσματα. Δημιουργεί έναν σύνδεσμο και τον συγκρίνει με την τρέχουσα διεύθυνση URL. Εάν είναι διαφορετική, ανακατευθύνει στον δημιουργημένο σύνδεσμο.
```php
-public function actionShow(int $id, string $slug = null): void
+public function actionShow(int $id, ?string $slug = null): void
{
$realSlug = $this->facade->getSlugForId($id);
// ανακατευθύνει εάν το $slug είναι διαφορετικό από το $realSlug
@@ -452,17 +452,6 @@ $this->sendResponse(new Responses\CallbackResponse($callback));
Το `#[Requires]` παρέχει προηγμένες επιλογές για τον περιορισμό της πρόσβασης στους παρουσιαστές και τις μεθόδους τους. Μπορεί να χρησιμοποιηθεί για τον προσδιορισμό μεθόδων HTTP, την απαίτηση αιτήσεων AJAX, τον περιορισμό της πρόσβασης στην ίδια προέλευση και τον περιορισμό της πρόσβασης μόνο στην προώθηση. Το χαρακτηριστικό μπορεί να εφαρμοστεί σε κλάσεις παρουσιαστών καθώς και σε μεμονωμένες μεθόδους όπως οι `action()`, `render()`, `handle()`, και `createComponent()`.
-Ακολουθεί ένα παράδειγμα χρήσης της για να περιορίσετε την πρόσβαση μόνο στη μέθοδο HTTP `POST`:
-
-```php
-use Nette\Application\Attributes\Requires;
-
-#[Requires(methods: 'POST')]
-class MyPresenter extends Nette\Application\UI\Presenter
-{
-}
-```
-
Μπορείτε να καθορίσετε αυτούς τους περιορισμούς:
- σε μεθόδους HTTP: `#[Requires(methods: ['GET', 'POST'])]`
- AJAX: `#[Requires(ajax: true)]`
@@ -470,22 +459,7 @@ class MyPresenter extends Nette\Application\UI\Presenter
- πρόσβαση μόνο μέσω προώθησης: `#[Requires(forward: true)]`
- περιορισμοί σε συγκεκριμένες ενέργειες: `#[Requires(actions: 'default')]`
-Οι συνθήκες μπορούν να συνδυαστούν με την απαρίθμηση πολλαπλών χαρακτηριστικών ή με τη συνένωσή τους σε ένα:
-
-```php
-#[Requires(methods: 'POST', ajax: true)]
-public function actionDelete(int $id)
-{
-}
-
-// or
-
-#[Requires(methods: 'POST')]
-#[Requires(ajax: true)]
-public function actionDelete(int $id)
-{
-}
-```
+Για λεπτομέρειες, ανατρέξτε στην ενότητα [Πώς να χρησιμοποιήσετε το Requires attribute |best-practices:attribute-requires].
Έλεγχος μεθόδου HTTP .[#toc-http-method-check]
diff --git a/application/el/routing.texy b/application/el/routing.texy
index 448fa6f67b..78ebb607a0 100644
--- a/application/el/routing.texy
+++ b/application/el/routing.texy
@@ -216,7 +216,7 @@ $router->addRoute('//www.%sld%.%tld%/%basePath%//addRoute('/[/]', [
@@ -225,7 +225,7 @@ $router->addRoute('/[/]', [
]);
```
-Ή μπορούμε να χρησιμοποιήσουμε αυτή τη μορφή, παρατηρήστε την αναδιατύπωση της κανονικής έκφρασης επικύρωσης:
+Για μια πιο λεπτομερή προδιαγραφή, μπορεί να χρησιμοποιηθεί μια ακόμη πιο εκτεταμένη μορφή, όπου εκτός από τις προεπιλεγμένες τιμές, μπορούν να οριστούν και άλλες ιδιότητες παραμέτρων, όπως μια κανονική έκφραση επικύρωσης (βλ. την παράμετρο `id` ):
```php
use Nette\Routing\Route;
@@ -243,7 +243,7 @@ $router->addRoute('/[/]', [
]);
```
-Αυτές οι πιο ομιλητικές μορφές είναι χρήσιμες για την προσθήκη άλλων μεταδεδομένων.
+Είναι σημαντικό να σημειωθεί ότι εάν οι παράμετροι που ορίζονται στον πίνακα δεν περιλαμβάνονται στη μάσκα διαδρομής, οι τιμές τους δεν μπορούν να αλλάξουν, ούτε καν με τη χρήση παραμέτρων ερωτήματος που καθορίζονται μετά από ένα ερωτηματικό στη διεύθυνση URL.
Φίλτρα και μεταφράσεις .[#toc-filters-and-translations]
@@ -477,10 +477,10 @@ $router->addRoute('index.html \.html?|\.php|>', /* ... */);
Ενσωμάτωση .[#toc-integration]
==============================
-Για να συνδέσουμε τον δρομολογητή μας στην εφαρμογή, πρέπει να ενημερώσουμε το DI container σχετικά με αυτόν. Ο ευκολότερος τρόπος είναι να προετοιμάσουμε το εργοστάσιο που θα κατασκευάσει το αντικείμενο του δρομολογητή και να πούμε στη διαμόρφωση του δοχείου να το χρησιμοποιήσει. Ας πούμε λοιπόν ότι γράφουμε μια μέθοδο για το σκοπό αυτό `App\Router\RouterFactory::createRouter()`:
+Για να συνδέσουμε τον δρομολογητή μας στην εφαρμογή, πρέπει να ενημερώσουμε το DI container σχετικά με αυτόν. Ο ευκολότερος τρόπος είναι να προετοιμάσουμε το εργοστάσιο που θα κατασκευάσει το αντικείμενο του δρομολογητή και να πούμε στη διαμόρφωση του δοχείου να το χρησιμοποιήσει. Ας πούμε λοιπόν ότι γράφουμε μια μέθοδο για το σκοπό αυτό `App\Core\RouterFactory::createRouter()`:
```php
-namespace App\Router;
+namespace App\Core;
use Nette\Application\Routers\RouteList;
@@ -499,7 +499,7 @@ class RouterFactory
```neon
services:
- - App\Router\RouterFactory::createRouter
+ - App\Core\RouterFactory::createRouter
```
Οποιεσδήποτε εξαρτήσεις, όπως μια σύνδεση βάσης δεδομένων κ.λπ., περνούν στη μέθοδο factory ως παράμετροι με τη χρήση [αυτόματης σύνδεσης |dependency-injection:autowiring]:
@@ -663,7 +663,7 @@ $router->addRoute(/* ... */);
Έτσι και πάλι θα δημιουργήσουμε μια μέθοδο που θα κατασκευάσει ένα δρομολογητή, για παράδειγμα:
```php
-namespace App\Router;
+namespace App\Core;
use Nette\Routing\RouteList;
@@ -694,7 +694,7 @@ $httpRequest = $container->getByType(Nette\Http\IRequest::class);
Ή θα δημιουργήσουμε αντικείμενα απευθείας:
```php
-$router = App\Router\RouterFactory::createRouter();
+$router = App\Core\RouterFactory::createRouter();
$httpRequest = (new Nette\Http\RequestFactory)->fromGlobals();
```
diff --git a/application/el/templates.texy b/application/el/templates.texy
index 4b83599f45..dfe884dd1b 100644
--- a/application/el/templates.texy
+++ b/application/el/templates.texy
@@ -34,35 +34,81 @@
Ορίζει το μπλοκ `content`, το οποίο εισάγεται στη θέση του `{include content}` στη διάταξη, και επίσης επαναπροσδιορίζει το μπλοκ `title`, το οποίο αντικαθιστά το `{block title}` στη διάταξη. Προσπαθήστε να φανταστείτε το αποτέλεσμα.
-Αναζήτηση προτύπων .[#toc-search-for-templates]
------------------------------------------------
+Αναζήτηση προτύπου .[#toc-template-lookup]
+------------------------------------------
-Η διαδρομή προς τα πρότυπα προκύπτει σύμφωνα με μια απλή λογική. Προσπαθεί να δει αν ένα από αυτά τα αρχεία προτύπων υπάρχει σε σχέση με τον κατάλογο όπου βρίσκεται η κλάση presenter, όπου `` είναι το όνομα του τρέχοντος παρουσιαστή και `` είναι το όνομα της τρέχουσας δράσης:
+Στους παρουσιαστές, δεν χρειάζεται να καθορίσετε ποιο πρότυπο πρέπει να αποδοθεί- το πλαίσιο θα καθορίσει αυτόματα τη διαδρομή, διευκολύνοντας την κωδικοποίηση για εσάς.
-- `templates//.latte`
-- `templates/..latte`
+Αν χρησιμοποιείτε μια δομή καταλόγου όπου κάθε παρουσιαστής έχει το δικό του κατάλογο, απλά τοποθετήστε το πρότυπο σε αυτόν τον κατάλογο κάτω από το όνομα της ενέργειας (π.χ. προβολή). Για παράδειγμα, για τη δράση `default`, χρησιμοποιήστε το πρότυπο `default.latte`:
-Αν το πρότυπο δεν βρεθεί, θα προσπαθήσει να ψάξει στον κατάλογο `templates` ένα επίπεδο πιο πάνω, δηλαδή στο ίδιο επίπεδο με τον κατάλογο με την κλάση παρουσιαστή.
+/--pre
+app/
+└── UI/
+ └── Home/
+ ├── HomePresenter.php
+ └── default.latte
+\--
-Εάν το πρότυπο δεν βρεθεί ούτε εκεί, η απάντηση είναι ένα [σφάλμα 404 |presenters#Error 404 etc.].
+Εάν χρησιμοποιείτε μια δομή όπου οι παρουσιαστές βρίσκονται μαζί σε έναν κατάλογο και τα πρότυπα σε έναν φάκελο `templates`, αποθηκεύστε το είτε σε ένα αρχείο `..latte` είτε στο `/.latte`:
-Μπορείτε επίσης να αλλάξετε την προβολή χρησιμοποιώντας το `$this->setView('otherView')`. Ή, αντί για αναζήτηση, καθορίστε απευθείας το όνομα του αρχείου προτύπου χρησιμοποιώντας τη διεύθυνση `$this->template->setFile('/path/to/template.latte')`.
+/--pre
+app/
+└── Presenters/
+ ├── HomePresenter.php
+ └── templates/
+ ├── Home.default.latte ← 1st variant
+ └── Home/
+ └── default.latte ← 2nd variant
+\--
+
+Ο κατάλογος `templates` μπορεί επίσης να τοποθετηθεί ένα επίπεδο ψηλότερα, στο ίδιο επίπεδο με τον κατάλογο με τις κλάσεις παρουσιαστών.
+
+Εάν το πρότυπο δεν βρεθεί, ο παρουσιαστής απαντά με το [σφάλμα 404 - σελίδα δεν βρέθηκε |presenters#Error 404 etc].
+
+Μπορείτε να αλλάξετε την προβολή χρησιμοποιώντας το `$this->setView('anotherView')`. Είναι επίσης δυνατό να καθορίσετε απευθείας το αρχείο προτύπου με το `$this->template->setFile('/path/to/template.latte')`.
.[note]
-Μπορείτε να αλλάξετε τις διαδρομές στις οποίες αναζητούνται τα πρότυπα υπερκαλύπτοντας τη μέθοδο [formatTemplateFiles |api:Nette\Application\UI\Presenter::formatTemplateFiles()], η οποία επιστρέφει έναν πίνακα πιθανών διαδρομών αρχείων.
+Τα αρχεία στα οποία αναζητούνται τα πρότυπα μπορούν να αλλάξουν με την παράκαμψη της μεθόδου [formatTemplateFiles() |api:Nette\Application\UI\Presenter::formatTemplateFiles()], η οποία επιστρέφει έναν πίνακα πιθανών ονομάτων αρχείων.
+
+
+Αναζήτηση προτύπων διάταξης .[#toc-layout-template-lookup]
+----------------------------------------------------------
+
+Η Nette αναζητά επίσης αυτόματα το αρχείο διάταξης.
+
+Εάν χρησιμοποιείτε μια δομή καταλόγου όπου κάθε παρουσιαστής έχει το δικό του κατάλογο, τοποθετήστε τη διάταξη είτε στο φάκελο με τον παρουσιαστή, εάν αφορά μόνο αυτόν, είτε ένα επίπεδο ψηλότερα εάν είναι κοινή για πολλούς παρουσιαστές:
+
+/--pre
+app/
+└── UI/
+ ├── @layout.latte ← common layout
+ └── Home/
+ ├── @layout.latte ← only for Home presenter
+ ├── HomePresenter.php
+ └── default.latte
+\--
+
+Εάν χρησιμοποιείτε μια δομή όπου οι παρουσιαστές είναι ομαδοποιημένοι σε έναν κατάλογο και τα πρότυπα βρίσκονται σε έναν φάκελο `templates`, η διάταξη αναμένεται στις ακόλουθες θέσεις:
-Η διάταξη αναμένεται στα ακόλουθα αρχεία:
+/--pre
+app/
+└── Presenters/
+ ├── HomePresenter.php
+ └── templates/
+ ├── @layout.latte ← common layout
+ ├── Home.@layout.latte ← only for Home, 1st variant
+ └── Home/
+ └── @layout.latte ← only for Home, 2nd variant
+\--
-- `templates//@.latte`
-- `templates/.@.latte`
-- `templates/@.latte` διάταξη κοινή για πολλούς παρουσιαστές
+Εάν ο παρουσιαστής βρίσκεται σε μια [ενότητα |modules], θα αναζητήσει επίσης πιο πάνω στο δέντρο καταλόγων σύμφωνα με την ένθεση της ενότητας.
-`` είναι το όνομα του τρέχοντος παρουσιαστή και `` είναι το όνομα της διάταξης, η οποία είναι εξ ορισμού `'layout'`. Το όνομα μπορεί να αλλάξει με το `$this->setLayout('otherLayout')`, έτσι ώστε να δοκιμάζονται τα αρχεία `@otherLayout.latte`.
+Το όνομα της διάταξης μπορεί να αλλάξει χρησιμοποιώντας το `$this->setLayout('layoutAdmin')` και τότε θα αναμένεται στο αρχείο `@layoutAdmin.latte`. Μπορείτε επίσης να καθορίσετε απευθείας το αρχείο προτύπου διάταξης χρησιμοποιώντας το `$this->setLayout('/path/to/template.latte')`.
-Μπορείτε επίσης να καθορίσετε απευθείας το όνομα του αρχείου του προτύπου διάταξης χρησιμοποιώντας το `$this->setLayout('/path/to/template.latte')`. Η χρήση του `$this->setLayout(false)` θα απενεργοποιήσει την αναζήτηση διάταξης.
+Η χρήση του `$this->setLayout(false)` ή της ετικέτας `{layout none}` μέσα στο πρότυπο απενεργοποιεί την αναζήτηση διάταξης.
.[note]
-Μπορείτε να αλλάξετε τις διαδρομές στις οποίες αναζητούνται τα πρότυπα με την παράκαμψη της μεθόδου [formatLayoutTemplateFiles |api:Nette\Application\UI\Presenter::formatLayoutTemplateFiles()], η οποία επιστρέφει έναν πίνακα πιθανών διαδρομών αρχείων.
+Τα αρχεία στα οποία αναζητούνται τα πρότυπα διάταξης μπορούν να αλλάξουν με την παράκαμψη της μεθόδου [formatLayoutTemplateFiles() |api:Nette\Application\UI\Presenter::formatLayoutTemplateFiles()], η οποία επιστρέφει έναν πίνακα πιθανών ονομάτων αρχείων.
Μεταβλητές στο πρότυπο .[#toc-variables-in-the-template]
@@ -104,7 +150,7 @@ class ArticleTemplate extends Nette\Bridges\ApplicationLatte\Template
Μπορείτε επίσης να αφεθείτε στην πολυτέλεια του ψιθυρίσματος στα πρότυπα, απλά εγκαταστήστε το πρόσθετο Latte στο PhpStorm και καθορίστε το όνομα της κλάσης στην αρχή του προτύπου, δείτε το άρθρο "Latte: πώς να πληκτρολογήσετε το σύστημα":https://blog.nette.org/el/latte-pos-na-chresimopoiesete-to-systema-typon:
```latte
-{templateType App\Presenters\ArticleTemplate}
+{templateType App\UI\Article\ArticleTemplate}
...
```
@@ -176,7 +222,7 @@ public function beforeRender(): void
Latte έκδοση 3 προσφέρει έναν πιο προηγμένο τρόπο δημιουργώντας μια [επέκταση |latte:creating-extension] για κάθε έργο ιστού. Εδώ είναι ένα πρόχειρο παράδειγμα μιας τέτοιας κλάσης:
```php
-namespace App\Templating;
+namespace App\UI\Accessory;
final class LatteExtension extends Latte\Extension
{
@@ -214,7 +260,7 @@ final class LatteExtension extends Latte\Extension
```neon
latte:
extensions:
- - App\Templating\LatteExtension
+ - App\UI\Accessory\LatteExtension
```
@@ -239,7 +285,7 @@ protected function beforeRender(): void
```neon
latte:
extensions:
- - Latte\Essential\TranslatorExtension
+ - Latte\Essential\TranslatorExtension(@Nette\Localization\Translator)
```
Ο μεταφραστής μπορεί στη συνέχεια να χρησιμοποιηθεί, για παράδειγμα, ως φίλτρο `|translate`, με πρόσθετες παραμέτρους που περνούν στη μέθοδο `translate()` (βλ. `foo, bar`):
diff --git a/application/en/ajax.texy b/application/en/ajax.texy
index a62ed95cfc..819a6e4627 100644
--- a/application/en/ajax.texy
+++ b/application/en/ajax.texy
@@ -77,6 +77,12 @@ npm install naja
```
+First you need to [initialize |https://naja.js.org/#/guide/01-install-setup-naja?id=initialization] the library:
+
+```js
+naja.initialize();
+```
+
To make an ordinary link (signal) or form submission an AJAX request, simply mark the respective link, form, or button with the `ajax` class:
```html
diff --git a/application/en/bootstrap.texy b/application/en/bootstrap.texy
index 14a412cd6f..a950df1e88 100644
--- a/application/en/bootstrap.texy
+++ b/application/en/bootstrap.texy
@@ -20,18 +20,44 @@ use Nette\Bootstrap\Configurator;
class Bootstrap
{
- public static function boot(): Configurator
+ private Configurator $configurator;
+ private string $rootDir;
+
+ public function __construct()
+ {
+ $this->rootDir = dirname(__DIR__);
+ // The configurator is responsible for setting up the application environment and services.
+ $this->configurator = new Configurator;
+ // Set the directory for temporary files generated by Nette (e.g. compiled templates)
+ $this->configurator->setTempDirectory($this->rootDir . '/temp');
+ }
+
+ public function bootWebApplication(): Nette\DI\Container
{
- $appDir = dirname(__DIR__);
- $configurator = new Configurator;
- //$configurator->setDebugMode('secret@23.75.345.200');
- $configurator->enableTracy($appDir . '/log');
- $configurator->setTempDirectory($appDir . '/temp');
- $configurator->createRobotLoader()
+ $this->initializeEnvironment();
+ $this->setupContainer();
+ return $this->configurator->createContainer();
+ }
+
+ private function initializeEnvironment(): void
+ {
+ // Nette is smart, and the development mode turns on automatically,
+ // or you can enable for a specific IP address it by uncommenting the following line:
+ // $this->configurator->setDebugMode('secret@23.75.345.200');
+
+ // Enables Tracy: the ultimate "swiss army knife" debugging tool.
+ $this->configurator->enableTracy($this->rootDir . '/log');
+
+ // RobotLoader: autoloads all classes in the given directory
+ $this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
- $configurator->addConfig($appDir . '/config/common.neon');
- return $configurator;
+ }
+
+ private function setupContainer(): void
+ {
+ // Load configuration files
+ $this->configurator->addConfig($this->rootDir . '/config/common.neon');
}
}
```
@@ -40,16 +66,15 @@ class Bootstrap
index.php
=========
-In the case of web applications, the initial file is `index.php`, which is located in the public directory `www/`. It lets the `Bootstrap` class to initialize the environment and return the `$configurator` which creates DI container. Then it obtains the `Application` service, that runs the web application:
+The initial file for web applications is `index.php`, located in the public directory `www/`. It uses the `Bootstrap` class to initialize the environment and create a DI container. Then, it obtains the `Application` service from the container, which launches the web application:
```php
-// initialize the environment + get Configurator object
-$configurator = App\Bootstrap::boot();
-// create a DI container
-$container = $configurator->createContainer();
+$bootstrap = new App\Bootstrap;
+// Initialize the environment + create a DI container
+$container = $bootstrap->bootWebApplication();
// DI container creates a Nette\Application\Application object
$application = $container->getByType(Nette\Application\Application::class);
-// start Nette application
+// Start the Nette application and handle the incoming request
$application->run();
```
@@ -66,19 +91,19 @@ Mode selection is done by autodetection, so there is usually no need to configur
If you want to enable development mode in other cases, for example, for programmers accessing from a specific IP address, you can use `setDebugMode()`:
```php
-$configurator->setDebugMode('23.75.345.200'); // one or more IP addresses
+$this->configurator->setDebugMode('23.75.345.200'); // one or more IP addresses
```
We definitely recommend combining an IP address with a cookie. We will store a secret token into the `nette-debug` cookie, e.g. `secret1234`, and the development mode will be activated for programmers with this combination of IP and cookie.
```php
-$configurator->setDebugMode('secret1234@23.75.345.200');
+$this->configurator->setDebugMode('secret1234@23.75.345.200');
```
We can also turn off developer mode completely, even for localhost:
```php
-$configurator->setDebugMode(false);
+$this->configurator->setDebugMode(false);
```
Note that the value `true` turns on developer mode by hard, which should never happen on a production server.
@@ -90,7 +115,7 @@ Debugging Tool Tracy
For easy debugging, we will turn on the great tool [Tracy |tracy:]. In developer mode it visualizes errors and in production mode it logs errors to the specified directory:
```php
-$configurator->enableTracy($appDir . '/log');
+$this->configurator->enableTracy($this->rootDir . '/log');
```
@@ -100,7 +125,7 @@ Temporary Files
Nette uses the cache for DI container, RobotLoader, templates, etc. Therefore it is necessary to set the path to the directory where the cache will be stored:
```php
-$configurator->setTempDirectory($appDir . '/temp');
+$this->configurator->setTempDirectory($this->rootDir . '/temp');
```
On Linux or macOS, set the [write permissions |nette:troubleshooting#Setting directory permissions] for directories `log/` and `temp/`.
@@ -112,7 +137,7 @@ RobotLoader
Usually, we will want to automatically load the classes using [RobotLoader |robot-loader:], so we have to start it up and let it load classes from the directory where `Bootstrap.php` is located (i.e. `__DIR__`) and all its subdirectories:
```php
-$configurator->createRobotLoader()
+$this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
```
@@ -126,7 +151,7 @@ Timezone
Configurator allows you to specify a timezone for your application.
```php
-$configurator->setTimeZone('Europe/Prague');
+$this->configurator->setTimeZone('Europe/Prague');
```
@@ -143,16 +168,17 @@ In the development mode, the container is automatically updated each time you ch
Configuration files are loaded using `addConfig()`:
```php
-$configurator->addConfig($appDir . '/config/common.neon');
+$this->configurator->addConfig($this->rootDir . '/config/common.neon');
```
The method `addConfig()` can be called multiple times to add multiple files.
```php
-$configurator->addConfig($appDir . '/config/common.neon');
-$configurator->addConfig($appDir . '/config/services.neon');
+$configDir = $this->rootDir . '/config';
+$this->configurator->addConfig($configDir . '/common.neon');
+$this->configurator->addConfig($configDir . '/services.neon');
if (PHP_SAPI === 'cli') {
- $configurator->addConfig($appDir . '/config/cli.php');
+ $this->configurator->addConfig($configDir . '/cli.php');
}
```
@@ -169,7 +195,7 @@ Static Parameters
Parameters used in configuration files can be defined [in the section `parameters`|dependency-injection:configuration#parameters] and also passed (or overwritten) by the `addStaticParameters()` method (it has alias `addParameters()`). It is important that different parameter values cause the generation of additional DI containers, i.e. additional classes.
```php
-$configurator->addStaticParameters([
+$this->configurator->addStaticParameters([
'projectId' => 23,
]);
```
@@ -183,7 +209,7 @@ Dynamic Parameters
We can also add dynamic parameters to the container, their different values, unlike static parameters, will not cause the generation of new DI containers.
```php
-$configurator->addDynamicParameters([
+$this->configurator->addDynamicParameters([
'remoteIp' => $_SERVER['REMOTE_ADDR'],
]);
```
@@ -191,7 +217,7 @@ $configurator->addDynamicParameters([
Environment variables could be easily made available using dynamic parameters. We can access them via `%env.variable%` in configuration files.
```php
-$configurator->addDynamicParameters([
+$this->configurator->addDynamicParameters([
'env' => getenv(),
]);
```
@@ -206,6 +232,7 @@ You can use the following static parameters in the configuration files:
- `%wwwDir%` is the absolute path to the directory containing the `index.php` entry file
- `%tempDir%` is the absolute path to the directory for temporary files
- `%vendorDir%` is the absolute path to the directory where Composer installs libraries
+- `%rootDir%` is the absolute path to the root directory of the project
- `%debugMode%` indicates whether the application is in debug mode
- `%consoleMode%` indicates whether the request came through the command line
@@ -225,7 +252,7 @@ services:
Create a new instance and insert it in bootstrap:
```php
-$configurator->addServices([
+$this->configurator->addServices([
'myservice' => new App\Model\MyCustomService('foobar'),
]);
```
@@ -234,13 +261,21 @@ $configurator->addServices([
Different Environments
======================
-Feel free to customize the `Bootstrap` class to suit your needs. You can add parameters to the `boot()` method to differentiate web projects, or add other methods, such as `bootForTests()`, which initializes the environment for unit tests, `bootForCli()` for scripts called from the command line, and so on.
+Don't hesitate to customize the `Bootstrap` class according to your needs. You can add parameters to the `bootWebApplication()` method to differentiate between web projects. Alternatively, you can add other methods, such as `bootTestEnvironment()` to initialize the environment for unit tests, `bootConsoleApplication()` for scripts called from the command line, and so on.
```php
-public static function bootForTests(): Configurator
+public function bootTestEnvironment(): Nette\DI\Container
{
- $configurator = self::boot();
Tester\Environment::setup(); // Nette Tester initialization
- return $configurator;
+ $this->setupContainer();
+ return $this->configurator->createContainer();
+}
+
+public function bootConsoleApplication(): Nette\DI\Container
+{
+ $this->configurator->setDebugMode(false);
+ $this->initializeEnvironment();
+ $this->setupContainer();
+ return $this->configurator->createContainer();
}
```
diff --git a/application/en/components.texy b/application/en/components.texy
index 42b40aaacb..2c79308bef 100644
--- a/application/en/components.texy
+++ b/application/en/components.texy
@@ -198,7 +198,7 @@ The link that calls the signal is created in the usual way, i.e. in the template
click here
```
-The signal is always called on the current presenter and view, so it is not possible to link to signal in different presenter / action.
+The signal is always called on the current presenter and action, it cannot be called on another presenter or action.
Thus, the signal causes the page to be reloaded in exactly the same way as in the original request, only in addition it calls the signal handling method with the appropriate parameters. If the method does not exist, exception [api:Nette\Application\UI\BadSignalException] is thrown, which is displayed to the user as error page 403 Forbidden.
@@ -230,6 +230,28 @@ In the template, these messages are available in the variable `$flashes` as obje
```
+Redirection After a Signal
+==========================
+
+After processing a component signal, redirection often follows. This situation is similar to forms—after submitting a form, we also redirect to prevent resubmission of data when the page is refreshed in the browser.
+
+```php
+$this->redirect('this') // redirects to the current presenter and action
+```
+
+Since a component is a reusable element and should not usually have a direct dependency on specific presenters, the `redirect()` and `link()` methods automatically interpret the parameter as a component signal:
+
+```php
+$this->redirect('click') // redirects to the 'click' signal of the same component
+```
+
+If you need to redirect to a different presenter or action, you can do so through the presenter:
+
+```php
+$this->getPresenter()->redirect('Product:show'); // redirects to a different presenter/action
+```
+
+
Persistent Parameters
=====================
@@ -430,7 +452,7 @@ class PaginatingControl extends Control
}
```
-The opposite process, that is, collecting values from persistent properites, is handled by the `saveState()` method.
+The opposite process, that is, collecting values from persistent properties, is handled by the `saveState()` method.
Signals in Depth
@@ -444,7 +466,7 @@ Signal can be received by any component, presenter of object which implements in
The main receivers of signals are `Presenters` and visual components extending `Control`. A signal is a sign for an object that it has to do something - poll counts in a vote from user, box with news has to unfold, form was sent and has to process data and so on.
-The URL for the signal is created using the method [Component::link() |api:Nette\Application\UI\Component::link()]. As parameter `$destination` we pass string `{signal}!` and as `$args` an array of arguments which we want to pass to the signal handler. Signal parameters are attached to the URL of the current presenter/view. **The parameter `?do` in the URL determines the signal called.**
+The URL for the signal is created using the [Component::link() |api:Nette\Application\UI\Component::link()] method. We pass the string `{signal}!` as the `$destination` parameter and the array of arguments we want to pass to the signal as `$args`. The signal is always called on the current presenter and action with the current parameters, the signal parameters are just added. In addition, the **parameter `?do`, which specifies the signal** is added right at the beginning.
Its format is `{signal}` or `{signalReceiver}-{signal}`. `{signalReceiver}` is the name of the component in the presenter. This is why hyphen (inaccurately dash) can't be present in the name of components - it is used to divide the name of the component and signal, but it's possible to compose several components.
diff --git a/application/en/configuration.texy b/application/en/configuration.texy
index fba71aa4fd..e9df62aef7 100644
--- a/application/en/configuration.texy
+++ b/application/en/configuration.texy
@@ -95,6 +95,9 @@ latte:
# enables [checking generated code |latte:develop#Checking Generated Code]
phpLinter: ... # (string) default is null
+ # sets the locale
+ locale: cs_CZ # (string) default is null
+
# class of $this->template
templateClass: App\MyTemplateClass # defaults to Nette\Bridges\ApplicationLatte\DefaultTemplate
```
@@ -104,7 +107,7 @@ If you are using Latte version 3, you can add new [extension |latte:creating-ext
```neon
latte:
extensions:
- - Latte\Essential\TranslatorExtension
+ - Latte\Essential\TranslatorExtension(@Nette\Localization\Translator)
```
If you are using Latte version 2, you can register new tags either by entering the class name or by referring to the service. Method `install()` is called by default, but this can be changed by specifying the name of another method:
diff --git a/application/en/how-it-works.texy b/application/en/how-it-works.texy
index 612d192393..cb0f291e1b 100644
--- a/application/en/how-it-works.texy
+++ b/application/en/how-it-works.texy
@@ -22,13 +22,13 @@ The directory structure looks something like this:
/--pre
web-project/
├── app/ ← directory with application
-│ ├── Presenters/ ← presenter classes
-│ │ ├── HomePresenter.php ← Home presenter class
-│ │ └── templates/ ← templates directory
-│ │ ├── @layout.latte ← template of shared layout
-│ │ └── Home/ ← templates for Home presenter
-│ │ └── default.latte ← template for action `default`
-│ ├── Router/ ← configuration of URL addresses
+│ ├── Core/ ← basic necessary classes
+│ │ └── RouterFactory.php ← configuration of URL addresses
+│ ├── UI/ ← presenters, templates & co.
+│ │ ├── @layout.latte ← template of shared layout
+│ │ └── Home/ ← Home presenter directory
+│ │ ├── HomePresenter.php ← Home presenter class
+│ │ └── default.latte ← template for action default
│ └── Bootstrap.php ← booting class Bootstrap
├── bin/ ← scripts for the command line
├── config/ ← configuration files
@@ -91,7 +91,7 @@ Applications written in Nette are divided into many so-called presenters (in oth
The application starts by asking the so-called router to decide which of the presenters to pass the current request for processing. The router decides whose responsibility it is. It looks at the input URL `https://example.com/product/123` and, based on how it is set up, decides that this is a job, for example, for **presenter** `Product`, who wants to `show` a product with `id: 123` as an action. It is a good habit to write a pairs of presenter + action separated by a colon as `Product:show`.
-So the router transformed the URL into a pair `Presenter:action` + parameters, in our case `Product:show` + `id: 123`. You can see how a router looks like in file `app/Router/RouterFactory.php` and we will describe it in detail in chapter [Routing].
+So the router transformed the URL into a pair `Presenter:action` + parameters, in our case `Product:show` + `id: 123`. You can see how a router looks like in file `app/Core/RouterFactory.php` and we will describe it in detail in chapter [Routing].
Let's move on. The application already knows the name of the presenter and can continue. By creating an object `ProductPresenter`, which is the code of presenter `Product`. More precisely, it asks the DI container for creating the presenter, because producting objects is its job.
@@ -121,12 +121,9 @@ So, the method `renderShow(123)` was called, whose code is fictional example, bu
Subsequently, the presenter returns the answer. This can be an HTML page, an image, an XML document, sending a file from disk, JSON or redirecting to another page. Importantly, if we do not explicitly say how to respond (which is the case of `ProductPresenter`), the answer will be to render the template with an HTML page. Why? Well, because in 99% of cases we want to draw a template, so the presenter takes this behavior as the default and wants to make our work easier. That's Nette's point.
-We don't even have to state which template to draw, he derives the path to it according to simple logic. In the case of presenter `Product` and action `show`, it tries to see if one of these template files exists relative to the directory where class `ProductPresenter` is located:
+We don't even need to specify which template to render; the framework will deduce the path itself. In the case of the `show` action, it simply tries to load the `show.latte` template in the directory with the `ProductPresenter` class. It also attempts to find the layout in the `@layout.latte` file (more about [template searching |templates#Template Lookup]).
-- `templates/Product/show.latte`
-- `templates/Product.show.latte`
-
-It will also try to find the layout in file `@layout.latte` and then it renders the template. Now the task of the presenter and the entire application is completed. If the template does not exist, a page with error 404 will be returned. You can read more about presenters on the [Presenters] page.
+Subsequently, the templates are rendered. This completes the task of the presenter and the entire application, and the work is done. If the template did not exist, a 404 error page would be returned. You can read more about presenters on the page [Presenters|presenters].
[* request-flow.svg *]
@@ -137,7 +134,7 @@ Just to be sure, let's try to recap the whole process with a slightly different
3) the router decodes the URL as a pair `Home:default`
4) an `HomePresenter` object is created
5) method `renderDefault()` is called (if exists)
-6) a template `templates/Home/default.latte` with a layout `templates/@layout.latte` is rendered
+6) a template `default.latte` with a layout `@layout.latte` is rendered
You may have come across a lot of new concepts now, but we believe they make sense. Creating applications in Nette is a breeze.
diff --git a/application/en/modules.texy b/application/en/modules.texy
index 376ac872b9..528cc1600c 100644
--- a/application/en/modules.texy
+++ b/application/en/modules.texy
@@ -2,29 +2,31 @@ Modules
*******
.[perex]
-In Nette, modules represent the logical units that make up an application. They include presenters, templates, possibly also components and model classes.
+Modules bring clarity to Nette applications by facilitating easy division into logical units.
-One directory for presenters and one for templates would not be enough for real projects. Having dozens of files in one folder is at least unorganized. How to get out of it? We simply split them into subdirectories on disk and into namespaces in the code. And that's exactly what the Nette modules do.
-
-So let's forget about a single folder for presenters and templates and instead create modules, for example `Admin` and `Front`.
+Similar to organizing files into folders on a hard drive, in Nette we can divide presenters, templates, and other auxiliary classes into modules. How does this work in practice? Simply by incorporating new subdirectories into the structure. Here’s an example of a structure with two modules, Front and Admin:
/--pre
-app/
-├── Presenters/
-├── Modules/ ← directory with modules
-│ ├── Admin/ ← module Admin
-│ │ ├── Presenters/ ← its presenters
-│ │ │ ├── DashboardPresenter.php
-│ │ │ └── templates/
-│ └── Front/ ← module Front
-│ └── Presenters/ ← its presenters
-│ └── ...
+app/
+├── UI/
+│ ├── Admin/ ← Admin module
+│ │ ├── @layout.latte
+│ │ ├── Dashboard/
+│ │ │ ├── DashboardPresenter.php
+│ │ │ └── default.latte
+│ │ └── ...
+│ ├── Front/ ← Front module
+│ │ ├── @layout.latte
+│ │ ├── Home/
+│ │ │ ├── HomePresenter.php
+│ │ │ └── default.latte
+│ │ └── ...
\--
-This directory structure will be reflected by the class namespaces, so for example `DashboardPresenter` will be in the `App\Modules\Admin\Presenters` namespace:
+This directory structure is reflected in the namespaces of the classes, so for example, `DashboardPresenter` is located in the namespace `App\UI\Admin\Dashboard`:
```php
-namespace App\Modules\Admin\Presenters;
+namespace App\UI\Admin\Dashboard;
class DashboardPresenter extends Nette\Application\UI\Presenter
{
@@ -32,35 +34,49 @@ class DashboardPresenter extends Nette\Application\UI\Presenter
}
```
-The `Dashboard` presenter inside the `Admin` module is referenced within the application using the colon notation as `Admin:Dashboard`, and its `default` action as `Admin:Dashboard:default`.
-And how does Nette proper know that `Admin:Dashboard` represents the `App\Modules\Admin\Presenters\DashboardPresenter` class? This is determined by [#mapping] in the configuration.
-Thus, the given structure is not hard set and you can modify it according to your needs.
+In the application, we refer to the `Dashboard` presenter within the `Admin` module using colon notation as `Admin:Dashboard`. For its `default` action, we refer to it as `Admin:Dashboard:default`.
-Modules can of course contain all other items besides presenters and templates, such as components, model classes, etc.
+The structure presented is not rigid; you can [fully customize it to your needs|#mapping] in the configuration. .[tip]
+
+Modules can include all other files, such as components and auxiliary classes, in addition to presenters and templates. If you are considering where to place these, consider using an `Accessory` folder:
+
+/--pre
+app/
+├── UI/
+│ ├── Admin/
+│ │ ├── Accessory/
+│ │ │ ├── FormFactory.php
+│ │ │ └── AdminLayout.php
+│ │ ├── Dashboard/
+│ │ └── ...
+\--
Nested Modules
--------------
-Modules don't have to form only a flat structure, you can also create submodules, for example:
+Modules can have multiple levels of nesting, similar to a directory structure on a disk:
/--pre
-app/
-├── Modules/ ← directory with modules
-│ ├── Blog/ ← module Blog
-│ │ ├── Admin/ ← submodule Admin
-│ │ │ ├── Presenters/
+app/
+├── UI/
+│ ├── Blog/ ← Blog module
+│ │ ├── Admin/ ← Admin submodule
+│ │ │ ├── Dashboard/
+│ │ │ └── ...
+│ │ ├── Front/ ← Front submodule
+│ │ │ ├── @layout.latte
+│ │ │ ├── Home/
│ │ │ └── ...
-│ │ └── Front/ ← submodule Front
-│ │ ├── Presenters/
-│ │ └── ...
-│ ├── Forum/ ← module Forum
+│ ├── Forum/ ← Forum module
│ │ └── ...
\--
-Thus, the `Blog` module is divided into `Admin` and `Front` submodules. Again, this will be reflected in the namespaces, which will be `App\Modules\Blog\Admin\Presenters` etc. The presenter `Dashboard` inside the submodule is referred to as `Blog:Admin:Dashboard`.
+The `Blog` module is divided into `Admin` and `Front` submodules. This is also reflected in the namespaces, which then appear as `App\UI\Blog\Admin` and similarly. To refer to the `Dashboard` presenter within the `Admin` submodule, we refer to it as `Blog:Admin:Dashboard`.
-The nesting can go as deep as you like, so sub-submodules can be created.
+Nesting can be as deep as needed, allowing the creation of sub-submodules.
+
+For example, if in administration you have many presenters related to order management, such as `OrderDetail`, `OrderEdit`, `OrderDispatch`, etc., you might create an `Order` module in which presenters like `Detail`, `Edit`, `Dispatch`, and others will be organized.
Creating Links
@@ -102,46 +118,66 @@ See [chapter on routing |routing#Modules].
Mapping
-------
-Defines the rules by which the class name is derived from the presenter name. We write them in [configuration] under the `application › mapping` key.
+Mapping defines the rules for deriving the class name from the presenter name. These rules are specified in the [configuration|configuration] under the key `application › mapping`.
+
+The directory structures mentioned earlier on this page are based on the following mapping:
+
+```neon
+application:
+ mapping: App\UI\*\**Presenter
+```
-Let's start with a sample that doesn't use modules. We'll just want the presenter classes to have the `App\Presenters` namespace. That means that a presenter such as `Home` should map to the `App\Presenters\HomePresenter` class. This can be achieved by the following configuration:
+How does the mapping work? For a better understanding, let's first imagine an application without modules. We want the presenter classes to fall under the namespace `App\UI`, so that the `Home` presenter maps to the class `App\UI\HomePresenter`. This can be achieved with this configuration:
```neon
application:
- mapping: App\Presenters\*Presenter
+ mapping: App\UI\*Presenter
```
-The presenter name is replaced with the asterisk in the class mask and the result is the class name. Easy!
+This mapping works by replacing the asterisk in the mask `App\UI\*Presenter` with the presenter name `Home`, resulting in the final class name `App\UI\HomePresenter`. Simple!
+
+However, as you can see in the examples in this and other chapters, we place presenter classes in eponymous subdirectories, e.g., the `Home` presenter is mapped to the class `App\UI\Home\HomePresenter`. This is achieved by doubling the asterisk (requires Nette Application 3.2):
+
+```neon
+application:
+ mapping: App\UI\**Presenter
+```
-If we divide presenters into modules, we can have our own mapping for each module:
+Now, let's move on to mapping presenters into modules. We can define specific mappings for each module:
```neon
application:
mapping:
- Front: App\Modules\Front\Presenters\*Presenter
- Admin: App\Modules\Admin\Presenters\*Presenter
+ Front: App\UI\Front\**Presenter
+ Admin: App\UI\Admin\**Presenter
Api: App\Api\*Presenter
```
-Now presenter `Front:Home` maps to class `App\Modules\Front\Presenters\HomePresenter` and presenter `Admin:Dashboard` to class `App\Modules\Admin\Presenters\DashboardPresenter`.
+According to this configuration, the presenter `Front:Home` maps to the class `App\UI\Front\Home\HomePresenter`, while the presenter `Api:OAuth` maps to the class `App\Api\OAuthPresenter`.
-It is more practical to create a general (star) rule to replace the first two. The extra asterisk will be added to the class mask just for the module:
+Since the `Front` and `Admin` modules have a similar mapping approach and there are likely to be more such modules, it is possible to create a general rule that replaces them. A new asterisk for the module is added to the class mask:
```neon
application:
mapping:
- *: App\Modules\*\Presenters\*Presenter
+ *: App\UI\*\**Presenter
Api: App\Api\*Presenter
```
-But what if we use nested modules and have a presenter `Admin:User:Edit`? In this case, the segment with an asterisk representing the module for each level is simply repeated and the result is class `App\Modules\Admin\User\Presenters\EditPresenter`.
+For multi-level nested modules, such as the presenter `Admin:User:Edit`, the asterisk segment repeats for each level, resulting in the class `App\UI\Admin\User\Edit\EditPresenter`.
-An alternative notation is to use an array consisting of three segments instead of a string. This notation is equivalent to the previous one:
+An alternative notation is to use an array composed of three segments instead of a string. This notation is equivalent to the previous one:
```neon
application:
mapping:
- *: [App\Modules, *, Presenters\*Presenter]
+ *: [App\UI, *, **Presenter]
+ Api: [App\Api, '', *Presenter]
```
-The default value is `*Module\*Presenter`.
+If we have only one rule in the configuration, the general one, we can write briefly:
+
+```neon
+application:
+ mapping: App\UI\*\**Presenter
+```
diff --git a/application/en/presenters.texy b/application/en/presenters.texy
index 324d00441d..2773f8486b 100644
--- a/application/en/presenters.texy
+++ b/application/en/presenters.texy
@@ -60,7 +60,7 @@ Similar to the method `render()`. While `render()` is intended to pr
It is important that `action()` is called before `render()`, so inside it we can possibly change the next course of life cycle, i.e. change the template that will be rendered and also the method `render()` that will be called, using `setView('otherView')`.
-The parameters from the request are passed to the method. It is possible and recommended to specify types for the parameters, e.g. `actionShow(int $id, string $slug = null)` - if parameter `id` is missing or if it is not an integer, the presenter returns [error 404|#Error 404 etc.] and terminates the operation.
+The parameters from the request are passed to the method. It is possible and recommended to specify types for the parameters, e.g. `actionShow(int $id, ?string $slug = null)` - if parameter `id` is missing or if it is not an integer, the presenter returns [error 404|#Error 404 etc.] and terminates the operation.
`handle(args...)` .{toc: handle()}
@@ -205,7 +205,7 @@ In the template, these messages are available in the variable `$flashes` as obje
Error 404 etc.
==============
-When we can't fulfill the request because for example the article we want to display does not exist in the database, we will throw out the 404 error using method `error(string $message = null, int $httpCode = 404)`, which represents HTTP error 404:
+When we can't fulfill the request because for example the article we want to display does not exist in the database, we will throw out the 404 error using method `error(?string $message = null, int $httpCode = 404)`, which represents HTTP error 404:
```php
public function renderShow(int $id): void
@@ -384,7 +384,7 @@ Redirection does not occur with an AJAX or POST request because it would result
You can also invoke canonization manually using method `canonicalize()`, which, like method `link()`, receives the presenter, actions, and parameters as arguments. It creates a link and compares it to the current URL. If it is different, it redirects to the generated link.
```php
-public function actionShow(int $id, string $slug = null): void
+public function actionShow(int $id, ?string $slug = null): void
{
$realSlug = $this->facade->getSlugForId($id);
// redirects if $slug is different from $realSlug
@@ -452,17 +452,6 @@ Access Restriction Using `#[Requires]` .{data-version:3.2.2}
The `#[Requires]` attribute provides advanced options for restricting access to presenters and their methods. It can be used to specify HTTP methods, require AJAX requests, limit access to the same origin, and restrict access to forwarding only. The attribute can be applied to presenter classes as well as individual methods such as `action()`, `render()`, `handle()`, and `createComponent()`.
-Here’s an example of using it to restrict access to only the HTTP `POST` method:
-
-```php
-use Nette\Application\Attributes\Requires;
-
-#[Requires(methods: 'POST')]
-class MyPresenter extends Nette\Application\UI\Presenter
-{
-}
-```
-
You can specify these restrictions:
- on HTTP methods: `#[Requires(methods: ['GET', 'POST'])]`
- requiring an AJAX request: `#[Requires(ajax: true)]`
@@ -470,22 +459,7 @@ You can specify these restrictions:
- access only via forwarding: `#[Requires(forward: true)]`
- restrictions on specific actions: `#[Requires(actions: 'default')]`
-Conditions can be combined by listing multiple attributes or by joining them into one:
-
-```php
-#[Requires(methods: 'POST', ajax: true)]
-public function actionDelete(int $id)
-{
-}
-
-// or
-
-#[Requires(methods: 'POST')]
-#[Requires(ajax: true)]
-public function actionDelete(int $id)
-{
-}
-```
+For details, see [How to use the Requires attribute |best-practices:attribute-requires].
HTTP Method Check
diff --git a/application/en/routing.texy b/application/en/routing.texy
index c35c692adb..f9af18510b 100644
--- a/application/en/routing.texy
+++ b/application/en/routing.texy
@@ -216,7 +216,7 @@ $router->addRoute('//www.%sld%.%tld%/%basePath%//addRoute('/[/]', [
@@ -225,7 +225,7 @@ $router->addRoute('/[/]', [
]);
```
-Or we can use this form, notice the rewriting of the validation regular expression:
+For a more detailed specification, an even more extended form can be used, where in addition to default values, other parameter properties can be set, such as a validation regular expression (see the `id` parameter):
```php
use Nette\Routing\Route;
@@ -243,7 +243,7 @@ $router->addRoute('/[/]', [
]);
```
-These more talkative formats are useful for adding other metadata.
+It is important to note that if the parameters defined in the array are not included in the path mask, their values cannot be changed, not even using query parameters specified after a question mark in the URL.
Filters and Translations
@@ -477,10 +477,10 @@ $router->addRoute('index.html \.html?|\.php|>', /* ... */);
Integration
===========
-In order to connect the our router into the application, we must tell the DI container about it. The easiest way is to prepare the factory that will build the router object and tell the container configuration to use it. So let's say we write a method for this purpose `App\Router\RouterFactory::createRouter()`:
+In order to connect the our router into the application, we must tell the DI container about it. The easiest way is to prepare the factory that will build the router object and tell the container configuration to use it. So let's say we write a method for this purpose `App\Core\RouterFactory::createRouter()`:
```php
-namespace App\Router;
+namespace App\Core;
use Nette\Application\Routers\RouteList;
@@ -499,7 +499,7 @@ Then we write in [configuration |dependency-injection:services]:
```neon
services:
- - App\Router\RouterFactory::createRouter
+ - App\Core\RouterFactory::createRouter
```
Any dependencies, such as a database connection etc., are passed to the factory method as its parameters using [autowiring |dependency-injection:autowiring]:
@@ -663,7 +663,7 @@ By separated usage, we mean the use of the router's capabilities in an applicati
So again we will create a method that will build a router, for example:
```php
-namespace App\Router;
+namespace App\Core;
use Nette\Routing\RouteList;
@@ -694,7 +694,7 @@ $httpRequest = $container->getByType(Nette\Http\IRequest::class);
Or we will create objects directly:
```php
-$router = App\Router\RouterFactory::createRouter();
+$router = App\Core\RouterFactory::createRouter();
$httpRequest = (new Nette\Http\RequestFactory)->fromGlobals();
```
diff --git a/application/en/templates.texy b/application/en/templates.texy
index 5107b4493a..bdc524c4e4 100644
--- a/application/en/templates.texy
+++ b/application/en/templates.texy
@@ -34,35 +34,81 @@ And this might be the action template:
It defines block `content`, which is inserted in place of `{include content}` in the layout, and also re-defines block `title`, which overwrites `{block title}` in the layout. Try to imagine the result.
-Search for Templates
---------------------
+Template Lookup
+---------------
-The path to the templates is deduced according to simple logic. It tries to see if one of these template files exists relative to the directory where presenter class is located, where `` is the name of the current presenter and `` is the name of the current action:
+In presenters, you don't need to specify which template should be rendered; the framework will automatically determine the path, making coding easier for you.
-- `templates//.latte`
-- `templates/..latte`
+If you use a directory structure where each presenter has its own directory, simply place the template in this directory under the name of the action (i.e. view). For example, for the `default` action, use the `default.latte` template:
-If the template is not found, it will try to search in the `templates` directory one level up, i.e., at the same level as the directory with the presenter class.
+/--pre
+app/
+└── UI/
+ └── Home/
+ ├── HomePresenter.php
+ └── default.latte
+\--
-If the template is not found there either, the response is a [404 error|presenters#Error 404 etc.].
+If you use a structure where presenters are together in one directory and templates in a `templates` folder, save it either in a file `..latte` or `/.latte`:
-You can also change the view using `$this->setView('otherView')`. Or, instead of searching, directly specify the name of the template file using `$this->template->setFile('/path/to/template.latte')`.
+/--pre
+app/
+└── Presenters/
+ ├── HomePresenter.php
+ └── templates/
+ ├── Home.default.latte ← 1st variant
+ └── Home/
+ └── default.latte ← 2nd variant
+\--
+
+The `templates` directory can also be placed one level higher, at the same level as the directory with presenter classes.
+
+If the template is not found, the presenter responds with [404 - page not found error|presenters#Error 404 etc].
+
+You can change the view using `$this->setView('anotherView')`. It is also possible to directly specify the template file with `$this->template->setFile('/path/to/template.latte')`.
.[note]
-You can change the paths where templates are searched by overriding the [formatTemplateFiles |api:Nette\Application\UI\Presenter::formatTemplateFiles()] method, which returns an array of possible file paths.
+Files where templates are searched can be changed by overriding the method [formatTemplateFiles() |api:Nette\Application\UI\Presenter::formatTemplateFiles()], which returns an array of possible file names.
+
+
+Layout Template Lookup
+----------------------
+
+Nette also automatically searches for the layout file.
+
+If you use a directory structure where each presenter has its own directory, place the layout either in the folder with the presenter, if it is specific only to them, or a level higher if it is common to multiple presenters:
+
+/--pre
+app/
+└── UI/
+ ├── @layout.latte ← common layout
+ └── Home/
+ ├── @layout.latte ← only for Home presenter
+ ├── HomePresenter.php
+ └── default.latte
+\--
+
+If you use a structure where presenters are grouped together in one directory and templates are in a `templates` folder, the layout will be expected in the following places:
-The layout is expected in the following files:
+/--pre
+app/
+└── Presenters/
+ ├── HomePresenter.php
+ └── templates/
+ ├── @layout.latte ← common layout
+ ├── Home.@layout.latte ← only for Home, 1st variant
+ └── Home/
+ └── @layout.latte ← only for Home, 2nd variant
+\--
-- `templates//@.latte`
-- `templates/.@.latte`
-- `templates/@.latte` layout common to multiple presenters
+If the presenter is in a [module|modules], it will also search further up the directory tree according to the module's nesting.
-`` is the name of the current presenter and `` is the name of the layout, which is by default `'layout'`. The name can be changed with `$this->setLayout('otherLayout')`, so that `@otherLayout.latte` files will be tried.
+The name of the layout can be changed using `$this->setLayout('layoutAdmin')` and then it will be expected in the file `@layoutAdmin.latte`. You can also directly specify the layout template file using `$this->setLayout('/path/to/template.latte')`.
-You can also directly specify the file name of the layout template using `$this->setLayout('/path/to/template.latte')`. Using `$this->setLayout(false)` will disable the layout searching.
+Using `$this->setLayout(false)` or the `{layout none}` tag inside the template disables layout search.
.[note]
-You can change the paths where templates are searched by overriding the [formatLayoutTemplateFiles |api:Nette\Application\UI\Presenter::formatLayoutTemplateFiles()] method, which returns an array of possible file paths.
+Files where layout templates are searched can be changed by overriding the method [formatLayoutTemplateFiles() |api:Nette\Application\UI\Presenter::formatLayoutTemplateFiles()], which returns an array of possible file names.
Variables in the Template
@@ -104,7 +150,7 @@ The `@property-read` annotation is for IDE and static analysis, it will make aut
You can indulge in the luxury of whispering in templates too, just install the Latte plugin in PhpStorm and specify the class name at the beginning of the template, see the article "Latte: how to type system":https://blog.nette.org/en/latte-how-to-use-type-system:
```latte
-{templateType App\Presenters\ArticleTemplate}
+{templateType App\UI\Article\ArticleTemplate}
...
```
@@ -176,7 +222,7 @@ public function beforeRender(): void
Latte version 3 offers a more advanced way by creating an [extension |latte:creating-extension] for each web project. Here is a rough example of such a class:
```php
-namespace App\Templating;
+namespace App\UI\Accessory;
final class LatteExtension extends Latte\Extension
{
@@ -214,7 +260,7 @@ We register it using [configuration#Latte]:
```neon
latte:
extensions:
- - App\Templating\LatteExtension
+ - App\UI\Accessory\LatteExtension
```
@@ -239,7 +285,7 @@ Alternatively, the translator can be set using the [configuration |configuration
```neon
latte:
extensions:
- - Latte\Essential\TranslatorExtension
+ - Latte\Essential\TranslatorExtension(@Nette\Localization\Translator)
```
The translator can then be used, for example, as a filter `|translate`, with additional parameters passed to the `translate()` method (see `foo, bar`):
diff --git a/application/es/ajax.texy b/application/es/ajax.texy
index a90acb698b..d1414e84c4 100644
--- a/application/es/ajax.texy
+++ b/application/es/ajax.texy
@@ -77,6 +77,12 @@ npm install naja
```
+Primero hay que [inicializar |https://naja.js.org/#/guide/01-install-setup-naja?id=initialization] la biblioteca:
+
+```js
+naja.initialize();
+```
+
Para convertir un enlace ordinario (señal) o el envío de un formulario en una petición AJAX, basta con marcar el enlace, formulario o botón correspondiente con la clase `ajax`:
```html
diff --git a/application/es/bootstrap.texy b/application/es/bootstrap.texy
index bed14d1d22..19bb56c0ba 100644
--- a/application/es/bootstrap.texy
+++ b/application/es/bootstrap.texy
@@ -20,18 +20,44 @@ use Nette\Bootstrap\Configurator;
class Bootstrap
{
- public static function boot(): Configurator
+ private Configurator $configurator;
+ private string $rootDir;
+
+ public function __construct()
+ {
+ $this->rootDir = dirname(__DIR__);
+ // El configurador se encarga de configurar el entorno y los servicios de la aplicación.
+ $this->configurator = new Configurator;
+ // Establecer el directorio para los archivos temporales generados por Nette (por ejemplo, plantillas compiladas).
+ $this->configurator->setTempDirectory($this->rootDir . '/temp');
+ }
+
+ public function bootWebApplication(): Nette\DI\Container
{
- $appDir = dirname(__DIR__);
- $configurator = new Configurator;
- //$configurator->setDebugMode('secret@23.75.345.200');
- $configurator->enableTracy($appDir . '/log');
- $configurator->setTempDirectory($appDir . '/temp');
- $configurator->createRobotLoader()
+ $this->initializeEnvironment();
+ $this->setupContainer();
+ return $this->configurator->createContainer();
+ }
+
+ private function initializeEnvironment(): void
+ {
+ // Nette es inteligente, y el modo de desarrollo se activa automáticamente,
+ // o puede habilitarlo para una dirección IP específica descomentando la siguiente línea:
+ // $this->configurator->setDebugMode('secret@23.75.345.200');
+
+ // Habilita Tracy: la última herramienta de depuración "navaja suiza".
+ $this->configurator->enableTracy($this->rootDir . '/log');
+
+ // RobotLoader: carga automáticamente todas las clases en el directorio dado
+ $this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
- $configurator->addConfig($appDir . '/config/common.neon');
- return $configurator;
+ }
+
+ private function setupContainer(): void
+ {
+ // Carga archivos de configuración
+ $this->configurator->addConfig($this->rootDir . '/config/common.neon');
}
}
```
@@ -40,16 +66,15 @@ class Bootstrap
index.php .[#toc-index-php]
===========================
-En el caso de las aplicaciones web, el archivo inicial es `index.php`, que se encuentra en el directorio público `www/`. Permite a la clase `Bootstrap` inicializar el entorno y devolver el `$configurator` que crea el contenedor DI. Luego obtiene el servicio `Application`, que ejecuta la aplicación web:
+El archivo inicial para aplicaciones web es `index.php`, ubicado en el directorio público `www/`. Utiliza la clase `Bootstrap` para inicializar el entorno y crear un contenedor DI. A continuación, obtiene el servicio `Application` del contenedor, que lanza la aplicación web:
```php
-// initialize the environment + get Configurator object
-$configurator = App\Bootstrap::boot();
-// create a DI container
-$container = $configurator->createContainer();
-// DI container creates a Nette\Application\Application object
+$bootstrap = new App\Bootstrap;
+// Inicializar el entorno + crear un contenedor DI
+$container = $bootstrap->bootWebApplication();
+// El contenedor DI crea un objeto Nette\Application\Application
$application = $container->getByType(Nette\Application\Application::class);
-// start Nette application
+// Inicia la aplicación Nette y gestiona la petición entrante
$application->run();
```
@@ -66,19 +91,19 @@ La selección del modo se hace por autodetección, por lo que normalmente no hay
Si desea habilitar el modo de desarrollo en otros casos, por ejemplo, para los programadores que acceden desde una dirección IP específica, puede utilizar `setDebugMode()`:
```php
-$configurator->setDebugMode('23.75.345.200'); // one or more IP addresses
+$this->configurator->setDebugMode('23.75.345.200'); // one or more IP addresses
```
Recomendamos encarecidamente combinar una dirección IP con una cookie. Almacenaremos un token secreto en la cookie `nette-debug`, por ejemplo `secret1234`, y el modo de desarrollo se activará para los programadores con esta combinación de IP y cookie.
```php
-$configurator->setDebugMode('secret1234@23.75.345.200');
+$this->configurator->setDebugMode('secret1234@23.75.345.200');
```
También podemos desactivar completamente el modo de desarrollo, incluso para localhost:
```php
-$configurator->setDebugMode(false);
+$this->configurator->setDebugMode(false);
```
Nótese que el valor `true` activa el modo desarrollador por fuerza, lo que nunca debería ocurrir en un servidor de producción.
@@ -90,7 +115,7 @@ Herramienta de depuración Tracy .[#toc-debugging-tool-tracy]
Para facilitar la depuración, activaremos la gran herramienta [Tracy |tracy:]. En modo desarrollador visualiza los errores y en modo producción los registra en el directorio especificado:
```php
-$configurator->enableTracy($appDir . '/log');
+$this->configurator->enableTracy($this->rootDir . '/log');
```
@@ -100,7 +125,7 @@ Archivos temporales .[#toc-temporary-files]
Nette utiliza la caché para el contenedor DI, RobotLoader, plantillas, etc. Por lo tanto es necesario establecer la ruta al directorio donde se almacenará la caché:
```php
-$configurator->setTempDirectory($appDir . '/temp');
+$this->configurator->setTempDirectory($this->rootDir . '/temp');
```
En Linux o macOS, establezca los [permisos de escritura |nette:troubleshooting#Setting directory permissions] para los directorios `log/` y `temp/`.
@@ -112,7 +137,7 @@ RobotLoader .[#toc-robotloader]
Normalmente, querremos cargar automáticamente las clases usando [RobotLoader |robot-loader:], así que tenemos que iniciarlo y dejar que cargue las clases desde el directorio donde se encuentra `Bootstrap.php` (es decir, `__DIR__`) y todos sus subdirectorios:
```php
-$configurator->createRobotLoader()
+$this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
```
@@ -126,7 +151,7 @@ Zona horaria .[#toc-timezone]
Configurator le permite especificar una zona horaria para su aplicación.
```php
-$configurator->setTimeZone('Europe/Prague');
+$this->configurator->setTimeZone('Europe/Prague');
```
@@ -143,16 +168,17 @@ En el modo de desarrollo, el contenedor se actualiza automáticamente cada vez q
Los archivos de configuración se cargan utilizando `addConfig()`:
```php
-$configurator->addConfig($appDir . '/config/common.neon');
+$this->configurator->addConfig($this->rootDir . '/config/common.neon');
```
El método `addConfig()` se puede llamar varias veces para añadir varios archivos.
```php
-$configurator->addConfig($appDir . '/config/common.neon');
-$configurator->addConfig($appDir . '/config/services.neon');
+$configDir = $this->rootDir . '/config';
+$this->configurator->addConfig($configDir . '/common.neon');
+$this->configurator->addConfig($configDir . '/services.neon');
if (PHP_SAPI === 'cli') {
- $configurator->addConfig($appDir . '/config/cli.php');
+ $this->configurator->addConfig($configDir . '/cli.php');
}
```
@@ -169,7 +195,7 @@ Parámetros estáticos .[#toc-static-parameters]
Los parámetros utilizados en los archivos de configuración pueden definirse [en la sección `parameters` |dependency-injection:configuration#parameters] y también pasarse (o sobrescribirse) por el método `addStaticParameters()` (tiene el alias `addParameters()`). Es importante que los diferentes valores de los parámetros provoquen la generación de contenedores DI adicionales, es decir, clases adicionales.
```php
-$configurator->addStaticParameters([
+$this->configurator->addStaticParameters([
'projectId' => 23,
]);
```
@@ -183,7 +209,7 @@ Parámetros dinámicos .[#toc-dynamic-parameters]
También podemos añadir parámetros dinámicos al contenedor, sus diferentes valores, a diferencia de los parámetros estáticos, no provocarán la generación de nuevos contenedores DI.
```php
-$configurator->addDynamicParameters([
+$this->configurator->addDynamicParameters([
'remoteIp' => $_SERVER['REMOTE_ADDR'],
]);
```
@@ -191,7 +217,7 @@ $configurator->addDynamicParameters([
Las variables de entorno podrían estar fácilmente disponibles utilizando parámetros dinámicos. Podemos acceder a ellas a través de `%env.variable%` en archivos de configuración.
```php
-$configurator->addDynamicParameters([
+$this->configurator->addDynamicParameters([
'env' => getenv(),
]);
```
@@ -206,6 +232,7 @@ Puede utilizar los siguientes parámetros estáticos en los archivos de configur
- `%wwwDir%` es la ruta absoluta al directorio que contiene el archivo de entrada `index.php`
- `%tempDir%` es la ruta absoluta al directorio para los archivos temporales
- `%vendorDir%` es la ruta absoluta al directorio donde Composer instala las bibliotecas
+- `%rootDir%` es la ruta absoluta al directorio raíz del proyecto
- `%debugMode%` indica si la aplicación está en modo depuración
- `%consoleMode%` indica si la solicitud llegó a través de la línea de comandos
@@ -225,7 +252,7 @@ services:
Creamos una nueva instancia y la insertamos en bootstrap:
```php
-$configurator->addServices([
+$this->configurator->addServices([
'myservice' => new App\Model\MyCustomService('foobar'),
]);
```
@@ -234,13 +261,21 @@ $configurator->addServices([
Diferentes entornos .[#toc-different-environments]
==================================================
-Siéntete libre de personalizar la clase `Bootstrap` para adaptarla a tus necesidades. Puedes añadir parámetros al método `boot()` para diferenciar proyectos web, o añadir otros métodos, como `bootForTests()`, que inicializa el entorno para pruebas unitarias, `bootForCli()` para scripts llamados desde la línea de comandos, etc.
+No dude en personalizar la clase `Bootstrap` según sus necesidades. Puedes añadir parámetros al método `bootWebApplication()` para diferenciar entre proyectos web. Alternativamente, puedes añadir otros métodos, como `bootTestEnvironment()` para inicializar el entorno para pruebas unitarias, `bootConsoleApplication()` para scripts llamados desde la línea de comandos, etc.
```php
-public static function bootForTests(): Configurator
+public function bootTestEnvironment(): Nette\DI\Container
+{
+ Tester\Environment::setup(); // Inicialización del comprobador de redes
+ $this->setupContainer();
+ return $this->configurator->createContainer();
+}
+
+public function bootConsoleApplication(): Nette\DI\Container
{
- $configurator = self::boot();
- Tester\Environment::setup(); // Nette Tester initialization
- return $configurator;
+ $this->configurator->setDebugMode(false);
+ $this->initializeEnvironment();
+ $this->setupContainer();
+ return $this->configurator->createContainer();
}
```
diff --git a/application/es/components.texy b/application/es/components.texy
index 0482a246a3..5e58b7e920 100644
--- a/application/es/components.texy
+++ b/application/es/components.texy
@@ -230,6 +230,28 @@ En la plantilla, estos mensajes están disponibles en la variable `$flashes` com
```
+Redirección tras una señal .[#toc-redirection-after-a-signal]
+=============================================================
+
+Después de procesar una señal de componente, a menudo se produce una redirección. Esta situación es similar a la de los formularios: después de enviar un formulario, también redirigimos para evitar que se vuelvan a enviar los datos cuando se actualiza la página en el navegador.
+
+```php
+$this->redirect('this') // redirects to the current presenter and action
+```
+
+Dado que un componente es un elemento reutilizable y, por lo general, no debería tener una dependencia directa de presentadores específicos, los métodos `redirect()` y `link()` interpretan automáticamente el parámetro como una señal de componente:
+
+```php
+$this->redirect('click') // redirects to the 'click' signal of the same component
+```
+
+Si necesita redirigir a un presentador o acción diferente, puede hacerlo a través del presentador:
+
+```php
+$this->getPresenter()->redirect('Product:show'); // redirects to a different presenter/action
+```
+
+
Parámetros persistentes .[#toc-persistent-parameters]
=====================================================
diff --git a/application/es/configuration.texy b/application/es/configuration.texy
index bbde2bac4e..aa5273344b 100644
--- a/application/es/configuration.texy
+++ b/application/es/configuration.texy
@@ -95,6 +95,9 @@ latte:
# habilita la [comprobación del código generado |latte:develop#Checking Generated Code]
phpLinter: ... # (string) por defecto es null
+ # establece la configuración regional
+ locale: cs_CZ # (string) por defecto es null
+
# clase de $this->plantilla
templateClass: App\MyTemplateClass # por defecto Nette\Bridges\ApplicationLatte\DefaultTemplate
```
@@ -104,7 +107,7 @@ Si está utilizando la versión 3 de Latte, puede añadir una nueva [extensión
```neon
latte:
extensions:
- - Latte\Essential\TranslatorExtension
+ - Latte\Essential\TranslatorExtension(@Nette\Localization\Translator)
```
/--comment
diff --git a/application/es/how-it-works.texy b/application/es/how-it-works.texy
index 1706cb62a5..e4e0447853 100644
--- a/application/es/how-it-works.texy
+++ b/application/es/how-it-works.texy
@@ -22,13 +22,13 @@ La estructura de directorios se parece a esto
/--pre
web-project/
├── app/ ← directorio con la aplicación
-│ ├── Presenters/ ← clases para presentadores
-│ │ ├── HomePresenter.php ← Home de inicio de la clase de presentador
-│ │ └── templates/ ← directorio de plantillas
-│ │ ├── @layout.latte ← plantilla de diseño compartida
-│ │ └── Home/ ← plantillas para Home presentador de inicio
-│ │ └── default.latte ← plantilla para la acción `default`
-│ ├── Router/ ← configuración de direcciones URL
+│ ├── Core/ ← clases básicas necesarias.
+│ │ └── RouterFactory.php ← configuración de direcciones URL.
+│ ├── UI/ ← presentadores, plantillas & co.
+│ │ ├── @layout.latte ← plantilla de maquetación compartida
+│ │ └── Home/ ← Home directorio del presentador
+│ │ ├── HomePresenter.php ← Clase del presentador de inicio
+│ │ └── default.latte ← plantilla para la acción default
│ └── Bootstrap.php ← clase de arranque Bootstrap
├── bin/ ← scripts para la línea de comandos
├── config/ ← archivos de configuración
@@ -91,7 +91,7 @@ Las aplicaciones escritas en Nette se dividen en muchos de los llamados presenta
La aplicación comienza pidiendo al llamado enrutador que decida a cuál de los presentadores debe pasar la petición actual para su procesamiento. El enrutador decide de quién es la responsabilidad. Mira la URL de entrada `https://example.com/product/123`, que quiere `show` un producto con `id: 123` como acción. Es una buena costumbre escribir pares de presentador + acción separados por dos puntos como `Product:show`.
-Así que el enrutador transforma la URL en un par `Presenter:action` + parámetros, en nuestro caso `Product:show` + `id: 123`. Puedes ver el aspecto de un enrutador en el archivo `app/Router/RouterFactory.php` y lo describiremos en detalle en el capítulo [Enrutamiento |Routing].
+Así que el enrutador transforma la URL en un par `Presenter:action` + parámetros, en nuestro caso `Product:show` + `id: 123`. Puedes ver el aspecto de un enrutador en el archivo `app/Core/RouterFactory.php` y lo describiremos en detalle en el capítulo [Enrutamiento |Routing].
Sigamos. La aplicación ya conoce el nombre del presentador y puede continuar. Creando un objeto `ProductPresenter`, que es el código del presentador `Product`. Más concretamente, le pide al contenedor DI que cree el presentador, porque producir objetos es su trabajo.
@@ -121,12 +121,9 @@ Así, se llamó al método `renderShow(123)`, cuyo código es ficticio ejemplo,
Posteriormente, el presentador devuelve la respuesta. Esta puede ser una página HTML, una imagen, un documento XML, el envío de un fichero desde disco, JSON o la redirección a otra página. Es importante destacar que, si no decimos explícitamente cómo responder (que es el caso de `ProductPresenter`), la respuesta será renderizar la plantilla con una página HTML. ¿Por qué? Pues porque en el 99% de los casos queremos dibujar una plantilla, así que el presentador toma este comportamiento por defecto y quiere facilitarnos el trabajo. Ese es el punto de Nette.
-Ni siquiera tenemos que indicar qué plantilla dibujar, él deriva la ruta hacia ella según una lógica simple. En el caso del presentador `Product` y la acción `show`, intenta ver si uno de estos archivos de plantilla existe en relación al directorio donde se encuentra la clase `ProductPresenter`:
+Ni siquiera necesitamos especificar qué plantilla renderizar; el framework deducirá la ruta por sí mismo. En el caso de la acción `show`, simplemente intenta cargar la plantilla `show.latte` en el directorio con la clase `ProductPresenter`. También intenta encontrar el diseño en el archivo `@layout.latte` (más información sobre la [búsqueda de plantillas |templates#Template Lookup]).
-- `templates/Product/show.latte`
-- `templates/Product.show.latte`
-
-También intentará encontrar el diseño en el archivo `@layout.latte` y luego renderizará la plantilla. Ahora se completa la tarea del presentador y de toda la aplicación. Si la plantilla no existe, se devolverá una página con el error 404. Puedes leer más sobre los presentadores en la página de [Presentadores |Presenters].
+Posteriormente, se renderizan las plantillas. Esto completa la tarea del presentador y de toda la aplicación, y el trabajo está hecho. Si la plantilla no existiera, se devolvería una página de error 404. Puede leer más sobre los presentadores en la página [Presentadores |presenters].
[* request-flow.svg *]
@@ -137,7 +134,7 @@ Sólo para estar seguros, intentemos recapitular todo el proceso con una URL lig
3) el router decodifica la URL como un par `Home:default`
4) se crea un objeto `HomePresenter`
5) se llama al método `renderDefault()` (si existe)
-6) se renderiza una plantilla `templates/Home/default.latte` con un diseño `templates/@layout.latte`
+6) se renderiza una plantilla `default.latte` con un diseño `@layout.latte`
Puede que ahora te hayas encontrado con un montón de conceptos nuevos, pero creemos que tienen sentido. Crear aplicaciones en Nette es pan comido.
diff --git a/application/es/modules.texy b/application/es/modules.texy
index 644cab5c1f..2827183beb 100644
--- a/application/es/modules.texy
+++ b/application/es/modules.texy
@@ -2,29 +2,31 @@ Módulos
*******
.[perex]
-En Nette, los módulos representan las unidades lógicas que componen una aplicación. Incluyen presentadores, plantillas, posiblemente también componentes y clases modelo.
+Los módulos aportan claridad a las aplicaciones Nette al facilitar su división en unidades lógicas.
-Un directorio para los presentadores y otro para las plantillas no serían suficientes para los proyectos reales. Tener docenas de archivos en una carpeta es, como mínimo, desorganizado. ¿Cómo salir de ello? Simplemente los dividimos en subdirectorios en el disco y en espacios de nombres en el código. Y eso es exactamente lo que hacen los módulos de Nette.
-
-Así que olvidémonos de una única carpeta para presentadores y plantillas y en su lugar creemos módulos, por ejemplo `Admin` y `Front`.
+De forma similar a la organización de archivos en carpetas en un disco duro, en Nette podemos dividir los presentadores, plantillas y otras clases auxiliares en módulos. ¿Cómo funciona esto en la práctica? Simplemente incorporando nuevos subdirectorios a la estructura. He aquí un ejemplo de estructura con dos módulos, Front y Admin:
/--pre
-app/
-├── Presenters/
-├── Modules/ ← directorio con módulos
-│ ├── Admin/ ← módulo Admin
-│ │ ├── Presenters/ ← sus presentadores
-│ │ │ ├── DashboardPresenter.php
-│ │ │ └── templates/
-│ └── Front/ ← módulo Front
-│ └── Presenters/ ← sus presentadores
-│ └── ...
+app/
+├── UI/
+│ ├── Admin/ ← Admin module
+│ │ ├── @layout.latte
+│ │ ├── Dashboard/
+│ │ │ ├── DashboardPresenter.php
+│ │ │ └── default.latte
+│ │ └── ...
+│ ├── Front/ ← Front module
+│ │ ├── @layout.latte
+│ │ ├── Home/
+│ │ │ ├── HomePresenter.php
+│ │ │ └── default.latte
+│ │ └── ...
\--
-Esta estructura de directorios se reflejará en los espacios de nombres de las clases, así por ejemplo `DashboardPresenter` estará en el espacio de nombres `App\Modules\Admin\Presenters`:
+Esta estructura de directorios se refleja en los espacios de nombres de las clases, así por ejemplo, `DashboardPresenter` se encuentra en el espacio de nombres `App\UI\Admin\Dashboard`:
```php
-namespace App\Modules\Admin\Presenters;
+namespace App\UI\Admin\Dashboard;
class DashboardPresenter extends Nette\Application\UI\Presenter
{
@@ -32,35 +34,49 @@ class DashboardPresenter extends Nette\Application\UI\Presenter
}
```
-El presentador `Dashboard` dentro del módulo `Admin` es referenciado dentro de la aplicación usando la notación de dos puntos como `Admin:Dashboard`, y su acción `default` como `Admin:Dashboard:default`.
-¿Y cómo sabe Nette que `Admin:Dashboard` representa la clase `App\Modules\Admin\Presenters\DashboardPresenter`? Esto se determina mediante el [mapeo |#mapping] en la configuración.
-Por lo tanto, la estructura dada no es rígida y puede modificarla según sus necesidades.
+En la aplicación, nos referimos al presentador `Dashboard` dentro del módulo `Admin` utilizando la notación de dos puntos como `Admin:Dashboard`. Para su acción `default`, nos referimos a él como `Admin:Dashboard:default`.
-Por supuesto, los módulos pueden contener todos los demás elementos además de presentadores y plantillas, como componentes, clases modelo, etc.
+La estructura presentada no es rígida; puede [adaptarla totalmente a sus necesidades |#mapping] en la configuración. .[tip]
+
+Los módulos pueden incluir todos los demás archivos, como componentes y clases auxiliares, además de presentadores y plantillas. Si está pensando dónde colocarlos, considere la posibilidad de utilizar una carpeta `Accessory`:
+
+/--pre
+app/
+├── UI/
+│ ├── Admin/
+│ │ ├── Accessory/
+│ │ │ ├── FormFactory.php
+│ │ │ └── AdminLayout.php
+│ │ ├── Dashboard/
+│ │ └── ...
+\--
Módulos anidados .[#toc-nested-modules]
---------------------------------------
-Los módulos no tienen por qué formar sólo una estructura plana, también puedes crear submódulos, por ejemplo:
+Los módulos pueden tener múltiples niveles de anidamiento, similar a una estructura de directorios en un disco:
/--pre
-app/
-├── Modules/ ← directorio con módulos
-│ ├── Blog/ ← módulo Blog
-│ │ ├── Admin/ ← submódulo Admin
-│ │ │ ├── Presenters/
+app/
+├── UI/
+│ ├── Blog/ ← Blog module
+│ │ ├── Admin/ ← Admin submodule
+│ │ │ ├── Dashboard/
+│ │ │ └── ...
+│ │ ├── Front/ ← Front submodule
+│ │ │ ├── @layout.latte
+│ │ │ ├── Home/
│ │ │ └── ...
-│ │ └── Front/ ← submódulo Front
-│ │ ├── Presenters/
-│ │ └── ...
-│ ├── Forum/ ← módulo Forum
+│ ├── Forum/ ← Forum module
│ │ └── ...
\--
-Así, el módulo `Blog` se divide en los submódulos `Admin` y `Front`. De nuevo, esto se reflejará en los espacios de nombres, que serán `App\Modules\Blog\Admin\Presenters`, etc. El presentador `Dashboard` dentro del submódulo se denomina `Blog:Admin:Dashboard`.
+El módulo `Blog` se divide en los submódulos `Admin` y `Front`. Esto también se refleja en los espacios de nombres, que aparecen como `App\UI\Blog\Admin` y similares. Para referirnos al presentador `Dashboard` dentro del submódulo `Admin`, lo denominamos `Blog:Admin:Dashboard`.
-El anidamiento puede ser tan profundo como se desee, por lo que pueden crearse submódulos.
+El anidamiento puede ser tan profundo como sea necesario, permitiendo la creación de sub-submódulos.
+
+Por ejemplo, si en administración tiene muchos presentadores relacionados con la gestión de pedidos, como `OrderDetail`, `OrderEdit`, `OrderDispatch`, etc., puede crear un módulo `Order` en el que se organizarán presentadores como `Detail`, `Edit`, `Dispatch`, y otros.
Creación de enlaces .[#toc-creating-links]
@@ -99,49 +115,69 @@ Enrutamiento .[#toc-routing]
Véase el [capítulo sobre en rutamiento|routing#Modules].
-Mapeo .[#toc-mapping]
----------------------
+Cartografía .[#toc-mapping]
+---------------------------
+
+El mapeo define las reglas para derivar el nombre de la clase del nombre del presentador. Estas reglas se especifican en la [configuración |configuration] bajo la clave `application › mapping`.
+
+Las estructuras de directorios mencionadas anteriormente en esta página se basan en la siguiente asignación:
-Define las reglas por las que el nombre de la clase se deriva del nombre del presentador. Las escribimos en [configuración |configuration] bajo la clave `application › mapping`.
+```neon
+application:
+ mapping: App\UI\*\**Presenter
+```
-Empecemos con un ejemplo que no utiliza módulos. Sólo querremos que las clases del presentador tengan el espacio de nombres `App\Presenters`. Eso significa que un presentador como `Home` debe mapearse a la clase `App\Presenters\HomePresenter`. Esto se puede lograr con la siguiente configuración:
+¿Cómo funciona el mapeo? Para entenderlo mejor, imaginemos primero una aplicación sin módulos. Queremos que las clases del presentador pertenezcan al espacio de nombres `App\UI`, de modo que el presentador `Home` se asigne a la clase `App\UI\HomePresenter`. Esto se puede lograr con esta configuración:
```neon
application:
- mapping: App\Presenters\*Presenter
+ mapping: App\UI\*Presenter
```
-El nombre del presentador se sustituye por el asterisco en la máscara de clase y el resultado es el nombre de la clase. Muy fácil.
+Este mapeo funciona reemplazando el asterisco en la máscara `App\UI\*Presenter` con el nombre del presentador `Home`, resultando en el nombre final de la clase `App\UI\HomePresenter`. Es muy sencillo.
+
+Sin embargo, como puede ver en los ejemplos de este y otros capítulos, colocamos las clases de presentador en subdirectorios epónimos, por ejemplo, el presentador `Home` se asigna a la clase `App\UI\Home\HomePresenter`. Esto se consigue duplicando el asterisco (requiere Nette Application 3.2):
+
+```neon
+application:
+ mapping: App\UI\**Presenter
+```
-Si dividimos a los presentadores en módulos, podemos tener nuestra propia asignación para cada módulo:
+Pasemos ahora a la asignación de presentadores a módulos. Podemos definir asignaciones específicas para cada módulo:
```neon
application:
mapping:
- Front: App\Modules\Front\Presenters\*Presenter
- Admin: App\Modules\Admin\Presenters\*Presenter
+ Front: App\UI\Front\**Presenter
+ Admin: App\UI\Admin\**Presenter
Api: App\Api\*Presenter
```
-Ahora el presentador `Front:Home` se asigna a la clase `App\Modules\Front\Presenters\HomePresenter` y el presentador `Admin:Dashboard` a la clase `App\Modules\Admin\Presenters\DashboardPresenter`.
+Según esta configuración, el presentador `Front:Home` se asigna a la clase `App\UI\Front\Home\HomePresenter`, mientras que el presentador `Api:OAuth` se asigna a la clase `App\Api\OAuthPresenter`.
-Es más práctico crear una regla general (estrella) para sustituir a las dos primeras. El asterisco adicional se añadirá a la máscara de clase sólo para el módulo:
+Puesto que los módulos `Front` y `Admin` tienen un enfoque de asignación similar y es probable que haya más módulos de este tipo, es posible crear una regla general que los sustituya. Se añade un nuevo asterisco para el módulo a la máscara de la clase:
```neon
application:
mapping:
- *: App\Modules\*\Presenters\*Presenter
+ *: App\UI\*\**Presenter
Api: App\Api\*Presenter
```
-Pero, ¿y si utilizamos módulos anidados y tenemos un presentador `Admin:User:Edit`? En este caso, el segmento con un asterisco que representa el módulo para cada nivel simplemente se repite y el resultado es la clase `App\Modules\Admin\User\Presenters\EditPresenter`.
+Para los módulos anidados de varios niveles, como el presentador `Admin:User:Edit`, el segmento del asterisco se repite para cada nivel, lo que da como resultado la clase `App\UI\Admin\User\Edit\EditPresenter`.
-Una notación alternativa es utilizar una matriz formada por tres segmentos en lugar de una cadena. Esta notación es equivalente a la anterior:
+Una notación alternativa consiste en utilizar una matriz compuesta por tres segmentos en lugar de una cadena. Esta notación es equivalente a la anterior:
```neon
application:
mapping:
- *: [App\Modules, *, Presenters\*Presenter]
+ *: [App\UI, *, **Presenter]
+ Api: [App\Api, '', *Presenter]
```
-El valor por defecto es `*Module\*Presenter`.
+Si sólo tenemos una regla en la configuración, la general, podemos escribir brevemente:
+
+```neon
+application:
+ mapping: App\UI\*\**Presenter
+```
diff --git a/application/es/presenters.texy b/application/es/presenters.texy
index 22cb178aa9..ee6f551d6c 100644
--- a/application/es/presenters.texy
+++ b/application/es/presenters.texy
@@ -60,7 +60,7 @@ Similar al método `render()`. Mientras que `render()` está destina
Es importante que `action()` se llame antes que `render()`para que dentro de él podamos posiblemente cambiar el siguiente curso del ciclo de vida, es decir, cambiar la plantilla que será renderizada y también el método `render()` que será llamado, usando `setView('otherView')`.
-Los parámetros de la petición se pasan al método. Es posible y recomendable especificar tipos para los parámetros, por ejemplo `actionShow(int $id, string $slug = null)` - si el parámetro `id` falta o si no es un entero, el presentador devuelve [el error 404 |#Error 404 etc.] y termina la operación.
+Los parámetros de la petición se pasan al método. Es posible y recomendable especificar tipos para los parámetros, por ejemplo `actionShow(int $id, ?string $slug = null)` - si el parámetro `id` falta o si no es un entero, el presentador devuelve [el error 404 |#Error 404 etc.] y termina la operación.
`handle(args...)` .{toc: handle()}
@@ -205,7 +205,7 @@ En la plantilla, estos mensajes están disponibles en la variable `$flashes` com
Error 404 etc. .[#toc-error-404-etc]
====================================
-Cuando no podamos satisfacer la petición porque por ejemplo el artículo que queremos mostrar no existe en la base de datos, lanzaremos el error 404 utilizando el método `error(string $message = null, int $httpCode = 404)`, que representa el error HTTP 404:
+Cuando no podamos satisfacer la petición porque por ejemplo el artículo que queremos mostrar no existe en la base de datos, lanzaremos el error 404 utilizando el método `error(?string $message = null, int $httpCode = 404)`, que representa el error HTTP 404:
```php
public function renderShow(int $id): void
@@ -384,7 +384,7 @@ La redirección no se produce con una solicitud AJAX o POST porque provocaría u
También puede invocar la canonización manualmente mediante el método `canonicalize()`, que, al igual que el método `link()`, recibe el presentador, las acciones y los parámetros como argumentos. Crea un enlace y lo compara con la URL actual. Si es diferente, redirige al enlace generado.
```php
-public function actionShow(int $id, string $slug = null): void
+public function actionShow(int $id, ?string $slug = null): void
{
$realSlug = $this->facade->getSlugForId($id);
// redirects if $slug is different from $realSlug
@@ -452,17 +452,6 @@ Restricción de acceso mediante `#[Requires]` .[#toc-access-restriction-using-re
El atributo `#[Requires]` ofrece opciones avanzadas para restringir el acceso a los presentadores y sus métodos. Puede utilizarse para especificar métodos HTTP, requerir solicitudes AJAX, limitar el acceso al mismo origen y restringir el acceso sólo al reenvío. El atributo puede aplicarse a clases de presentadores, así como a métodos individuales como `action()`, `render()`, `handle()`y `createComponent()`.
-He aquí un ejemplo de su uso para restringir el acceso únicamente al método HTTP `POST`:
-
-```php
-use Nette\Application\Attributes\Requires;
-
-#[Requires(methods: 'POST')]
-class MyPresenter extends Nette\Application\UI\Presenter
-{
-}
-```
-
Puede especificar estas restricciones
- en los métodos HTTP: `#[Requires(methods: ['GET', 'POST'])]`
- que requieren una petición AJAX: `#[Requires(ajax: true)]`
@@ -470,22 +459,7 @@ Puede especificar estas restricciones
- acceso sólo mediante reenvío: `#[Requires(forward: true)]`
- restricciones sobre acciones específicas: `#[Requires(actions: 'default')]`
-Las condiciones pueden combinarse enumerando varios atributos o uniéndolos en uno solo:
-
-```php
-#[Requires(methods: 'POST', ajax: true)]
-public function actionDelete(int $id)
-{
-}
-
-// or
-
-#[Requires(methods: 'POST')]
-#[Requires(ajax: true)]
-public function actionDelete(int $id)
-{
-}
-```
+Para obtener más información, consulte [Cómo utilizar el atributo Requires atributo |best-practices:attribute-requires].
Comprobación del método HTTP .[#toc-http-method-check]
diff --git a/application/es/routing.texy b/application/es/routing.texy
index c6ed0f3950..417438e650 100644
--- a/application/es/routing.texy
+++ b/application/es/routing.texy
@@ -216,7 +216,7 @@ $router->addRoute('//www.%sld%.%tld%/%basePath%//addRoute('/[/]', [
@@ -225,7 +225,7 @@ $router->addRoute('/[/]', [
]);
```
-O podemos utilizar esta forma, observe la reescritura de la expresión regular de validación:
+Para una especificación más detallada, se puede utilizar una forma aún más extendida, en la que además de los valores por defecto, se pueden establecer otras propiedades de los parámetros, como una expresión regular de validación (véase el parámetro `id` ):
```php
use Nette\Routing\Route;
@@ -243,7 +243,7 @@ $router->addRoute('/[/]', [
]);
```
-Estos formatos más locuaces son útiles para añadir otros metadatos.
+Es importante señalar que si los parámetros definidos en la matriz no se incluyen en la máscara de ruta, sus valores no podrán modificarse, ni siquiera utilizando parámetros de consulta especificados tras un signo de interrogación en la URL.
Filtros y traducciones .[#toc-filters-and-translations]
@@ -477,10 +477,10 @@ $router->addRoute('index.html \.html?|\.php|>', /* ... */);
Integración .[#toc-integration]
===============================
-Para conectar nuestro router a la aplicación, debemos informar al contenedor DI sobre él. La forma más sencilla es preparar la fábrica que construirá el objeto router y decirle a la configuración del contenedor que lo utilice. Digamos que escribimos un método para este propósito `App\Router\RouterFactory::createRouter()`:
+Para conectar nuestro router a la aplicación, debemos informar al contenedor DI sobre él. La forma más sencilla es preparar la fábrica que construirá el objeto router y decirle a la configuración del contenedor que lo utilice. Digamos que escribimos un método para este propósito `App\Core\RouterFactory::createRouter()`:
```php
-namespace App\Router;
+namespace App\Core;
use Nette\Application\Routers\RouteList;
@@ -499,7 +499,7 @@ Luego escribimos en [configuración |dependency-injection:services]:
```neon
services:
- - App\Router\RouterFactory::createRouter
+ - App\Core\RouterFactory::createRouter
```
Cualquier dependencia, como una conexión de base de datos, etc., se pasa al método de fábrica como sus parámetros utilizando [autowiring |dependency-injection:autowiring]:
@@ -663,7 +663,7 @@ Por uso separado, nos referimos al uso de las capacidades del router en una apli
Así que de nuevo crearemos un método que construirá un enrutador, por ejemplo
```php
-namespace App\Router;
+namespace App\Core;
use Nette\Routing\RouteList;
@@ -694,7 +694,7 @@ $httpRequest = $container->getByType(Nette\Http\IRequest::class);
O crearemos los objetos directamente:
```php
-$router = App\Router\RouterFactory::createRouter();
+$router = App\Core\RouterFactory::createRouter();
$httpRequest = (new Nette\Http\RequestFactory)->fromGlobals();
```
diff --git a/application/es/templates.texy b/application/es/templates.texy
index 761f7a648e..af06db6505 100644
--- a/application/es/templates.texy
+++ b/application/es/templates.texy
@@ -34,35 +34,81 @@ Y esta podría ser la plantilla de acción:
Define el bloque `content`, que se inserta en lugar de `{include content}` en el diseño, y también redefine el bloque `title`, que sobrescribe `{block title}` en el diseño. Intenta imaginar el resultado.
-Búsqueda de plantillas .[#toc-search-for-templates]
----------------------------------------------------
+Búsqueda de plantillas .[#toc-template-lookup]
+----------------------------------------------
-La ruta a las plantillas se deduce según una lógica simple. Se intenta ver si uno de estos archivos de plantilla existe en relación con el directorio donde se encuentra la clase de presentador, donde `` es el nombre del presentador actual y `` es el nombre de la acción actual:
+En los presentadores, no es necesario especificar qué plantilla debe renderizarse; el framework determinará automáticamente la ruta, facilitándole la codificación.
-- `templates//.latte`
-- `templates/..latte`
+Si utiliza una estructura de directorios donde cada presentador tiene su propio directorio, simplemente coloque la plantilla en este directorio bajo el nombre de la acción (es decir, vista). Por ejemplo, para la acción `default`, utilice la plantilla `default.latte`:
-Si no se encuentra la plantilla, se intentará buscar en el directorio `templates` un nivel más arriba, es decir, al mismo nivel que el directorio con la clase presentadora.
+/--pre
+app/
+└── UI/
+ └── Home/
+ ├── HomePresenter.php
+ └── default.latte
+\--
-Si la plantilla tampoco se encuentra allí, la respuesta es un [error 404 |presenters#Error 404 etc.].
+Si utiliza una estructura en la que los presentadores están juntos en un directorio y las plantillas en una carpeta `templates`, guárdela en un archivo `..latte` o en `/.latte`:
-También puede cambiar la vista utilizando `$this->setView('otherView')`. O, en lugar de buscar, especifique directamente el nombre del archivo de plantilla utilizando `$this->template->setFile('/path/to/template.latte')`.
+/--pre
+app/
+└── Presenters/
+ ├── HomePresenter.php
+ └── templates/
+ ├── Home.default.latte ← 1st variant
+ └── Home/
+ └── default.latte ← 2nd variant
+\--
+
+El directorio `templates` también puede colocarse un nivel más arriba, al mismo nivel que el directorio con las clases de presentador.
+
+Si no se encuentra la plantilla, el presentador responde con el [error 404 - página no encontrada |presenters#Error 404 etc].
+
+Puede cambiar la vista utilizando `$this->setView('anotherView')`. También es posible especificar directamente el archivo de plantilla con `$this->template->setFile('/path/to/template.latte')`.
.[note]
-Puede cambiar las rutas donde se buscan las plantillas anulando el método [formatTemplateFiles |api:Nette\Application\UI\Presenter::formatTemplateFiles()], que devuelve una matriz de posibles rutas de archivo.
+Los archivos en los que se buscan las plantillas pueden cambiarse anulando el método [formatTemplateFiles() |api:Nette\Application\UI\Presenter::formatTemplateFiles()], que devuelve una matriz de posibles nombres de archivo.
+
+
+Búsqueda de plantillas de diseño .[#toc-layout-template-lookup]
+---------------------------------------------------------------
+
+Nette también busca automáticamente el archivo de diseño.
+
+Si utiliza una estructura de directorios en la que cada presentador tiene su propio directorio, coloque la maqueta en la carpeta con el presentador, si es específica sólo para él, o en un nivel superior si es común a varios presentadores:
+
+/--pre
+app/
+└── UI/
+ ├── @layout.latte ← common layout
+ └── Home/
+ ├── @layout.latte ← only for Home presenter
+ ├── HomePresenter.php
+ └── default.latte
+\--
+
+Si utiliza una estructura en la que los presentadores están agrupados en un directorio y las plantillas se encuentran en una carpeta `templates`, la maquetación se esperará en los siguientes lugares:
-El diseño se espera en los siguientes archivos:
+/--pre
+app/
+└── Presenters/
+ ├── HomePresenter.php
+ └── templates/
+ ├── @layout.latte ← common layout
+ ├── Home.@layout.latte ← only for Home, 1st variant
+ └── Home/
+ └── @layout.latte ← only for Home, 2nd variant
+\--
-- `templates//@.latte`
-- `templates/.@.latte`
-- `templates/@.latte` diseño común a varios presentadores
+Si el presentador está en un [módulo |modules], también buscará más arriba en el árbol de directorios según el anidamiento del módulo.
-`` es el nombre del presentador actual y `` es el nombre de la maquetación, que por defecto es `'layout'`. El nombre puede cambiarse con `$this->setLayout('otherLayout')`, de modo que se intentarán los archivos `@otherLayout.latte`.
+El nombre de la presentación puede cambiarse utilizando `$this->setLayout('layoutAdmin')` y entonces se esperará en el archivo `@layoutAdmin.latte`. También puede especificar directamente el archivo de plantilla de presentación utilizando `$this->setLayout('/path/to/template.latte')`.
-También puede especificar directamente el nombre de archivo de la plantilla de maquetación con `$this->setLayout('/path/to/template.latte')`. El uso de `$this->setLayout(false)` desactivará la búsqueda de diseños.
+El uso de `$this->setLayout(false)` o de la etiqueta `{layout none}` dentro de la plantilla desactiva la búsqueda de diseños.
.[note]
-Puede cambiar las rutas donde se buscan las plantillas anulando el método [formatLayoutTemplateFiles |api:Nette\Application\UI\Presenter::formatLayoutTemplateFiles()], que devuelve una matriz de posibles rutas de archivo.
+Los archivos en los que se buscan las plantillas de diseño pueden modificarse modificando el método [formatLayoutTemplateFiles() |api:Nette\Application\UI\Presenter::formatLayoutTemplateFiles()], que devuelve una matriz de posibles nombres de archivo.
Variables en la plantilla .[#toc-variables-in-the-template]
@@ -104,7 +150,7 @@ La anotación `@property-read` es para IDE y análisis estático, hará que func
Puedes permitirte el lujo de susurrar en las plantillas también, simplemente instala el plugin Latte en PhpStorm y especifica el nombre de la clase al principio de la plantilla, ver el artículo "Latte: cómo escribir sistema:https://blog.nette.org/es/latte-como-utilizar-el-sistema-de-tipos":
```latte
-{templateType App\Presenters\ArticleTemplate}
+{templateType App\UI\Article\ArticleTemplate}
...
```
@@ -176,7 +222,7 @@ public function beforeRender(): void
La versión 3 de Latte ofrece una forma más avanzada creando una [extensión |latte:creating-extension] para cada proyecto web. He aquí un ejemplo aproximado de una clase de este tipo:
```php
-namespace App\Templating;
+namespace App\UI\Accessory;
final class LatteExtension extends Latte\Extension
{
@@ -214,7 +260,7 @@ La registramos usando [configuration|configuration#Latte]:
```neon
latte:
extensions:
- - App\Templating\LatteExtension
+ - App\UI\Accessory\LatteExtension
```
@@ -239,7 +285,7 @@ Alternativamente, el traductor se puede establecer utilizando la [configuración
```neon
latte:
extensions:
- - Latte\Essential\TranslatorExtension
+ - Latte\Essential\TranslatorExtension(@Nette\Localization\Translator)
```
El traductor puede utilizarse, por ejemplo, como un filtro `|translate`, con parámetros adicionales pasados al método `translate()` (véase `foo, bar`):
diff --git a/application/fr/ajax.texy b/application/fr/ajax.texy
index 6ef5b2bf32..d93abac2f4 100644
--- a/application/fr/ajax.texy
+++ b/application/fr/ajax.texy
@@ -77,6 +77,12 @@ npm install naja
```
+Vous devez d'abord [initialiser |https://naja.js.org/#/guide/01-install-setup-naja?id=initialization] la bibliothèque :
+
+```js
+naja.initialize();
+```
+
Pour faire d'un lien ordinaire (signal) ou d'une soumission de formulaire une requête AJAX, il suffit de marquer le lien, le formulaire ou le bouton correspondant avec la classe `ajax`:
```html
diff --git a/application/fr/bootstrap.texy b/application/fr/bootstrap.texy
index 3b80608880..32c12e829b 100644
--- a/application/fr/bootstrap.texy
+++ b/application/fr/bootstrap.texy
@@ -20,18 +20,44 @@ use Nette\Bootstrap\Configurator;
class Bootstrap
{
- public static function boot(): Configurator
+ private Configurator $configurator;
+ private string $rootDir;
+
+ public function __construct()
+ {
+ $this->rootDir = dirname(__DIR__);
+ // Le configurateur est chargé de configurer l'environnement et les services de l'application.
+ $this->configurator = new Configurator;
+ // Définir le répertoire pour les fichiers temporaires générés par Nette (par exemple, les modèles compilés)
+ $this->configurator->setTempDirectory($this->rootDir . '/temp');
+ }
+
+ public function bootWebApplication(): Nette\DI\Container
{
- $appDir = dirname(__DIR__);
- $configurator = new Configurator;
- //$configurator->setDebugMode('secret@23.75.345.200');
- $configurator->enableTracy($appDir . '/log');
- $configurator->setTempDirectory($appDir . '/temp');
- $configurator->createRobotLoader()
+ $this->initializeEnvironment();
+ $this->setupContainer();
+ return $this->configurator->createContainer();
+ }
+
+ private function initializeEnvironment(): void
+ {
+ // Nette est intelligent, et le mode développement est activé automatiquement,
+ // ou vous pouvez l'activer pour une adresse IP spécifique en décommentant la ligne suivante:
+ // $this->configurator->setDebugMode('secret@23.75.345.200');
+
+ // Active Tracy: l'ultime outil de débogage "couteau suisse".
+ $this->configurator->enableTracy($this->rootDir . '/log');
+
+ // RobotLoader: charge automatiquement toutes les classes dans le répertoire donné
+ $this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
- $configurator->addConfig($appDir . '/config/common.neon');
- return $configurator;
+ }
+
+ private function setupContainer(): void
+ {
+ // Chargement des fichiers de configuration
+ $this->configurator->addConfig($this->rootDir . '/config/common.neon');
}
}
```
@@ -40,16 +66,15 @@ class Bootstrap
index.php .[#toc-index-php]
===========================
-Dans le cas des applications web, le fichier initial est `index.php`, qui se trouve dans le répertoire public `www/`. Il laisse la classe `Bootstrap` pour initialiser l'environnement et retourne la classe `$configurator` qui crée le conteneur DI. Ensuite, il obtient le service `Application`, qui exécute l'application web :
+Le fichier initial des applications web est `index.php`, situé dans le répertoire public `www/`. Il utilise la classe `Bootstrap` pour initialiser l'environnement et créer un conteneur DI. Ensuite, il obtient le service `Application` du conteneur, ce qui lance l'application web :
```php
-// initialisation de l'environnement + obtention de l'objet Configurateur
-$configurator = App\Bootstrap::boot();
-// créer un conteneur DI
-$container = $configurator->createContainer();
+$bootstrap = new App\Bootstrap;
+// Initialiser l'environnement + créer un conteneur DI
+$container = $bootstrap->bootWebApplication();
// Le conteneur DI crée un objet Nette\Application\Application
$application = $container->getByType(Nette\Application\Application::class);
-// Démarrage de l'application Nette
+// Démarrer l'application Nette et traiter la demande entrante
$application->run();
```
@@ -66,19 +91,19 @@ La sélection du mode se fait par autodétection, il n'est donc généralement p
Si vous souhaitez activer le mode développement dans d'autres cas, par exemple pour les programmeurs accédant depuis une adresse IP spécifique, vous pouvez utiliser `setDebugMode()`:
```php
-$configurator->setDebugMode('23.75.345.200'); // une ou plusieurs adresses IP
+$this->configurator->setDebugMode('23.75.345.200'); // une ou plusieurs adresses IP
```
Nous recommandons vivement de combiner une adresse IP avec un cookie. Nous stockerons un jeton secret dans le cookie `nette-debug`, par exemple `secret1234`, et le mode de développement sera activé pour les programmeurs avec cette combinaison d'IP et de cookie.
```php
-$configurator->setDebugMode('secret1234@23.75.345.200');
+$this->configurator->setDebugMode('secret1234@23.75.345.200');
```
Nous pouvons également désactiver complètement le mode de développement, même pour localhost :
```php
-$configurator->setDebugMode(false);
+$this->configurator->setDebugMode(false);
```
Notez que la valeur `true` active le mode développeur par défaut, ce qui ne devrait jamais arriver sur un serveur de production.
@@ -90,7 +115,7 @@ Outil de débogage Tracy .[#toc-debugging-tool-tracy]
Pour faciliter le débogage, nous allons activer l'excellent outil [Tracy |tracy:]. En mode développeur, il visualise les erreurs et en mode production, il enregistre les erreurs dans le répertoire spécifié :
```php
-$configurator->enableTracy($appDir . '/log');
+$this->configurator->enableTracy($this->rootDir . '/log');
```
@@ -100,7 +125,7 @@ Fichiers temporaires .[#toc-temporary-files]
Nette utilise le cache pour le conteneur DI, RobotLoader, les modèles, etc. Il est donc nécessaire de définir le chemin d'accès au répertoire où le cache sera stocké :
```php
-$configurator->setTempDirectory($appDir . '/temp');
+$this->configurator->setTempDirectory($this->rootDir . '/temp');
```
Sous Linux ou macOS, définissez les [droits d'écriture |nette:troubleshooting#Setting directory permissions] pour les répertoires `log/` et `temp/`.
@@ -112,7 +137,7 @@ RobotLoader .[#toc-robotloader]
En général, nous voulons charger automatiquement les classes à l'aide de [RobotLoader |robot-loader:], nous devons donc le lancer et le laisser charger les classes du répertoire où se trouve `Bootstrap.php` (c'est-à-dire `__DIR__`) et de tous ses sous-répertoires :
```php
-$configurator->createRobotLoader()
+$this->configurator->createRobotLoader()
->addDirectory(__DIR__)
->register();
```
@@ -126,7 +151,7 @@ Fuseau horaire .[#toc-timezone]
Le configurateur vous permet de spécifier un fuseau horaire pour votre application.
```php
-$configurator->setTimeZone('Europe/Prague');
+$this->configurator->setTimeZone('Europe/Prague');
```
@@ -143,16 +168,17 @@ En mode développement, le conteneur est automatiquement mis à jour chaque fois
Les fichiers de configuration sont chargés à l'aide de `addConfig()`:
```php
-$configurator->addConfig($appDir . '/config/common.neon');
+$this->configurator->addConfig($this->rootDir . '/config/common.neon');
```
La méthode `addConfig()` peut être appelée plusieurs fois pour ajouter plusieurs fichiers.
```php
-$configurator->addConfig($appDir . '/config/common.neon');
-$configurator->addConfig($appDir . '/config/services.neon');
+$configDir = $this->rootDir . '/config';
+$this->configurator->addConfig($configDir . '/common.neon');
+$this->configurator->addConfig($configDir . '/services.neon');
if (PHP_SAPI === 'cli') {
- $configurator->addConfig($appDir . '/config/cli.php');
+ $this->configurator->addConfig($configDir . '/cli.php');
}
```
@@ -169,7 +195,7 @@ Paramètres statiques .[#toc-static-parameters]
Les paramètres utilisés dans les fichiers de configuration peuvent être définis [dans la section `parameters` |dependency-injection:configuration#parameters] et également transmis (ou écrasés) par la méthode `addStaticParameters()` (qui a un alias `addParameters()`). Il est important que les différentes valeurs des paramètres entraînent la génération de conteneurs DI supplémentaires, c'est-à-dire de classes supplémentaires.
```php
-$configurator->addStaticParameters([
+$this->configurator->addStaticParameters([
'projectId' => 23,
]);
```
@@ -183,7 +209,7 @@ Paramètres dynamiques .[#toc-dynamic-parameters]
Nous pouvons également ajouter des paramètres dynamiques au conteneur, leurs différentes valeurs, contrairement aux paramètres statiques, ne provoqueront pas la génération de nouveaux conteneurs DI.
```php
-$configurator->addDynamicParameters([
+$this->configurator->addDynamicParameters([
'remoteIp' => $_SERVER['REMOTE_ADDR'],
]);
```
@@ -191,7 +217,7 @@ $configurator->addDynamicParameters([
Les variables d'environnement peuvent être facilement mises à disposition à l'aide de paramètres dynamiques. Nous pouvons y accéder via `%env.variable%` dans les fichiers de configuration.
```php
-$configurator->addDynamicParameters([
+$this->configurator->addDynamicParameters([
'env' => getenv(),
]);
```
@@ -206,6 +232,7 @@ Vous pouvez utiliser les paramètres statiques suivants dans les fichiers de con
- `%wwwDir%` est le chemin absolu vers le répertoire contenant le fichier d'entrée `index.php`
- `%tempDir%` est le chemin absolu vers le répertoire des fichiers temporaires
- `%vendorDir%` est le chemin absolu vers le répertoire où Composer installe les bibliothèques
+- `%rootDir%` est le chemin absolu vers le répertoire racine du projet
- `%debugMode%` indique si l'application est en mode débogage
- `%consoleMode%` indique si la demande provient de la ligne de commande
@@ -225,7 +252,7 @@ services:
Créez une nouvelle instance et insérez-la dans bootstrap :
```php
-$configurator->addServices([
+$this->configurator->addServices([
'myservice' => new App\Model\MyCustomService('foobar'),
]);
```
@@ -234,13 +261,21 @@ $configurator->addServices([
Différents environnements .[#toc-different-environments]
========================================================
-N'hésitez pas à personnaliser la classe `Bootstrap` en fonction de vos besoins. Vous pouvez ajouter des paramètres à la méthode `boot()` pour différencier les projets Web, ou ajouter d'autres méthodes, comme `bootForTests()`, qui initialise l'environnement pour les tests unitaires, `bootForCli()` pour les scripts appelés depuis la ligne de commande, etc.
+N'hésitez pas à personnaliser la classe `Bootstrap` en fonction de vos besoins. Vous pouvez ajouter des paramètres à la méthode `bootWebApplication()` pour différencier les projets web. Vous pouvez également ajouter d'autres méthodes, telles que `bootTestEnvironment()` pour initialiser l'environnement des tests unitaires, `bootConsoleApplication()` pour les scripts appelés à partir de la ligne de commande, etc.
```php
-public static function bootForTests(): Configurator
+public function bootTestEnvironment(): Nette\DI\Container
+{
+ Tester\Environment::setup(); // Initialisation du testeur Nette
+ $this->setupContainer();
+ return $this->configurator->createContainer();
+}
+
+public function bootConsoleApplication(): Nette\DI\Container
{
- $configurator = self::boot();
- Tester\Environment::setup(); // Initialisation du testeur de nappe
- return $configurator;
+ $this->configurator->setDebugMode(false);
+ $this->initializeEnvironment();
+ $this->setupContainer();
+ return $this->configurator->createContainer();
}
```
diff --git a/application/fr/components.texy b/application/fr/components.texy
index 0b261bac97..a9472f1af9 100644
--- a/application/fr/components.texy
+++ b/application/fr/components.texy
@@ -230,6 +230,28 @@ Dans le modèle, ces messages sont disponibles dans la variable `$flashes` sous
```
+Redirection après un signal .[#toc-redirection-after-a-signal]
+==============================================================
+
+Le traitement d'un signal de composant est souvent suivi d'une redirection. Cette situation est similaire à celle des formulaires : après avoir soumis un formulaire, nous redirigeons également les données pour éviter qu'elles ne soient soumises à nouveau lorsque la page est rafraîchie dans le navigateur.
+
+```php
+$this->redirect('this') // redirects to the current presenter and action
+```
+
+Étant donné qu'un composant est un élément réutilisable et qu'il ne doit généralement pas dépendre directement de présentateurs spécifiques, les méthodes `redirect()` et `link()` interprètent automatiquement le paramètre comme un signal de composant :
+
+```php
+$this->redirect('click') // redirects to the 'click' signal of the same component
+```
+
+Si vous devez rediriger vers un autre présentateur ou une autre action, vous pouvez le faire par l'intermédiaire du présentateur :
+
+```php
+$this->getPresenter()->redirect('Product:show'); // redirects to a different presenter/action
+```
+
+
Paramètres persistants .[#toc-persistent-parameters]
====================================================
diff --git a/application/fr/configuration.texy b/application/fr/configuration.texy
index 4398c0e7fe..d180bce83a 100644
--- a/application/fr/configuration.texy
+++ b/application/fr/configuration.texy
@@ -90,10 +90,13 @@ latte:
strictTypes: ... # (bool) vaut false par défaut
# active le [mode strict de l'analyseur |latte:develop#strict mode]
- strictParsing : ... # (bool) la valeur par défaut est false
+ strictParsing: ... # (bool) la valeur par défaut est false
# permet de [vérifier le code généré |latte:develop#Checking Generated Code]
- phpLinter : ... # (string) la valeur par défaut est null
+ phpLinter: ... # (string) la valeur par défaut est null
+
+ # définit la locale
+ locale: cs_CZ # (string) la valeur par défaut est null
# classe de $this->template
templateClass: App\MyTemplateClass # Valeur par défaut: Nette\Bridges\ApplicationLatte\DefaultTemplate
@@ -104,7 +107,7 @@ Si vous utilisez la version 3 de Latte, vous pouvez ajouter une nouvelle [extens
```neon
latte:
extensions:
- - Latte\Essential\TranslatorExtension
+ - Latte\Essential\TranslatorExtension(@Nette\Localization\Translator)
```
/--comment
diff --git a/application/fr/how-it-works.texy b/application/fr/how-it-works.texy
index 9c4358110a..57aeb786a4 100644
--- a/application/fr/how-it-works.texy
+++ b/application/fr/how-it-works.texy
@@ -22,13 +22,13 @@ La structure des répertoires ressemble à ceci :
/--pre
web-project/
├── app/ ← répertoire avec application
-│ ├── Presenters/ ← classes d'presenter
-│ │ ├── HomePresenter.php ← Home classe des présentateurs
-│ │ └── templates/ ← répertoire des modèles
-│ │ ├── @layout.latte ← modèle de disposition partagée
-│ │ └── Home/ ← Modèles pour le présentateur de la page d'accueil
-│ │ └── default.latte ← modèle pour l'action `default`
-│ ├── Router/ ← configuration des adresses URL
+│ ├── Core/ ← basic necessary classes
+│ │ └── RouterFactory.php ← configuration des adresses URL
+│ ├── UI/ ← presenters, templates & co.
+│ │ ├─── @layout.latte ← template of shared layout
+│ │ └── Home/ ← Home presenter directory
+│ │ ├── HomePresenter.php ← Classe Home Presenter
+│ │ └── default.latte ← template for action default
│ └── Bootstrap.php ← classe de démarrage Bootstrap
├── bin/ ← scripts pour la ligne de commande
├── config/ ← configuration files
@@ -91,7 +91,7 @@ Les applications écrites dans Nette sont divisées en plusieurs présentateurs
L'application commence par demander à ce qu'on appelle le routeur de décider lequel des présentateurs doit transmettre la demande actuelle pour traitement. Le routeur décide de la responsabilité qui lui incombe. Il examine l'URL d'entrée `https://example.com/product/123`, qui veut `show` un produit avec `id: 123` comme action. C'est une bonne habitude d'écrire une paire présentateur + action séparée par un deux-points comme `Product:show`.
-Le routeur transforme donc l'URL en une paire `Presenter:action` + paramètres, dans notre cas `Product:show` + `id: 123`. Vous pouvez voir à quoi ressemble un routeur dans le fichier `app/Router/RouterFactory.php` et nous le décrirons en détail dans le chapitre [Routage |Routing].
+Le routeur transforme donc l'URL en une paire `Presenter:action` + paramètres, dans notre cas `Product:show` + `id: 123`. Vous pouvez voir à quoi ressemble un routeur dans le fichier `app/Core/RouterFactory.php` et nous le décrirons en détail dans le chapitre [Routage |Routing].
Continuons. L'application connaît déjà le nom du présentateur et peut continuer. En créant un objet `ProductPresenter`, qui est le code du présentateur `Product`. Plus précisément, elle demande au conteneur DI de créer le présentateur, car la production d'objets est son travail.
@@ -121,12 +121,9 @@ Ainsi, la méthode `renderShow(123)` a été appelée, dont le code est un exemp
Ensuite, le présentateur renvoie la réponse. Cela peut être une page HTML, une image, un document XML, l'envoi d'un fichier depuis le disque, JSON ou la redirection vers une autre page. Il est important de noter que si nous ne disons pas explicitement comment répondre (ce qui est le cas de `ProductPresenter`), la réponse sera de rendre le modèle avec une page HTML. Pourquoi ? Eh bien, parce que dans 99% des cas, nous voulons dessiner un modèle, donc le présentateur prend ce comportement par défaut et veut nous faciliter le travail. C'est le point de vue de Nette.
-Nous n'avons même pas besoin d'indiquer quel modèle dessiner, il dérive le chemin vers celui-ci selon une logique simple. Dans le cas du présentateur `Product` et de l'action `show`, il essaie de voir si l'un de ces fichiers modèles existe par rapport au répertoire où se trouve la classe `ProductPresenter`:
+Il n'est même pas nécessaire de spécifier le modèle à rendre ; le framework déduira lui-même le chemin d'accès. Dans le cas de l'action `show`, il essaie simplement de charger le modèle `show.latte` dans le répertoire contenant la classe `ProductPresenter`. Il tente également de trouver la mise en page dans le fichier `@layout.latte` (plus d'informations sur la [recherche de modèles |templates#Template Lookup]).
-- `templates/Product/show.latte`
-- `templates/Product.show.latte`
-
-Il essaiera également de trouver la mise en page dans le fichier `@layout.latte`, puis il effectuera le rendu du modèle. La tâche du présentateur et de l'ensemble de l'application est maintenant terminée. Si le modèle n'existe pas, une page d'erreur 404 sera renvoyée. Vous pouvez en savoir plus sur les présentateurs sur la page [Présentateurs |Presenters].
+Ensuite, les modèles sont rendus. La tâche du présentateur et de l'ensemble de l'application est ainsi achevée et le travail est terminé. Si le modèle n'existait pas, une page d'erreur 404 serait renvoyée. Pour en savoir plus sur les présentateurs, consultez la page [Présentateurs |presenters].
[* request-flow.svg *]
@@ -137,7 +134,7 @@ Juste pour être sûr, essayons de récapituler l'ensemble du processus avec une
3) le routeur décode l'URL comme une paire `Home:default`
4) un objet `HomePresenter` est créé
5) la méthode `renderDefault()` est appelée (si elle existe)
-6) un modèle `templates/Home/default.latte` avec une mise en page `templates/@layout.latte` est rendu
+6) un modèle `default.latte` avec une mise en page `@layout.latte` est rendu
Vous avez peut-être rencontré beaucoup de nouveaux concepts maintenant, mais nous pensons qu'ils ont un sens. Créer des applications dans Nette est un jeu d'enfant.
diff --git a/application/fr/modules.texy b/application/fr/modules.texy
index 754e97b5ad..7734341840 100644
--- a/application/fr/modules.texy
+++ b/application/fr/modules.texy
@@ -2,29 +2,31 @@ Modules
*******
.[perex]
-Dans Nette, les modules représentent les unités logiques qui composent une application. Ils comprennent des présentateurs, des modèles, éventuellement aussi des composants et des classes de modèles.
+Les modules apportent de la clarté aux applications Nette en facilitant la division en unités logiques.
-Un répertoire pour les présentateurs et un autre pour les modèles ne seraient pas suffisants pour les projets réels. Avoir des dizaines de fichiers dans un seul dossier est pour le moins inorganisé. Comment s'en sortir ? Il suffit de les répartir en sous-répertoires sur le disque et en espaces de noms dans le code. Et c'est exactement ce que font les modules Nette.
-
-Oublions donc le dossier unique pour les présentateurs et les modèles et créons plutôt des modules, par exemple `Admin` et `Front`.
+À l'instar de l'organisation des fichiers en dossiers sur un disque dur, Nette permet de diviser les présentateurs, les modèles et les autres classes auxiliaires en modules. Comment cela fonctionne-t-il en pratique ? Simplement en incorporant de nouveaux sous-répertoires dans la structure. Voici un exemple de structure avec deux modules, Front et Admin :
/--pre
-app/
-├── Presenters/
-├── Modules/ ← répertoire avec les modules
-│ ├── Admin/ ← module Admin
-│ │ ├── Presenters/ ← ses présentateurs
-│ │ │ ├── DashboardPresenter.php
-│ │ │ └── templates/
-│ └── Front/ ← module Front
-│ └── Presenters/ ← ses présentateurs
-│ └── ...
+app/
+├── UI/
+│ ├── Admin/ ← Admin module
+│ │ ├── @layout.latte
+│ │ ├── Dashboard/
+│ │ │ ├── DashboardPresenter.php
+│ │ │ └── default.latte
+│ │ └── ...
+│ ├── Front/ ← Front module
+│ │ ├── @layout.latte
+│ │ ├── Home/
+│ │ │ ├── HomePresenter.php
+│ │ │ └── default.latte
+│ │ └── ...
\--
-Cette structure de répertoire sera reflétée par les espaces de noms des classes, ainsi par exemple `DashboardPresenter` sera dans l'espace de noms `App\Modules\Admin\Presenters`:
+Cette structure de répertoires se reflète dans les espaces de noms des classes. Ainsi, par exemple, `DashboardPresenter` est situé dans l'espace de noms `App\UI\Admin\Dashboard`:
```php
-namespace App\Modules\Admin\Presenters;
+namespace App\UI\Admin\Dashboard;
class DashboardPresenter extends Nette\Application\UI\Presenter
{
@@ -32,35 +34,49 @@ class DashboardPresenter extends Nette\Application\UI\Presenter
}
```
-Le présentateur `Dashboard` dans le module `Admin` est référencé dans l'application en utilisant la notation deux points comme `Admin:Dashboard`, et son action `default` comme `Admin:Dashboard:default`.
-Et comment Nette proper sait-elle que `Admin:Dashboard` représente la classe `App\Modules\Admin\Presenters\DashboardPresenter`? Cela est déterminé par le [mappage |#mapping] dans la configuration.
-Ainsi, la structure donnée n'est pas figée et vous pouvez la modifier en fonction de vos besoins.
+Dans l'application, nous faisons référence au présentateur `Dashboard` dans le module `Admin` en utilisant la notation des deux points comme `Admin:Dashboard`. Pour son action `default`, nous l'appelons `Admin:Dashboard:default`.
-Les modules peuvent bien sûr contenir tous les éléments autres que les présentateurs et les modèles, tels que les composants, les classes de modèles, etc.
+La structure présentée n'est pas rigide ; vous pouvez [l'adapter entièrement à vos besoins |#mapping] dans la configuration. .[tip]
+
+Les modules peuvent inclure tous les autres fichiers, tels que les composants et les classes auxiliaires, en plus des présentateurs et des modèles. Si vous vous demandez où placer ces derniers, envisagez d'utiliser un dossier `Accessory`:
+
+/--pre
+app/
+├── UI/
+│ ├── Admin/
+│ │ ├── Accessory/
+│ │ │ ├── FormFactory.php
+│ │ │ └── AdminLayout.php
+│ │ ├── Dashboard/
+│ │ └── ...
+\--
Modules imbriqués .[#toc-nested-modules]
----------------------------------------
-Les modules ne doivent pas uniquement former une structure plate, vous pouvez également créer des sous-modules, par exemple :
+Les modules peuvent avoir plusieurs niveaux d'imbrication, comme la structure d'un répertoire sur un disque :
/--pre
-app/
-├── Modules/ ← répertoire avec les modules
-│ ├── Blog/ ← module Blog
-│ │ ├── Admin/ ← sous-module Admin
-│ │ │ ├── Presenters/
+app/
+├── UI/
+│ ├── Blog/ ← Blog module
+│ │ ├── Admin/ ← Admin submodule
+│ │ │ ├── Dashboard/
+│ │ │ └── ...
+│ │ ├── Front/ ← Front submodule
+│ │ │ ├── @layout.latte
+│ │ │ ├── Home/
│ │ │ └── ...
-│ │ └── Front/ ← sous-module Front
-│ │ ├── Presenters/
-│ │ └── ...
-│ ├── Forum/ ← module Forum
+│ ├── Forum/ ← Forum module
│ │ └── ...
\--
-Ainsi, le module `Blog` est divisé en sous-modules `Admin` et `Front`. Là encore, cela se reflétera dans les espaces de noms, qui seront `App\Modules\Blog\Admin\Presenters` etc. Le présentateur `Dashboard` à l'intérieur du sous-module est désigné par `Blog:Admin:Dashboard`.
+Le module `Blog` est divisé en sous-modules `Admin` et `Front`. Cela se reflète également dans les espaces de noms, qui apparaissent alors comme `App\UI\Blog\Admin` et similaires. Pour désigner le présentateur `Dashboard` au sein du sous-module `Admin`, nous l'appelons `Blog:Admin:Dashboard`.
-L'imbrication peut aller aussi loin que vous le souhaitez, de sorte que des sous-sous-modules peuvent être créés.
+L'imbrication peut être aussi poussée que nécessaire, ce qui permet de créer des sous-sous-modules.
+
+Par exemple, si dans l'administration vous avez de nombreux présentateurs liés à la gestion des commandes, tels que `OrderDetail`, `OrderEdit`, `OrderDispatch`, etc., vous pouvez créer un module `Order` dans lequel les présentateurs tels que `Detail`, `Edit`, `Dispatch`, et d'autres seront organisés.
Création de liens .[#toc-creating-links]
@@ -102,46 +118,66 @@ Voir le [chapitre sur le routage |routing#Modules].
Cartographie .[#toc-mapping]
----------------------------
-Définit les règles par lesquelles le nom de la classe est dérivé du nom du présentateur. On les inscrit dans la [configuration] sous la clé `application › mapping`.
+Le mappage définit les règles permettant de dériver le nom de la classe à partir du nom du présentateur. Ces règles sont spécifiées dans la [configuration |configuration] sous la clé `application › mapping`.
+
+Les structures de répertoire mentionnées plus haut sur cette page sont basées sur la correspondance suivante :
+
+```neon
+application:
+ mapping: App\UI\*\**Presenter
+```
-Commençons par un exemple qui n'utilise pas de modules. Nous voulons simplement que les classes du présentateur aient l'espace de nom `App\Presenters`. Cela signifie qu'un présentateur tel que `Home` doit correspondre à la classe `App\Presenters\HomePresenter`. Ceci peut être réalisé par la configuration suivante :
+Comment fonctionne la cartographie ? Pour mieux comprendre, imaginons d'abord une application sans modules. Nous voulons que les classes de présentateurs relèvent de l'espace de noms `App\UI`, de sorte que le présentateur `Home` soit associé à la classe `App\UI\HomePresenter`. Cette configuration permet d'atteindre cet objectif :
```neon
application:
- mapping: App\Presenters\*Presenter
+ mapping: App\UI\*Presenter
```
-Le nom du présentateur est remplacé par l'astérisque dans le masque de classe et le résultat est le nom de la classe. Facile !
+Ce mappage fonctionne en remplaçant l'astérisque du masque `App\UI\*Presenter` par le nom du présentateur `Home`, ce qui donne le nom de classe final `App\UI\HomePresenter`. C'est simple !
+
+Cependant, comme vous pouvez le voir dans les exemples de ce chapitre et d'autres chapitres, nous plaçons les classes de présentateurs dans des sous-répertoires éponymes, par exemple, le présentateur `Home` est associé à la classe `App\UI\Home\HomePresenter`. Pour ce faire, il suffit de doubler l'astérisque (Nette Application 3.2 requise) :
+
+```neon
+application:
+ mapping: App\UI\**Presenter
+```
-Si nous divisons les présentateurs en modules, nous pouvons avoir notre propre mappage pour chaque module :
+Passons maintenant au mappage des présentateurs dans les modules. Nous pouvons définir des correspondances spécifiques pour chaque module :
```neon
application:
mapping:
- Front: App\Modules\Front\Presenters\*Presenter
- Admin: App\Modules\Admin\Presenters\*Presenter
+ Front: App\UI\Front\**Presenter
+ Admin: App\UI\Admin\**Presenter
Api: App\Api\*Presenter
```
-Maintenant, le présentateur `Front:Home` correspond à la classe `App\Modules\Front\Presenters\HomePresenter` et le présentateur `Admin:Dashboard` à la classe `App\Modules\Admin\Presenters\DashboardPresenter`.
+Selon cette configuration, le présentateur `Front:Home` correspond à la classe `App\UI\Front\Home\HomePresenter`, tandis que le présentateur `Api:OAuth` correspond à la classe `App\Api\OAuthPresenter`.
-Il est plus pratique de créer une règle générale (étoile) pour remplacer les deux premières. L'astérisque supplémentaire sera ajouté au masque de classe uniquement pour le module :
+Étant donné que les modules `Front` et `Admin` ont une approche de mappage similaire et qu'il est probable qu'il y ait d'autres modules de ce type, il est possible de créer une règle générale qui les remplace. Un nouvel astérisque pour le module est ajouté au masque de classe :
```neon
application:
mapping:
- *: App\Modules\*\Presenters\*Presenter
+ *: App\UI\*\**Presenter
Api: App\Api\*Presenter
```
-Mais qu'en est-il si nous utilisons des modules imbriqués et que nous avons un présentateur `Admin:User:Edit`? Dans ce cas, le segment avec un astérisque représentant le module pour chaque niveau est simplement répété et le résultat est la classe `App\Modules\Admin\User\Presenters\EditPresenter`.
+Pour les modules imbriqués à plusieurs niveaux, tels que le présentateur `Admin:User:Edit`, le segment astérisque se répète pour chaque niveau, ce qui donne la classe `App\UI\Admin\User\Edit\EditPresenter`.
-Une notation alternative consiste à utiliser un tableau composé de trois segments au lieu d'une chaîne de caractères. Cette notation est équivalente à la précédente :
+Une autre notation consiste à utiliser un tableau composé de trois segments au lieu d'une chaîne. Cette notation est équivalente à la précédente :
```neon
application:
mapping:
- *: [App\Modules, *, Presenters\*Presenter]
+ *: [App\UI, *, **Presenter]
+ Api: [App\Api, '', *Presenter]
```
-La valeur par défaut est `*Module\*Presenter`.
+Si nous n'avons qu'une seule règle dans la configuration, la règle générale, nous pouvons l'écrire brièvement :
+
+```neon
+application:
+ mapping: App\UI\*\**Presenter
+```
diff --git a/application/fr/presenters.texy b/application/fr/presenters.texy
index bf1050cfa2..538f20ab44 100644
--- a/application/fr/presenters.texy
+++ b/application/fr/presenters.texy
@@ -60,7 +60,7 @@ Similaire à la méthode `render()`. Alors que `render()` a pour but
Il est important que `action()` soit appelé avant `render()`afin qu'à l'intérieur de celui-ci, nous puissions éventuellement modifier le cours suivant du cycle de vie, c'est-à-dire changer le modèle qui sera rendu et également la méthode `render()` qui sera appelée, en utilisant `setView('otherView')`.
-Les paramètres de la requête sont transmis à la méthode. Il est possible et recommandé de spécifier des types pour les paramètres, par exemple `actionShow(int $id, string $slug = null)` - si le paramètre `id` est manquant ou s'il ne s'agit pas d'un nombre entier, le présentateur renvoie l'[erreur 404 |#Error 404 etc.] et met fin à l'opération.
+Les paramètres de la requête sont transmis à la méthode. Il est possible et recommandé de spécifier des types pour les paramètres, par exemple `actionShow(int $id, ?string $slug = null)` - si le paramètre `id` est manquant ou s'il ne s'agit pas d'un nombre entier, le présentateur renvoie l'[erreur 404 |#Error 404 etc.] et met fin à l'opération.
`handle(args...)` .{toc: handle()}
@@ -205,7 +205,7 @@ Dans le modèle, ces messages sont disponibles dans la variable `$flashes` en ta
Erreur 404 etc. .[#toc-error-404-etc]
=====================================
-Lorsque nous ne pouvons pas répondre à la demande, par exemple parce que l'article que nous voulons afficher n'existe pas dans la base de données, nous envoyons l'erreur 404 en utilisant la méthode `error(string $message = null, int $httpCode = 404)`, qui représente l'erreur HTTP 404 :
+Lorsque nous ne pouvons pas répondre à la demande, par exemple parce que l'article que nous voulons afficher n'existe pas dans la base de données, nous envoyons l'erreur 404 en utilisant la méthode `error(?string $message = null, int $httpCode = 404)`, qui représente l'erreur HTTP 404 :
```php
public function renderShow(int $id): void
@@ -384,7 +384,7 @@ La redirection ne se produit pas avec une demande AJAX ou POST, car elle entraî
Vous pouvez également invoquer la canonisation manuellement à l'aide de la méthode `canonicalize()`, qui, comme la méthode `link()`, reçoit le présentateur, les actions et les paramètres comme arguments. Elle crée un lien et le compare à l'URL actuelle. Si elle est différente, elle redirige vers le lien généré.
```php
-public function actionShow(int $id, string $slug = null): void
+public function actionShow(int $id, ?string $slug = null): void
{
$realSlug = $this->facade->getSlugForId($id);
// redirige si $slug est différent de $realSlug
@@ -452,17 +452,6 @@ Restriction d'accès à l'aide de `#[Requires]` .[#toc-access-restriction-using-
L'attribut `#[Requires]` fournit des options avancées pour restreindre l'accès aux présentateurs et à leurs méthodes. Il peut être utilisé pour spécifier des méthodes HTTP, exiger des requêtes AJAX, limiter l'accès à la même origine et restreindre l'accès à la transmission uniquement. L'attribut peut être appliqué aux classes de présentateurs ainsi qu'aux méthodes individuelles telles que `action()`, `render()`, `handle()`, et `createComponent()`.
-Voici un exemple d'utilisation pour restreindre l'accès à la seule méthode HTTP `POST`:
-
-```php
-use Nette\Application\Attributes\Requires;
-
-#[Requires(methods: 'POST')]
-class MyPresenter extends Nette\Application\UI\Presenter
-{
-}
-```
-
Vous pouvez spécifier ces restrictions :
- sur les méthodes HTTP : `#[Requires(methods: ['GET', 'POST'])]`
- nécessitant une requête AJAX : `#[Requires(ajax: true)]`
@@ -470,22 +459,7 @@ Vous pouvez spécifier ces restrictions :
- accès uniquement par le biais d'une redirection : `#[Requires(forward: true)]`
- restrictions sur des actions spécifiques : `#[Requires(actions: 'default')]`
-Les conditions peuvent être combinées en énumérant plusieurs attributs ou en les réunissant en un seul :
-
-```php
-#[Requires(methods: 'POST', ajax: true)]
-public function actionDelete(int $id)
-{
-}
-
-// or
-
-#[Requires(methods: 'POST')]
-#[Requires(ajax: true)]
-public function actionDelete(int $id)
-{
-}
-```
+Pour plus de détails, voir [Comment utiliser l'attribut Requires |best-practices:attribute-requires].
Vérification de la méthode HTTP .[#toc-http-method-check]
diff --git a/application/fr/routing.texy b/application/fr/routing.texy
index 9fe5d5e4a6..29541d7fb9 100644
--- a/application/fr/routing.texy
+++ b/application/fr/routing.texy
@@ -216,7 +216,7 @@ $router->addRoute('//www.%sld%.%tld%/%basePath%//addRoute('/[/]', [
@@ -225,7 +225,7 @@ $router->addRoute('/[/]', [
]);
```
-Ou nous pouvons utiliser cette forme, remarquez la réécriture de l'expression régulière de validation :
+Pour une spécification plus détaillée, une forme encore plus étendue peut être utilisée, où en plus des valeurs par défaut, d'autres propriétés de paramètres peuvent être définies, telles qu'une expression régulière de validation (voir le paramètre `id` ) :
```php
use Nette\Routing\Route;
@@ -243,7 +243,7 @@ $router->addRoute('/[/]', [
]);
```
-Ces formats plus bavards sont utiles pour ajouter d'autres métadonnées.
+Il est important de noter que si les paramètres définis dans le tableau ne sont pas inclus dans le masque de chemin, leurs valeurs ne peuvent pas être modifiées, même en utilisant des paramètres de requête spécifiés après un point d'interrogation dans l'URL.
Filtres et traductions .[#toc-filters-and-translations]
@@ -477,10 +477,10 @@ $router->addRoute('index.html \.html?|\.php|>', /* ... */);
Intégration .[#toc-integration]
===============================
-Afin de connecter notre routeur à l'application, nous devons en informer le conteneur DI. Le moyen le plus simple est de préparer la fabrique qui construira l'objet routeur et de dire à la configuration du conteneur de l'utiliser. Disons que nous écrivons une méthode dans ce but `App\Router\RouterFactory::createRouter()`:
+Afin de connecter notre routeur à l'application, nous devons en informer le conteneur DI. Le moyen le plus simple est de préparer la fabrique qui construira l'objet routeur et de dire à la configuration du conteneur de l'utiliser. Disons que nous écrivons une méthode dans ce but `App\Core\RouterFactory::createRouter()`:
```php
-namespace App\Router;
+namespace App\Core;
use Nette\Application\Routers\RouteList;
@@ -499,7 +499,7 @@ Puis nous écrivons dans la [configuration |dependency-injection:services]:
```neon
services:
- - App\Router\RouterFactory::createRouter
+ - App\Core\RouterFactory::createRouter
```
Toutes les dépendances, telles qu'une connexion à une base de données, etc., sont transmises à la méthode factory en tant que paramètres en utilisant le [câblage automatique |dependency-injection:autowiring]:
@@ -663,7 +663,7 @@ Par utilisation séparée, nous entendons l'utilisation des capacités du routeu
Donc encore une fois nous allons créer une méthode qui va construire un routeur, par exemple :
```php
-namespace App\Router;
+namespace App\Core;
use Nette\Routing\RouteList;
@@ -694,7 +694,7 @@ $httpRequest = $container->getByType(Nette\Http\IRequest::class);
Ou bien nous créerons directement des objets :
```php
-$router = App\Router\RouterFactory::createRouter();
+$router = App\Core\RouterFactory::createRouter();
$httpRequest = (new Nette\Http\RequestFactory)->fromGlobals();
```
diff --git a/application/fr/templates.texy b/application/fr/templates.texy
index 8ecd733495..494ea2da09 100644
--- a/application/fr/templates.texy
+++ b/application/fr/templates.texy
@@ -34,35 +34,81 @@ Et ceci pourrait être le modèle d'action :
Il définit le bloc `content`, qui est inséré à la place de `{include content}` dans la mise en page, et redéfinit également le bloc `title`, qui écrase `{block title}` dans la mise en page. Essayez d'imaginer le résultat.
-Recherche de modèles .[#toc-search-for-templates]
--------------------------------------------------
+Recherche de modèles .[#toc-template-lookup]
+--------------------------------------------
-Le chemin vers les modèles est déduit selon une logique simple. Il essaie de voir si l'un de ces fichiers modèles existe par rapport au répertoire où se trouve la classe du présentateur, où `` est le nom du présentateur actuel et `` est le nom de l'action en cours :
+Dans les présentateurs, vous n'avez pas besoin de spécifier quel modèle doit être rendu ; le cadre détermine automatiquement le chemin, ce qui facilite le codage.
-- `templates//.latte`
-- `templates/