Comment fonctionnent les applications ?
Vous êtes en train de lire le document de base de la documentation Nette. Vous y apprendrez tous les principes des applications web. Nice de A à Z, du moment de la naissance jusqu'au dernier souffle du script PHP. Après la lecture, vous saurez :
- comment tout cela fonctionne
- ce qu'est Bootstrap, Presenter et le conteneur DI
- à quoi ressemble la structure des répertoires
Structure du répertoire
Ouvrez un exemple de squelette d'une application web appelée WebProject et vous pouvez observer les fichiers sur lesquels on écrit.
La structure des répertoires ressemble à ceci :
web-project/ ├── app/ ← répertoire avec application │ ├── 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 │ ├── common.neon │ └── services.neon ├── log/ ← journaux d'erreurs ├── temp/ ← fichiers temporaires, cache, … ├── vendor/ ← bibliothèques installées par Composer │ ├── ... │ └── autoload.php ← autoloading of libs installed by Composer ├── www/ ← répertoire public, racine du document du projet │ ├── .htaccess ← règles du mod_rewrite, etc. │ └── index.php ← fichier initial qui lance l'application └── .htaccess ← interdit l'accès à tous les répertoires sauf www
Vous pouvez modifier la structure des répertoires de n'importe quelle manière, renommer ou déplacer des dossiers, puis
modifier simplement les chemins d'accès à log/
et temp/
dans le fichier Bootstrap.php
et
le chemin d'accès à ce fichier dans composer.json
dans la section autoload
. Rien de plus, pas de
reconfiguration compliquée, pas de changements constants. Nette dispose d'une autodétection intelligente.
Pour les applications un peu plus importantes, nous pouvons diviser les dossiers contenant des présentateurs et des modèles en sous-répertoires (sur le disque) et en espaces de noms (dans le code), que nous appelons modules.
Le répertoire www/
est le répertoire public ou la racine du document du projet. Vous pouvez le renommer sans
avoir à définir quoi que ce soit d'autre du côté de l'application. Il suffit de configurer l'hébergement
pour que le document-root aille dans ce répertoire.
Vous pouvez également télécharger directement le projet Web, y compris Nette, en utilisant Composer:
composer create-project nette/web-project
Sous Linux ou macOS, définissez les droits d'écriture pour les répertoires
log/
et temp/
.
L'application WebProject est prête à fonctionner, il n'est pas nécessaire de configurer quoi que ce soit d'autre et vous
pouvez la visualiser directement dans le navigateur en accédant au dossier www/
.
Demande HTTP
Tout commence lorsqu'un utilisateur ouvre la page dans un navigateur et que le navigateur frappe le serveur avec une requête
HTTP. La requête est dirigée vers un fichier PHP situé dans le répertoire public www/
, qui est
index.php
. Supposons qu'il s'agisse d'une requête vers https://example.com/product/123
et sera
exécutée.
Sa tâche est la suivante :
- initialiser l'environnement
- récupérer l'usine
- lancer l'application Nette qui traite la demande.
Quel genre d'usine ? Nous ne produisons pas de tracteurs, mais des sites web ! Attendez, je vais vous expliquer tout de suite.
Par „initialiser l'environnement“, nous voulons dire, par exemple, que Tracy est activé, qui est un outil étonnant pour consigner ou visualiser les erreurs. Il enregistre les erreurs sur le serveur de production et les affiche directement sur le serveur de développement. Par conséquent, l'initialisation doit également décider si le site fonctionne en mode production ou en mode développement. Pour ce faire, Nette utilise l'autodétection : si vous exécutez le site sur localhost, il fonctionne en mode développeur. Vous n'avez rien à configurer et l'application est prête à être déployée aussi bien en développement qu'en production. Ces étapes sont réalisées et décrites en détail dans le chapitre sur la classe Bootstrap.
Le troisième point (oui, nous avons sauté le deuxième, mais nous y reviendrons) consiste à démarrer l'application. Le
traitement des demandes HTTP dans Nette est effectué par la classe Nette\Application\Application
(ci-après
dénommée Application
), donc lorsque nous disons „lancer une application“, nous voulons dire appeler une
méthode portant le nom run()
sur un objet de cette classe.
Nette est un mentor qui vous guide pour écrire des applications propres grâce à des méthodologies éprouvées. Et la plus
éprouvée est appelée injection de dépendance, en abrégé DI. Pour l'instant, nous ne voulons pas vous ennuyer avec
l'explication de DI, car il y a un chapitre séparé, la chose importante ici
est que les objets clés seront généralement créés par une usine pour les objets appelés conteneur DI (abrégé DIC).
Oui, c'est la fabrique dont on a parlé il y a un moment. Et elle crée également l'objet Application
pour nous,
donc nous avons d'abord besoin d'un conteneur. Nous l'obtenons en utilisant la classe Configurator
et la laissons
produire l'objet Application
, appelons la méthode run()
et cela démarre l'application Nette. C'est
exactement ce qui se passe dans le fichier index.php.
Application Nette
La classe Application a une seule tâche : répondre à une requête HTTP.
Les applications écrites dans Nette sont divisées en plusieurs présentateurs (dans d'autres frameworks, vous pouvez rencontrer le terme contrôleur, qui est le même), qui sont des classes représentant une page spécifique du site Web : par exemple, la page d'accueil, un produit dans une boutique en ligne, un formulaire d'inscription, un flux sitemap, etc. L'application peut avoir de un à plusieurs milliers de 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/Core/RouterFactory.php
et nous le décrirons en détail dans le chapitre Routage.
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.
Le présentateur pourrait ressembler à ceci :
class ProductPresenter extends Nette\Application\UI\Presenter
{
public function __construct(
private ProductRepository $repository,
) {
}
public function renderShow(int $id): void
{
// nous obtenons des données du modèle et les transmettons au modèle
$this->template->product = $this->repository->getProduct($id);
}
}
La demande est traitée par le présentateur. Et la tâche est claire : faire l'action show
avec
id: 123
. Ce qui dans le langage des présentateurs signifie que la méthode renderShow()
est appelée et
que dans le paramètre $id
on obtient 123
.
Un présentateur peut gérer plusieurs actions, c'est-à-dire avoir plusieurs méthodes. render<Action>()
.
Mais nous recommandons de concevoir des présentateurs avec une ou aussi peu d'actions que possible.
Ainsi, la méthode renderShow(123)
a été appelée, dont le code est un exemple fictif, mais vous pouvez y voir
comment les données sont transmises au modèle, c'est-à-dire en écrivant à $this->template
.
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.
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).
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.
Juste pour être sûr, essayons de récapituler l'ensemble du processus avec une URL légèrement différente :
- l'URL sera
https://example.com
- nous démarrons l'application, nous créons un conteneur et nous l'exécutons
Application::run()
- le routeur décode l'URL comme une paire
Home:default
- un objet
HomePresenter
est créé - la méthode
renderDefault()
est appelée (si elle existe) - 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.
Modèles
En ce qui concerne les modèles, Nette utilise le système de modèles Latte. C'est
pourquoi les fichiers contenant des modèles se terminent par .latte
. Latte est utilisé parce que c'est le système
de modèles le plus sûr pour PHP, et en même temps le système le plus intuitif. Vous n'avez pas besoin d'apprendre grand-chose
de nouveau, il vous suffit de connaître PHP et quelques balises Latte. Vous trouverez tout dans la
documentation.
Dans le template, nous créons un lien vers d'autres présentateurs et actions comme suit :
<a n:href="Product:show $productId">product detail</a>
Il suffit d'écrire la paire familière Presenter:action
au lieu de l'URL réelle et d'inclure tous les
paramètres. L'astuce est n:href
, qui indique que cet attribut sera traité par Nette. Et elle le fera :
<a href="/product/456">product detail</a>
Le routeur mentionné précédemment est chargé de générer l'URL. En fait, les routeurs de Nette sont uniques en ce sens qu'ils peuvent non seulement transformer une URL en une paire présentateur:action, mais aussi, à l'inverse, générer une URL à partir du nom du présentateur + action + paramètres. Grâce à cela, dans Nette, vous pouvez changer complètement la forme de l'URL dans toute l'application finie sans changer un seul caractère dans le modèle ou le présentateur, juste en modifiant le routeur. Et grâce à cela, ce que l'on appelle la canonisation fonctionne, ce qui est une autre caractéristique unique de Nette, qui améliore le SEO (optimisation de la facilité de recherche sur Internet) en empêchant automatiquement l'existence de contenu dupliqué à différentes URL. De nombreux programmeurs trouvent cela étonnant.
Composants interactifs
Nous avons encore une chose à vous dire sur les présentateurs : ils ont un système de composants intégré. Les plus anciens d'entre vous se souviennent peut-être de quelque chose de similaire dans Delphi ou ASP.NET Web Forms. React ou Vue.js sont construits sur quelque chose de très similaire. Dans le monde des frameworks PHP, il s'agit d'une fonctionnalité tout à fait unique.
Les composants sont des unités distinctes réutilisables que nous plaçons dans des pages (c'est-à-dire des présentateurs). Il peut s'agir de formulaires, de grilles de données, de menus, de sondages, en fait de tout ce qui peut être utilisé de manière répétée. Nous pouvons créer nos propres composants ou utiliser une partie de la vaste gamme de composants open source.
Les composants modifient fondamentalement l'approche du développement d'applications. Ils ouvrent de nouvelles possibilités pour composer des pages à partir d'unités prédéfinies. Et ils ont quelque chose en commun avec Hollywood.
Conteneur et configuration de DI
Le conteneur DI (fabrique d'objets) est le cœur de toute l'application.
Ne vous inquiétez pas, il ne s'agit pas d'une boîte noire magique, comme cela pourrait sembler dans les mots précédents. En
fait, il s'agit d'une classe PHP assez ennuyeuse générée par Nette et stockée dans un répertoire de cache. Elle possède un
grand nombre de méthodes nommées createServiceAbcd()
et chacune d'entre elles crée et renvoie un objet. Oui, il y
a aussi une méthode createServiceApplication()
qui produit Nette\Application\Application
, dont nous
avons besoin dans le fichier index.php
pour exécuter l'application. Et il y a des méthodes pour produire des
présentateurs individuels. Et ainsi de suite.
Les objets que le conteneur DI crée sont appelés services pour une raison quelconque.
Ce qui est vraiment spécial à propos de cette classe est qu'elle n'est pas programmée par vous, mais par le framework. Il
génère en fait le code PHP et l'enregistre sur le disque. Vous donnez simplement des instructions sur les objets que le
conteneur doit être capable de produire et comment exactement. Ces instructions sont écrites dans des fichiers de configuration au format NEON et portent donc l'extension .neon
.
Les fichiers de configuration sont utilisés uniquement pour donner des instructions au conteneur DI. Ainsi, par exemple, si je
spécifie l'option expiration: 14 days
dans la section session, le conteneur
DI, lorsqu'il créera l'objet Nette\Http\Session
représentant la session, appellera sa méthode
setExpiration('14 days')
, et la configuration deviendra ainsi une réalité.
Un chapitre entier est prêt pour vous, décrivant ce qui peut être configuré et comment définir vos propres services.
Lorsque vous entrerez dans la création de services, vous rencontrerez le mot autowiring. Il s'agit d'un gadget qui vous rendra la vie incroyablement plus facile. Il permet de passer automatiquement des objets là où vous en avez besoin (dans les constructeurs de vos classes, par exemple) sans avoir à faire quoi que ce soit. Vous constaterez que le conteneur DI de Nette est un petit miracle.
Et maintenant ?
Nous avons passé en revue les principes de base des applications dans Nette. Jusqu'ici, très superficiellement, mais vous allez bientôt plonger dans les profondeurs et finalement créer de merveilleuses applications web. Où continuer ? Avez-vous essayé le tutoriel Créer votre première application?
En plus de ce qui précède, Nette dispose de tout un arsenal de classes utiles, d'une couche de base de données, etc. Essayez volontairement de cliquer sur la documentation. Ou visitez le blog. Vous découvrirez beaucoup de choses intéressantes.
Laissez le framework vous apporter beaucoup de joie 💙