-
-
Notifications
You must be signed in to change notification settings - Fork 277
Expand file tree
/
Copy pathhow-it-works.texy
More file actions
200 lines (127 loc) · 16.8 KB
/
how-it-works.texy
File metadata and controls
200 lines (127 loc) · 16.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
¿Cómo funcionan las aplicaciones?
*********************************
<div class=perex>
Está leyendo el documento fundamental de la documentación de Nette. Aprenderá todo el principio de funcionamiento de las aplicaciones web. De la A a la Z, desde el momento del nacimiento hasta el último suspiro del script PHP. Después de leerlo, sabrá:
- cómo funciona todo
- qué son Bootstrap, Presenter y el contenedor DI
- cómo es la estructura de directorios
</div>
Estructura de directorios
=========================
Abra el ejemplo del esqueleto de una aplicación web llamado [WebProject|https://github.com/nette/web-project] y mientras lee, puede mirar los archivos de los que se habla.
La estructura de directorios tiene este aspecto:
/--pre
<b>web-project/</b>
├── <b>app/</b> ← directorio con la aplicación
│ ├── <b>Core/</b> ← clases básicas necesarias para el funcionamiento
│ │ └── <b>RouterFactory.php</b> ← configuración de direcciones URL
│ ├── <b>Presentation/</b> ← presenters, plantillas, etc.
│ │ ├── <b>@layout.latte</b> ← plantilla de layout
│ │ └── <b>Home/</b> ← directorio del presenter Home
│ │ ├── <b>HomePresenter.php</b> ← clase del presenter Home
│ │ └── <b>default.latte</b> ← plantilla de la acción default
│ └── <b>Bootstrap.php</b> ← clase de arranque Bootstrap
├── <b>assets/</b> ← recursos (SCSS, TypeScript, imágenes de origen).
├── <b>bin/</b> ← scripts ejecutados desde la línea de comandos
├── <b>config/</b> ← archivos de configuración
│ ├── <b>common.neon</b>
│ └── <b>services.neon</b>
├── <b>log/</b> ← errores registrados
├── <b>temp/</b> ← archivos temporales, caché, etc.
├── <b>vendor/</b> ← librerías instaladas por Composer
│ ├── ...
│ └── <b>autoload.php</b> ← autoloading de todos los paquetes instalados
├── <b>www/</b> ← directorio público o document-root del proyecto
│ ├── <b>assets/</b> ← archivos estáticos compilados (CSS, JS, imágenes, ...)
│ ├── <b>.htaccess</b> ← reglas mod_rewrite
│ └── <b>index.php</b> ← archivo inicial con el que se inicia la aplicación
└── <b>.htaccess</b> ← prohíbe el acceso a todos los directorios excepto www
\--
Puede cambiar la estructura de directorios como desee, renombrar o mover carpetas, es completamente flexible. Nette, además, dispone de una autodetección inteligente y reconoce automáticamente la ubicación de la aplicación, incluida su base de URL.
En aplicaciones un poco más grandes, podemos [dividir las carpetas con presenters y plantillas en subdirectorios |directory-structure#Presenters y plantillas] y las clases en espacios de nombres, que llamamos módulos.
El directorio `www/` representa el llamado directorio público o document-root del proyecto. Puede renombrarlo sin necesidad de configurar nada más en el lado de la aplicación. Solo es necesario [configurar el hosting |nette:troubleshooting#Cómo cambiar o eliminar el directorio www de la URL] para que el document-root apunte a este directorio.
También puede descargar WebProject directamente incluyendo Nette usando [Composer |best-practices:composer]:
```shell
composer create-project nette/web-project
```
En Linux o macOS, establezca [permisos de escritura |nette:troubleshooting#Configuración de permisos de directorio] para los directorios `log/` y `temp/`.
La aplicación WebProject está lista para ejecutarse, no es necesario configurar absolutamente nada y puede mostrarla directamente en el navegador accediendo a la carpeta `www/`.
Petición HTTP
=============
Todo comienza en el momento en que el usuario abre una página en el navegador. Es decir, cuando el navegador llama al servidor con una petición HTTP. La petición apunta a un único archivo PHP, que se encuentra en el directorio público `www/`, y este es `index.php`. Supongamos que se trata de una petición a la dirección `https://example.com/product/123`. Gracias a la [configuración adecuada del servidor |nette:troubleshooting#Cómo configurar el servidor para URLs amigables], incluso esta URL se mapea al archivo `index.php` y este se ejecuta.
Su tarea es:
1) inicializar el entorno
2) obtener la fábrica
3) iniciar la aplicación Nette, que gestionará la petición
¿Qué fábrica? ¡No fabricamos tractores, sino páginas web! Espere, se explicará de inmediato.
Con las palabras "inicialización del entorno" nos referimos, por ejemplo, a que se activa [Tracy|tracy:], que es una herramienta increíble para el registro o la visualización de errores. En el servidor de producción, registra los errores, en el de desarrollo los muestra directamente. Por lo tanto, la inicialización también incluye la decisión de si el sitio web se ejecuta en modo de producción o de desarrollo. Para esto, Nette utiliza una [autodetección inteligente |bootstrapping#Modo de desarrollo vs producción]: si ejecuta el sitio web en localhost, se ejecuta en modo de desarrollo. Por lo tanto, no necesita configurar nada y la aplicación está lista tanto para el desarrollo como para la implementación en producción. Estos pasos se realizan y se describen detalladamente en el capítulo sobre la [clase Bootstrap|bootstrapping].
El tercer punto (sí, saltamos el segundo, pero volveremos a él) es el inicio de la aplicación. La gestión de las peticiones HTTP en Nette está a cargo de la clase `Nette\Application\Application` (en adelante `Application`), por lo que cuando decimos iniciar la aplicación, nos referimos específicamente a llamar al método con el nombre apropiado `run()` en el objeto de esta clase.
Nette es un mentor que le guía para escribir aplicaciones limpias según metodologías probadas. Y una de las más probadas se llama **inyección de dependencias**, abreviada como DI. En este momento no queremos cargarle con la explicación de DI, para eso está [un capítulo aparte|dependency-injection:introduction], lo importante es la consecuencia de que los objetos clave generalmente nos los creará una fábrica de objetos, que se llama **contenedor DI** (abreviado como DIC). Sí, esa es la fábrica de la que hablamos hace un momento. Y también nos fabricará el objeto `Application`, por eso necesitamos primero el contenedor. Lo obtenemos usando la clase `Configurator` y le pedimos que fabrique el objeto `Application`, llamamos al método `run()` en él y así se inicia la aplicación Nette. Exactamente esto sucede en el archivo [index.php |bootstrapping#index.php].
Nette Application
=================
La clase Application tiene una única tarea: responder a la petición HTTP.
Las aplicaciones escritas en Nette se dividen en muchos llamados presenters (en otros frameworks puede encontrar el término controller, es lo mismo), que son clases, cada una de las cuales representa alguna página específica del sitio web: p. ej., la página de inicio; un producto en una tienda electrónica; un formulario de inicio de sesión; un feed sitemap, etc. Una aplicación puede tener desde uno hasta miles de presenters.
Application comienza pidiendo al llamado router que decida a cuál de los presenters pasar la petición actual para su gestión. El router decide de quién es la responsabilidad. Mira la URL de entrada `https://example.com/product/123` y, basándose en cómo está configurado, decide que este es trabajo, por ejemplo, para el **presenter** `Product`, al que le pedirá como **acción** la visualización (`show`) del producto con `id: 123`. Es una buena costumbre escribir el par presenter + acción separado por dos puntos como `Product:show`.
Por lo tanto, el router transformó la URL en el par `Presenter:action` + parámetros, en nuestro caso `Product:show` + `id: 123`. Puede ver cómo es un router de este tipo en el archivo `app/Core/RouterFactory.php` y lo describimos detalladamente en el capítulo [Enrutamiento |Routing].
Sigamos. Application ya conoce el nombre del presenter y puede continuar. Creando el objeto de la clase `ProductPresenter`, que es el código del presenter `Product`. Más precisamente, pide al contenedor DI que fabrique el presenter, porque para eso está él.
El presenter puede verse así:
```php
class ProductPresenter extends Nette\Application\UI\Presenter
{
public function __construct(
private ProductRepository $repository,
) {
}
public function renderShow(int $id): void
{
// obtenemos datos del modelo y los pasamos a la plantilla
$this->template->product = $this->repository->getProduct($id);
}
}
```
La gestión de la petición la asume el presenter. Y la tarea es clara: realiza la acción `show` con `id: 123`. Lo que en el lenguaje de los presenters significa que se llama al método `renderShow()` y en el parámetro `$id` recibe `123`.
Un presenter puede manejar múltiples acciones, es decir, tener múltiples métodos `render<Action>()`. Pero recomendamos diseñar presenters con una o la menor cantidad posible de acciones.
Entonces, se llamó al método `renderShow(123)`, cuyo código es un ejemplo ficticio, pero puede ver en él cómo se pasan los datos a la plantilla, es decir, escribiendo en `$this->template`.
Posteriormente, el presenter devuelve una respuesta. Esta puede ser una página HTML, una imagen, un documento XML, el envío de un archivo desde el disco, JSON o incluso una redirección a otra página. Es importante que si no decimos explícitamente cómo debe responder (que es el caso de `ProductPresenter`), la respuesta será la renderización de una plantilla con una página HTML. ¿Por qué? Porque en el 99% de los casos queremos renderizar una plantilla, por lo que el presenter toma este comportamiento como predeterminado y quiere facilitarnos el trabajo. Ese es el propósito de Nette.
Ni siquiera tenemos que indicar qué plantilla renderizar, él mismo deduce la ruta hacia ella. En el caso de la acción `show`, simplemente intenta cargar la plantilla `show.latte` en el directorio con la clase `ProductPresenter`. También intentará localizar el layout en el archivo `@layout.latte` (más detalles sobre la [búsqueda de plantillas |templates#Búsqueda de plantillas]).
Y posteriormente renderiza las plantillas. Con esto, la tarea del presenter y de toda la aplicación está completa y la obra está terminada. Si la plantilla no existiera, se devolvería una página con error 404. Puede leer más sobre los presenters en la página [Presenters|presenters].
[* request-flow.svg *]
Por si acaso, intentemos recapitular todo el proceso con una URL ligeramente diferente:
1) La URL será `https://example.com`
2) Arrancamos la aplicación, se crea el contenedor y se ejecuta `Application::run()`
3) El router decodifica la URL como el par `Home:default`
4) Se crea el objeto de la clase `HomePresenter`
5) Se llama al método `renderDefault()` (si existe)
6) Se renderiza la plantilla, p. ej., `default.latte` con el layout, p. ej., `@layout.latte`
Puede que ahora se haya encontrado con muchos conceptos nuevos, pero creemos que tienen sentido. Crear aplicaciones en Nette es increíblemente fácil.
Plantillas
==========
Ya que hablamos de plantillas, en Nette se utiliza el sistema de plantillas [Latte |latte:]. Por eso esas extensiones `.latte` en las plantillas. Latte se utiliza, por un lado, porque es el sistema de plantillas más seguro para PHP y, al mismo tiempo, el sistema más intuitivo. No necesita aprender mucho nuevo, le basta con conocer PHP y algunas etiquetas. Todo lo aprenderá [en la documentación |templates].
En la plantilla, se [crean enlaces |creating-links] a otros presenters y acciones de esta manera:
```latte
<a n:href="Product:show $productId">detalle del producto</a>
```
Simplemente, en lugar de la URL real, escribe el par conocido `Presenter:action` e indica los parámetros necesarios. El truco está en `n:href`, que indica que este atributo será procesado por Nette. Y generará:
```latte
<a href="/product/456">detalle del producto</a>
```
La generación de URL está a cargo del router mencionado anteriormente. Es decir, los routers en Nette son excepcionales porque pueden realizar no solo transformaciones de URL al par presenter:action, sino también al revés, es decir, generar una URL a partir del nombre del presenter + acción + parámetros. Gracias a esto, en Nette puede cambiar completamente las formas de las URL en toda la aplicación terminada, sin cambiar un solo carácter en la plantilla o el presenter. Simplemente modificando el router. También gracias a esto funciona la llamada canonización, que es otra característica única de Nette que contribuye a un mejor SEO (optimización para motores de búsqueda) al evitar automáticamente la existencia de contenido duplicado en diferentes URL. Muchos programadores lo consideran asombroso.
Componentes interactivos
========================
Sobre los presenters debemos revelarle una cosa más: tienen incorporado un sistema de componentes. Algo similar pueden recordar los veteranos de Delphi o ASP.NET Web Forms, algo remotamente similar es la base de React o Vue.js. En el mundo de los frameworks PHP, es una característica absolutamente única.
Los componentes son unidades reutilizables independientes que insertamos en las páginas (es decir, presenters). Pueden ser [formularios |forms:in-presenter], [datagrids |https://componette.org/contributte/datagrid/], menús, encuestas de votación, en realidad cualquier cosa que tenga sentido usar repetidamente. Podemos crear nuestros propios componentes o usar algunos de la [enorme oferta |https://componette.org] de componentes de código abierto.
Los componentes influyen fundamentalmente en el enfoque para la creación de aplicaciones. Le abrirán nuevas posibilidades de componer páginas a partir de unidades prefabricadas. Y además tienen algo en común con [Hollywood |components#Estilo Hollywood].
Contenedor DI y configuración
=============================
El contenedor DI o fábrica de objetos es el corazón de toda la aplicación.
No se preocupe, no es ninguna caja negra mágica, como podría parecer por las líneas anteriores. En realidad, es una clase PHP bastante aburrida, que Nette genera y guarda en el directorio de caché. Tiene muchos métodos llamados como `createServiceAbcd()` y cada uno de ellos sabe cómo fabricar y devolver algún objeto. Sí, también está el método `createServiceApplication()`, que fabrica `Nette\Application\Application`, que necesitábamos en el archivo `index.php` para iniciar la aplicación. Y hay métodos que fabrican los presenters individuales. Y así sucesivamente.
A los objetos que crea el contenedor DI, por alguna razón, se les llama servicios.
Lo que es realmente especial de esta clase es que no la programa usted, sino el framework. Él realmente genera el código PHP y lo guarda en el disco. Usted solo da instrucciones sobre qué objetos debe saber fabricar el contenedor y cómo exactamente. Y estas instrucciones están escritas en [archivos de configuración |bootstrapping#Configuración del contenedor DI], para los cuales se utiliza el formato [NEON|neon:format] y, por lo tanto, también tienen la extensión `.neon`.
Los archivos de configuración sirven puramente para instruir al contenedor DI. Así que, por ejemplo, si indico en la sección [session |http:configuration#Sesión] la opción `expiration: 14 days`, el contenedor DI al crear el objeto `Nette\Http\Session` que representa la sesión, llamará a su método `setExpiration('14 days')` y así la configuración se hará realidad.
Hay un capítulo completo preparado para usted que describe qué se puede [configurar |nette:configuring] y cómo [definir servicios propios |dependency-injection:services].
Una vez que se adentre un poco en la creación de servicios, se encontrará con la palabra [autowiring |dependency-injection:autowiring]. Esta es una característica que le simplificará la vida de manera increíble. Sabe cómo pasar automáticamente objetos donde los necesita (por ejemplo, en los constructores de sus clases), sin que tenga que hacer nada. Descubrirá que el contenedor DI en Nette es un pequeño milagro.
¿A dónde ir ahora?
==================
Hemos repasado los principios básicos de las aplicaciones en Nette. Hasta ahora muy superficialmente, pero pronto profundizará y con el tiempo creará maravillosas aplicaciones web. ¿A dónde continuar ahora? ¿Ya ha probado el tutorial [Escribiendo la primera aplicación|quickstart:]?
Además de lo descrito anteriormente, Nette dispone de todo un arsenal de [clases útiles|utils:], [capa de base de datos|database:], etc. Intente simplemente hacer clic en la documentación. O en el [blog|https://blog.nette.org]. Descubrirá muchas cosas interesantes.
Que el framework le traiga mucha alegría 💙