Skip to content

Commit

Permalink
dirname2
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed Apr 18, 2024
1 parent 1dfe4e9 commit 42c11be
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 89 deletions.
113 changes: 71 additions & 42 deletions application/cs/modules.texy
Original file line number Diff line number Diff line change
Expand Up @@ -2,65 +2,81 @@ 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
<b>app/</b>
├── <del>Presenters/</del>
├── <b>Modules/</b> ← adresář s moduly
app/
├── UI/
│ ├── <b>Admin/</b> ← modul Admin
│ │ ├── <b>Presenters/</b> ← jeho presentery
│ │ │ ├── <b>DashboardPresenter.php</b>
│ │ │ └── <b>templates/</b>
│ └── <b>Front/</b> ← modul Front
│ └── <b>Presenters/</b> ← jeho presentery
│ └── ...
│ │ ├── @layout.latte
│ │ ├── Dashboard/
│ │ │ ├── DashboardPresenter.php
│ │ │ └── default.latte
│ │ └── ...
│ ├── <b>Front/</b> ← 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
{
// ...
}
```

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/
│ │ ├── <b>Accessory/</b>
│ │ │ ├── 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
<b>app/</b>
├── <b>Modules/</b> ← adresář s moduly
app/
├── UI/
│ ├── <b>Blog/</b> ← modul Blog
│ │ ├── <b>Admin/</b> ← submodul Admin
│ │ │ ├── <b>Presenters/</b>
│ │ │ ├── Dashboard/
│ │ │ └── ...
│ │ ├── <b>Front/</b> ← submodul Front
│ │ │ ├── @layout.latte
│ │ │ ├── Home/
│ │ │ └── ...
│ │ └── <b>Front/</b> ← submodul Front
│ │ ├── <b>Presenters/</b>
│ │ └── ...
│ ├── <b>Forum/</b> ← 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ů
Expand Down Expand Up @@ -102,46 +118,59 @@ 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`.

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í:
Všechny příklady v této kapitole vycházejí z následujícího mapování:

```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é!
Pro lepší pochopení si nejprve představíme 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í:

Pokud presentery členíme do modulů, můžeme pro každý modul mít vlastní mapování:
```neon
application:
mapping: App\UI\*Presenter
```

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
```

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`.
123 changes: 76 additions & 47 deletions application/en/modules.texy
Original file line number Diff line number Diff line change
Expand Up @@ -2,65 +2,81 @@ 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
<b>app/</b>
├── <del>Presenters/</del>
├── <b>Modules/</b> ← directory with modules
│ ├── <b>Admin/</b> ← module Admin
│ │ ├── <b>Presenters/</b> ← its presenters
│ │ │ ├── <b>DashboardPresenter.php</b>
│ │ │ └── <b>templates/</b>
│ └── <b>Front/</b> ← module Front
│ └── <b>Presenters/</b> ← its presenters
│ └── ...
app/
├── UI/
│ ├── <b>Admin/</b> ← Admin module
│ │ ├── @layout.latte
│ │ ├── Dashboard/
│ │ │ ├── DashboardPresenter.php
│ │ │ └── default.latte
│ │ └── ...
│ ├── <b>Front/</b> ← 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
{
// ...
}
```

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/
│ │ ├── <b>Accessory/</b>
│ │ │ ├── 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
<b>app/</b>
├── <b>Modules/</b> ← directory with modules
│ ├── <b>Blog/</b> ← module Blog
│ │ ├── <b>Admin/</b> ← submodule Admin
│ │ │ ├── <b>Presenters/</b>
app/
├── UI/
│ ├── <b>Blog/</b> ← Blog module
│ │ ├── <b>Admin/</b> ← Admin submodule
│ │ │ ├── Dashboard/
│ │ │ └── ...
│ │ ├── <b>Front/</b> ← Front submodule
│ │ │ ├── @layout.latte
│ │ │ ├── Home/
│ │ │ └── ...
│ │ └── <b>Front/</b> ← submodule Front
│ │ ├── <b>Presenters/</b>
│ │ └── ...
│ ├── <b>Forum/</b> ← module Forum
│ ├── <b>Forum/</b> ← 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
Expand Down Expand Up @@ -102,46 +118,59 @@ 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`.

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:
All examples in this chapter are based on the following mapping 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!
For better understanding, let's first consider an application without modules. We want presenter classes to fall under the namespace `App\UI`. To map the `Home` presenter to the class `App\UI\HomePresenter`, we achieve this with the following configuration:

If we divide presenters into modules, we can have our own mapping for each module:
```neon
application:
mapping: App\UI\*Presenter
```

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
```

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`.

0 comments on commit 42c11be

Please sign in to comment.