Comment fonctionnent les applications ?
Vous lisez actuellement le guide fondamental de la documentation Nette. Vous apprendrez tout le principe de fonctionnement des applications web. De A à Z, du début à la fin de l'exécution du script PHP. Après lecture, vous saurez :
- comment tout cela fonctionne
- ce qu'est Bootstrap, un Presenter et un conteneur DI
- à quoi ressemble la structure des répertoires
Structure des répertoires
Ouvrez l'exemple de squelette d'application web appelé WebProject et pendant la lecture, examinez les fichiers mentionnés.
La structure des répertoires ressemble à quelque chose comme ceci :
web-project/ ├── app/ ← répertoire de l'application │ ├── Core/ ← classes de base nécessaires au fonctionnement │ │ └── RouterFactory.php ← configuration des adresses URL │ ├── Presentation/ ← presenters, templates & co. │ │ ├── @layout.latte ← template de layout │ │ └── Home/ ← répertoire du presenter Home │ │ ├── HomePresenter.php ← classe du presenter Home │ │ └── default.latte ← template de l'action default │ └── Bootstrap.php ← classe de démarrage Bootstrap ├── bin/ ← scripts exécutés depuis la ligne de commande ├── config/ ← fichiers de configuration │ ├── common.neon │ └── services.neon ├── log/ ← erreurs journalisées ├── temp/ ← fichiers temporaires, cache, … ├── vendor/ ← bibliothèques installées par Composer │ ├── ... │ └── autoload.php ← autoloading de tous les paquets installés ├── www/ ← répertoire public ou document-root du projet │ ├── .htaccess ← règles mod_rewrite │ └── index.php ← fichier initial par lequel l'application est lancée └── .htaccess ← interdit l'accès à tous les répertoires sauf www
Vous pouvez modifier la structure des répertoires comme vous le souhaitez, renommer ou déplacer des dossiers, elle est entièrement flexible. De plus, Nette dispose d'une autodétection intelligente et reconnaît automatiquement l'emplacement de l'application, y compris sa base d'URL.
Pour les applications légèrement plus grandes, nous pouvons diviser les dossiers avec les presenters et les templates en sous-répertoires et les classes en espaces de noms, que nous appelons modules.
Le répertoire www/
représente le répertoire public ou document-root du projet. Vous pouvez le renommer sans
aucune configuration supplémentaire côté application. Il suffit de configurer
l'hébergement pour que le document-root pointe vers ce répertoire.
Vous pouvez également télécharger directement WebProject incluant Nette en utilisant Composer :
composer create-project nette/web-project
Sous Linux ou macOS, définissez les permissions d'écriture pour
les répertoires log/
et temp/
.
L'application WebProject est prête à être lancée, il n'y a absolument rien à configurer et vous pouvez l'afficher
directement dans le navigateur en accédant au dossier www/
.
Requête HTTP
Tout commence au moment où l'utilisateur ouvre une page dans le navigateur. C'est-à-dire lorsque le navigateur contacte le
serveur avec une requête HTTP. La requête pointe vers un seul fichier PHP, qui se trouve dans le répertoire public
www/
, et c'est index.php
. Supposons qu'il s'agisse d'une requête pour l'adresse
https://example.com/product/123
. Grâce à une configuration serveur
appropriée, cette URL est également associée au fichier index.php
, qui est ensuite exécuté.
Ses tâches sont :
- initialiser l'environnement
- obtenir la factory
- lancer l'application Nette, qui traitera la requête
Quelle factory ? Nous ne fabriquons pas de tracteurs, mais des sites web ! Patientez, cela va s'éclaircir.
Par “initialisation de l'environnement”, nous entendons par exemple l'activation de Tracy, qui est un outil exceptionnel pour la journalisation ou la visualisation des erreurs. Sur un serveur de production, il journalise les erreurs, sur un serveur de développement, il les affiche directement. L'initialisation comprend donc également la décision de savoir si le site fonctionne en mode production ou développement. Pour cela, Nette utilise une autodétection intelligente : si vous lancez le site sur localhost, il fonctionne en mode développement. Vous n'avez donc rien à configurer et l'application est prête à la fois pour le développement et le déploiement en production. Ces étapes sont effectué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) est le lancement de l'application. Le
traitement des requêtes HTTP dans Nette est géré par la classe Nette\Application\Application
(ci-après
Application
), donc quand nous disons lancer l'application, nous entendons spécifiquement appeler la méthode
run()
sur l'objet de cette classe.
Nette est un mentor qui vous guide vers l'écriture d'applications propres selon des méthodologies éprouvées. Et l'une de
celles qui sont absolument les plus éprouvées s'appelle l'injection de dépendances, en abrégé DI. Pour le moment, nous
ne voulons pas vous surcharger avec l'explication de la DI, il y a un chapitre séparé pour cela, l'important est la conséquence
que les objets clés nous seront généralement créés par une factory d'objets appelée conteneur DI (abrégé en DIC).
Oui, c'est la factory dont il était question il y a un instant. Et elle nous créera aussi l'objet Application
,
c'est pourquoi nous avons d'abord besoin du conteneur. Nous l'obtenons à l'aide de la classe Configurator
et nous
lui demandons de créer l'objet Application
, nous appelons sa méthode run()
et l'application Nette est
ainsi lancée. C'est exactement ce qui se passe dans le fichier index.php.
Nette Application
La classe Application
n'a qu'une seule tâche : répondre à la requête HTTP.
Les applications écrites en Nette sont divisées en de nombreux presenters (dans d'autres frameworks, vous pouvez rencontrer le terme controller, c'est la même chose), qui sont des classes, dont chacune représente une page web spécifique : par ex. la page d'accueil ; un produit dans une boutique en ligne ; un formulaire de connexion ; un flux sitemap, etc. Une application peut avoir d'un à des milliers de presenters.
Application
commence par demander au routeur de décider à quel presenter transmettre la requête actuelle pour
traitement. Le routeur détermine qui est responsable. Il regarde l'URL d'entrée https://example.com/product/123
et
sur la base de sa configuration, décide que c'est le travail, par ex., du presenter Product
, auquel il
demandera comme action l'affichage (show
) du produit avec id: 123
. Il est de bonne pratique de
noter la paire presenter + action séparée par deux-points, comme Product:show
.
Le routeur a donc transformé l'URL en une paire Presenter:action
+ paramètres, dans notre cas
Product:show
+ id: 123
. À quoi ressemble un tel routeur, vous pouvez le voir dans le fichier
app/Core/RouterFactory.php
et nous le décrivons en détail dans le chapitre Routage.
Continuons. Application
connaît déjà le nom du presenter et peut continuer. En créant l'objet de la classe
ProductPresenter
, qui est le code du presenter Product
. Plus précisément, il demande au conteneur DI
de créer le presenter, car c'est son rôle.
Le presenter peut ressembler à ceci :
class ProductPresenter extends Nette\Application\UI\Presenter
{
public function __construct(
private ProductRepository $repository,
) {
}
public function renderShow(int $id): void
{
// nous obtenons les données du modèle et les passons au template
$this->template->product = $this->repository->getProduct($id);
}
}
Le presenter prend en charge le traitement de la requête. Et la tâche est claire : effectuer l'action show
avec
id: 123
. Ce qui, dans le langage des presenters, signifie que la méthode renderShow()
est appelée et
reçoit 123
dans le paramètre $id
.
Un presenter peut gérer plusieurs actions, c'est-à-dire avoir plusieurs méthodes render<Action>()
. Mais
nous recommandons de concevoir des presenters avec une seule ou le moins d'actions possible.
Donc, 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 passées au template, c'est-à-dire en écrivant dans $this->template
.
Ensuite, le presenter retourne une réponse. Cela peut être une page HTML, une image, un document XML, l'envoi d'un fichier
depuis le disque, du JSON ou même une redirection vers une autre page. Il est important que si nous ne disons pas explicitement
comment répondre (ce qui est le cas de ProductPresenter
), la réponse sera le rendu d'un template avec une page
HTML. Pourquoi ? Parce que dans 99% des cas, nous voulons rendre un template, donc le presenter considère ce comportement comme
celui par défaut et veut nous faciliter le travail. C'est le but de Nette.
Nous n'avons même pas besoin de spécifier quel template rendre, il déduit le chemin lui-même. Dans le cas de l'action
show
, il essaie simplement de charger le template show.latte
dans le répertoire de la classe
ProductPresenter
. Il essaie également de trouver le layout dans le fichier @layout.latte
(plus de
détails sur la recherche de
templates).
Et ensuite, il rend les templates. La tâche du presenter et de toute l'application est ainsi terminée. Si le template n'existait pas, une page d'erreur 404 serait retournée. Vous en apprendrez plus sur les presenters sur la page Presenters.
Pour être sûr, essayons de récapituler tout le processus avec une URL légèrement différente :
- L'URL sera
https://example.com
- nous démarrons l'application, le conteneur est créé et
Application::run()
est lancé - le routeur décode l'URL comme la paire
Home:default
- l'objet de la classe
HomePresenter
est créé - la méthode
renderDefault()
est appelée (si elle existe) - le template (par ex.
default.latte
) avec le layout (par ex.@layout.latte
) est rendu
Vous avez peut-être rencontré de nombreux nouveaux termes maintenant, mais nous espérons qu'ils ont du sens. Créer des applications avec Nette est incroyablement simple et agréable.
Templates
Puisque nous avons parlé des templates, Nette utilise le système de templates Latte. D'une part parce que c'est le système de templates le plus sécurisé pour PHP, et d'autre part parce que c'est aussi le système le plus intuitif. Vous n'avez pas besoin d'apprendre beaucoup de nouveautés, la connaissance de PHP et de quelques balises suffit. Vous apprendrez tout dans la documentation.
Dans le template, des liens sont créés vers d'autres presenters & actions comme ceci :
<a n:href="Product:show $productId">détail du produit</a>
Au lieu d'une URL réelle, écrivez simplement la paire connue Presenter:action
et spécifiez d'éventuels
paramètres. L'astuce réside dans n:href
, qui indique que cet attribut sera traité par Nette. Et il
générera :
<a href="/product/456">détail du produit</a>
La génération d'URL est gérée par le routeur mentionné précédemment. En effet, les routeurs dans Nette sont exceptionnels car ils peuvent effectuer non seulement des transformations d'URL en paire presenter:action, mais aussi l'inverse, c'est-à-dire générer une URL à partir du nom du presenter + action + paramètres. Grâce à cela, dans Nette, vous pouvez complètement changer les formes d'URL dans toute une application terminée, sans changer un seul caractère dans le template ou le presenter. Juste en modifiant le routeur. Grâce à cela fonctionne également la canonisation, qui est une autre caractéristique unique de Nette, contribuant à un meilleur SEO (optimisation pour les moteurs de recherche) en empêchant automatiquement l'existence de contenu dupliqué sur différentes URL. De nombreux programmeurs trouvent cela impressionnant.
Composants interactifs
Nous devons vous dire encore une chose sur les presenters : ils ont un système de composants intégré. Les vétérans peuvent se souvenir de quelque chose de similaire dans Delphi ou ASP.NET Web Forms ; React ou Vue.js sont basés sur quelque chose de vaguement similaire. Dans le monde des frameworks PHP, c'est une caractéristique absolument unique.
Les composants sont des unités autonomes et réutilisables que nous insérons dans les pages (c'est-à-dire les presenters). Il peut s'agir de formulaires, de datagrids, de menus, de sondages, en fait de tout ce qu'il est judicieux d'utiliser de manière répétée. Nous pouvons créer nos propres composants ou utiliser certains de la vaste offre de composants open source.
Les composants influencent fondamentalement l'approche de la création d'applications. Ils vous ouvrent de nouvelles possibilités de composition de pages à partir d'unités préfabriquées. Et en plus, ils ont quelque chose en commun avec Hollywood.
Conteneur DI et configuration
Le conteneur DI ou factory d'objets est le cœur de toute l'application.
Ne vous inquiétez pas, ce n'est pas une boîte noire magique, comme on pourrait le penser d'après les lignes précédentes.
En fait, c'est une classe PHP plutôt simple, générée par Nette et stockée dans le répertoire cache. Elle a beaucoup de
méthodes nommées comme createServiceAbcd()
et chacune d'elles sait comment créer et retourner un objet. Oui, il y
a aussi une méthode createServiceApplication()
, qui crée Nette\Application\Application
, dont nous
avions besoin dans le fichier index.php
pour lancer l'application. Et il y a des méthodes créant les presenters
individuels. Et ainsi de suite.
Les objets que le conteneur DI crée sont, pour une raison quelconque, appelés services.
Ce qui est vraiment spécial à propos de cette classe, c'est que ce n'est pas vous qui la programmez, mais le framework. Il
génère réellement le code PHP et le sauvegarde sur le disque. Vous donnez simplement des instructions sur les objets que le
conteneur doit savoir créer et comment précisément. Et ces instructions sont écrites dans des fichiers de configuration, pour
lesquels le format NEON est utilisé et qui ont donc aussi l'extension
.neon
.
Les fichiers de configuration servent uniquement à instruire le conteneur DI. Ainsi, par exemple, si j'indique dans la section
session l'option expiration: 14 days
, alors le
conteneur DI, lors de la création de l'objet Nette\Http\Session
représentant la session, appellera sa méthode
setExpiration('14 days')
et la configuration deviendra ainsi réalité.
Il y a tout un chapitre préparé pour vous décrivant tout ce qui peut être configuré et comment définir vos propres services.
Dès que vous vous familiariserez un peu avec la création de services, vous rencontrerez le mot autowiring. C'est une astuce qui vous simplifiera incroyablement la vie. Elle sait comment passer automatiquement des objets là où vous en avez besoin (par exemple dans les constructeurs de vos classes), sans que vous ayez à faire quoi que ce soit. Vous découvrirez que le conteneur DI de Nette est un petit miracle.
Où aller ensuite ?
Nous avons parcouru les principes de base des applications en Nette. Pour l'instant très superficiellement, mais vous approfondirez bientôt et créerez avec le temps de merveilleuses applications web. Où continuer ? Avez-vous déjà essayé le tutoriel Écrivons notre première application ?
En plus de ce qui a été décrit ci-dessus, Nette dispose de tout un arsenal de classes utiles, d'une couche de base de données, etc. Essayez juste de parcourir la documentation. Ou le blog. Vous découvrirez beaucoup de choses intéressantes.
Que le framework vous apporte beaucoup de joie 💙