Bonjour,
Je suis entrain de développer un site sur le jeu Euro Truck Simulator 2 en MVC (sans framework).
J'aurais une petite question, je souhaite faire un système de module afin d'ajouter de nouvelles fonctionnalités facilement et rapidement.
J'ai déjà une petite idée de comment faire : un fichier JSon (toute la config du site est géré avec du JSon, facile à utiliser et a écrire d'où ce choix ;) ) listant les modules installés et activés. A chaque fois qu'on va sur le site, ce dernier va donc lire cette configuration et charger les dits modules (un peu comme le fait Symfony sauf que pour ce dernier on ne peut désactiver qu'en supprimant la ligne d'appel donc il faut modifier le code pour plus utiliser un bundle, pas terrible je trouve). Ce système me permet donc via l'administration, d'activer/désactiver les différents modules.
Voilà donc ma question : est-ce qu'on peu dans une classe parente, récupéré des informations provenant de la classe enfant ? Il me semble que je l'avais fais en récupérant le nom de la classe enfant, mais je sais plus comment on fait ça et je trouve pas sur le net.
Pourquoi est-ce que je veux faire ça ?
Petite explication :
Je ne veux pas d'une dépendance dans le code, en clair je souhaite faire comme avec Wordpress : modifier une page (par exemple) sans modifier le code de la dite page. En gros avec Wordpress, on peut très bien créer un plugin qui apporte de nouveaux widget quand on poste un message, et un autre plugin qui va modifier ce dit widget voir lui adjoindre un autre widget (je me souviens qu'à Eoxia je l'ai fait ça dans Wordpress).
Ainsi, je souhaite donc qu'un module puisse intéragir sans qu'on ai besoin de faire explicitement appel à lui dans un autre code. Voilà un peu l'idée.
Pour être plus précis et donner un exemple, j'en suis à faire le module de news pour mon site, il me faut donc créer mon système de module (c'est prévu dès ce week-end), mais voilà alors que les news seront affichées sur la page d'accueil, si demain je souhaite que ce ne soit plus les news mais par exemple la liste des 5 derniers messages du forum, ben je veux pouvoir le faire sans aller modifier le code du controller de la page d'accueil (ou son template), ce qui permet alors via l'administration de gérer ce genre de choses (tout est prévu à la gestion via l'admin, le site sera très modulaire).
J'ai donc penser au système d'observé-observateur (le design-pattern Observer), je me disais qu'avec, les pages (controller comme template, ça pourrais se faire aussi avec les entités en théorie lol) qui seraient prévus pour pouvoir avoir des modules qui s'y greffe, seraient donc observés, les modules étant donc observateurs.
A partir de là, un fichier de configuration JSon (services.json par exemple), indiquerais donc les observés et les observateurs à greffer, du coup à l'utilisation de l'observé, il ferait un notify (par exemple) pour informer ses observateurs, ces derniers alors pourraient par exemple afficher leur template (pour reprendre mon exemple des news et des 5 derniers posts du forum).
Par rapport à mon exemple de tout à l'heure, je pourrais donc sans toucher au code de IndexController, afficher les news ou les 5 derniers posts du forum (voir les deux) suivant ce qui est indiqué dans l'administration (ici dans services.json correspondant à IndexController).
Sauf que pour éviter de devoir taper obligatoirement du code particulier dans chaque controller, j'aurais voulut que ça soit inclus directement dans le controller générique dont tous héritent (d'où la question de tout à l'heure).
Si vous savez me répondre à mes quelques questions, et ceux qui auraient des idées pour améliorer ce que je veux faire je suis preneur bien entendu (surtout toi GrafikArt, je sais que tu es d'une aide précieuse ;) ).
Merci d'avance et bonne après-midi à tous.
Par rapport à la question initialement posée :
Est-ce qu'on peu dans une classe parente, récupéré des informations provenant de la classe enfant ? Il me semble que je l'avais fais en récupérant le nom de la classe enfant, mais je sais plus comment on fait ça et je trouve pas sur le net.
Pour récupérer le nom de la classe enfant depuis une méthode définie dans la classe parente, on peut faire appelle à de la résolution static à la volée.
Exemple :
<?php
class ParentClass
{
public function getParentClassName()
{
return self::class;
}
public function getCallerClassName()
{
return static::class;
}
}
class ChildClass extends ParentClass
{}
$child = new ChildClass();
echo $child->getParentClassName();
echo "<br>";
echo $child->getCallerClassName();
En espérant avoir compris la question :)
Salut,
Je n'ai pas compris pourquoi tu voulais récupérer les informations d'une classe enfant dans une classe parent. C'est surprenant d'ailleurs.
Pour ta problématique : j'ai développé un framework il y'a quelques années et j'ai adopté plus ou moins un comportement similaire car j'aime avoir mes couches métiers bien organisées par dossier, et non une organisation du type : un dossier "views", un dossier "controlers" etc...
J'avais créé un super contrôleur pour mes modules, qui connaissait les différentes fonctionnalités proposées par mes modules. Chaque module avait un fichier de configuration afin de décrire ses fonctionnalités.
C'est une sorte de proxy si tu veux, qui connait l'existance des modules, les fonctionnalités qu'ils proposent mais qui se fiche complètement de l'arrière du décors.
Ce controleur lisait les configurations et mettait à disposition de mes vues, des actions, des éléments de menu et différentes choses servant le front mais aussi l'admin des modules.
Grâce à ces fichiers de conf, je gérai aussi l'interdépendance des modules.
Mon proxy-controleur envoyait une erreur si un module avait besoin qu'un autre module soit présent/actif pour fonctionner.
J'avais aussi séparé les modules développés des modules du coeur de mon framework.
Ca me pemettait par exemple d'avoir le module users disponible de manière global pour tous mes autres modules afin de gérer les droits directement dans les fichiers de conf de mes modules ou encore un module utils dans le lequel je mettai des fonctions/class utilitaire disponible dans tout le framework.
Ces modules du coeurs fonctionnait de la même manière, il avait aussi un super controleur pour les rendre disponible au reste de l'application.
Je dis tout ça de mémoire, ça fait quelques années déjà, mais j'espère que ça te donnera des pistes pour avancer.
Bonjour Guique et merci de ta réponse.
Dans le fonctionnement que je désire qui est aussi un tremplin à la création de mon propre framework, je veux malgré un système MVC classique, éviter les dépendances.
Pourquoi je souhaite depuis une classe parente récupérer des informations de la classe enfant ?
Pour te répondre, je prends donc l'exemple du module que là j'ai besoin de créer à savoir les news.
Sur ma page d'accueil je souhaite pouvoir y placer les news ou tout autre module, sans que le controller associé à la vue de ma page d'accueil n'est connaissance de quoi que se soit. En gros, avec le design-pattern Observer, ma page d'accueil informera simplement le ou les observateurs (le module de news en sera donc un). Ceci donc me permettra d'afficher sur l'accueil, le module des news avec une vue prévue à cet effet au sein du module.
Sauf que le module à besoin de la gestion utilisateur, mais je ne veux pas devoir au sein même du module devoir récupérer manuellement les informations.
Je souhaite que tout le travail normal de gestion utilisateur (par exemple), puisse être fait par le controller principal d'après des informations de son enfant, sans obliger l'enfant à devoir faire lui même des vérifications. Ainsi, quand on veut aller sur l'administration par exemple, il faut vérifier qu'on est un utilisateur ayant les droits pour y accéder ; sauf qu'il faut répercuter la vérification au sein des controllers concernés, donc tous les modules ayant une administration (+ l'administration générale), doit donc appeler une fonction de la gestion utilisateur, afin de vérifier que la personne dispose bien des droits.
C'est un code lourd et chiant qui se répète continuellement, je voulais donc qu'au moment de l'appel au controller, donc dans le __construct de la classe, que la classe parente (initialisée juste avant), il puisse y avoir une vérification qui est effectuée d'après une propriété ou une constante (je sais pas trop comment faire) de la classe enfant.
En gros, chaque controller peut demander certaines autorisations pour autoriser l'accès ; au lieu que se soit le controller qui fasse tout le boulot et donc répéter sans cesse le code, la vérification est faite par la classe parente mais d'après l'information provenant de l'enfant puisque c'est lui qui définit les autorisations nécessaires.
J'avais déjà fait des tests à un moment donnés, mais hélas je n'ai plus le code ; où j'avais réussi à faire un truc du genre.
Comme au moment de la construction de l'enfant, on construit le parent en premier, j'avais trouvé que la classe dont on hérite, pouvait savoir qui l'avait appelé (en l'occurence c'est la classe enfant qui l'appel), et donc accéder aux informations publiques de la classe appelante. Mais je ne sais plus du tout comment faire.
J'avais placé cela dans la configuration de mes modules.
Chaque module proposait des actions disponible pour le reste de l'application et chaque action nécessitait certains droits.
Le proxy-controlleur sert justement de lien.
Il connaissait les actions de chaque module, les droits nécessaire pour y accéder, et il déléguait au module users, global à l'application, le soin de savoir si l'utilisateur pouvait ou non accéder au contenu.
Quand je parle de dépendance, je ne suis pas dans une architecture en arbre mais dans une architecture de micro-service.
Exemple de dépendance dans cette architecture : le module facturation a besoin d'appeler le module user pour générer une facture.
Plutôt que laisser cela dans le code des modules, je l'avais renseigné dans les fichiers de config des modules pour que cela soit testé en amont, avant d'executer le code de mon module, par le proxy-controleur.
Ce super controleur te permet aussi de ne charger que les modules dont tu as besoin pour répondre à la demande utilisateur et tout le code lourd dont tu parles (contrôle des rôles des utilisateurs etc..) est géré par un seul et unique module, le module users.
Dernière chose : le framework dont je parle avait une architecture MVC.
Je vais peut être froisser les puristes mais à mes yeux, une architecture MVC ne veut pas dire un dossier "Models", un dossier "Views" et un dossier "Controller".
Dans mon cas, chaque module définissait son controller (extends d'une classe controller bien entendu), son modèle (idem) et au besoin ses views.
En gros, vu que j'ai déjà un système de configuration (par fichiers JSon, lus directement pour l'instant, à terme ce sera une lib qui vérifiera la structure pour la valider avant de renvoyer le tableau correspondant au JSon ; le résultat étant toujours spécifique à la lib concernée), avec un fichier de configuration lu directement par mon controller principal (donc automatiquement exécuté à l'appel de n'importe quel controller), je pourrais lui faire vérifier les droits ?
Du coup je pourrais avoir un fichier du genre "services.json", avec une section dedans dédier à la vérification utilisateur ; le module plaçant alors dedans (à son installation), dans cette section, l'information sur les droits nécessaires ; le controller principal lisant alors cette information, pourra vérifier les droits utilisateurs. Mais il faut toujours pouvoir savoir le module qui a besoin de cette vérification non ?
C'est là où je ne sais pas trop comment faire à part avec mon idée, pour que chaque module n'est pas besoin de tester les droits (et donc que ça soit fait en automatique), alors que les droits sont différents suivant le module.
Ou alors (je suis entrain de penser à ça en te répondant lol), je pourrais (pour simplifier le bordel), dans le constructeur du module, appeler en premier le constructeur du parent puis appeler une simple fonction du parent en lui fournissant le nom du module. Le controller principal (qui est le parent), fait alors les vérifications depuis le fichier de configuration JSon dans la section dont il a reçu le nom en paramètre.
Comme je gère les erreurs avec des exceptions (et mon propre gestionnaire d'erreur), je peux donc vérifier les droits spécifique au module via le parent, qui renvoi alors une exception (via le gestionnaire d'erreur) si l'utilisateur n'a pas les droit.
Comme c'est une exception, le code s'arrête donc je n'ai rien à gérer derrière et l'action du controller appelé du module ne s'exécutera alors pas (ce qui est le but dans ce que je veux faire).
Qu'est-ce que tu en penses ?
Bonjour SimonAndGarfunkel, c'est exactement ce que je cherchais merci de l'information.
Hello,
Oui, c'est cela que j'avais fait.
Le choix que j'avais fait était de rendre les modules totalement vide de toute la logique du framework, sauf dans le fichier de configuration, afin qu'un autre développeur, sans connettre le framework, puisse facilement développer un module et l'insérer. Ca a été le cas et ça a bien marché.
Attention tout de même : l'exemple dont je te parle a plusieurs années maintenant. Je ferai peut être les choses différements aujourd'hui.
Par exemple, pour un dev en ce moment, je m'interesse plus à ce genre de chose
Bon courage pour ton développement en tout cas.
Je te félicite pour la démarche.
Tout développeur devrait un jour passer par la à mes yeux afin de bien comprendre, en profondeur, les choses.
Il y en a malheureusement trop à mon gout qui se contentent d'installer des libraries sans réellement comprendre les concepts de base.
Merci pour le lien Guique, j'étudierais ça à l'occasion. En fait je fais cette démarche de "presque" tout développer moi même car Symfony correspond pas à mes besoins. En effet, mon site doit pouvoir être installer par n'importe qui (il est open-source) qui souhaite gérer cette "extension RP du jeu Euro Truck Simulator 2" entre membre d'un groupe sans en passer par le site officiel de mon projet ; hors Symfony requiert obligatoirement l'usage de la console donc accès SSH et connaissance du fonctionnement + modification de parameters.yml.
Hors mon but, est d'être comme sur un CMS : tu arrives sur la page d'installation, tu remplis le formulaire et basta, la base est créer/configurer, le fichier de configuration est créer etc.
En sus cela me permet aussi de mieux comprendre comment chaque choses fonctionnent, donc même si je réutilise Twig actuellement pour les templates, je fais mon propre système d'entités (pas d'ORM), mon propre système de routing, de gestion d'erreurs et j'en passe.
A terme, tout ces outils devraient effectivement me permettre de créer mon propre framework, répondant à mes besoins. Mais après j'ai d'autres projets qui seront certainement fait avec Symfony.