Bonjour à tous,
J'ai créé une application pour ma petite entreprise. Celle-ci a pour but de gérer des demandes libellées "jobs" ci-après. Je rencontre un problème que je vais tenter de simplifier au maximum.
Le code côté serveur est du PHP 5.6 qui réalise des requêtes vers une base de données MySQL 5. Je travaille en orienté objet. La partie client se base sur de l'HTML et du JavaScript. Le PHP n'intervient en rien dans la création de la partie client. Le JavaScript réalise des requêtes REST à mon API (via du JSON). Par exemple, pour voir la liste des "jobs", la requête sera : /api/jobs.php?op=get_all_jobs tandis que pour récupérer toutes les informations d'un job, cela sera : /api/jobs.php?op=get_job&id=3.
Comme dit précédemment, je travaille en orienté objet. J'ai une classe "Engine" (un singleton) qui est mon point d'entrée pour tout. Je possède différents "sous-moteurs" qui permettent d'effectuer les actions vers la base de données. Par exemple, si j'ai une entité "User", je posséderai également un "sous-moteur" nommé "UsersEngine" qui possèdera des méthodes comme "getAllUsers()", "getUserFromId()", "searchUsersFromName()", "updateUser()", "deleteUser()", "createUser()", etc...
Au niveau des mes entités, j'ai une classe nommée "Job". Celle-ci contient également d'autres objets comme par exemple des "User" ou encore des "Request". Un "Job" peut être assigné qu'à un seul "User". Voici la conception au niveau de la base de données :
Table "users" :
- ID
- Nom d'utilisateur
- Prénom
- Nom
Table "jobs" :
- ID
- Numéro interne
- ID de l'utilisateur (FK vers la table "users")
- ...
Dans un premier temps, pour récupérer tous les "jobs", je faisais quelque chose comme ceci :
- SELECT sur la table jobs
- Pour chaque FK, j'appelais le sous-moteur correspondant qui faisait une requête séparée pour créer l'objet (...->usersEngine->getUserFromId($idRecupereDansLeSelect)
Rapidement, après quelques milliers d'entrées, les temps de chargement sont devenus longs. Je suis donc passé par un SELECT avec jointure. Je récupère toutes les valeurs et je créé directement les différents objets. Par exemple :
Cela fonctionnait bien. Cependant, il s'est avéré que mes collaborateurs s'échangent les "jobs". Certains s'assignent un "job" pendant 2 mois, n'y touchent pas et le transfèrent à un autre collègue qui traite le "job" en seulement 2 jours (il y a tout un système difficile à expliquer, l'idée n'est pas de revoir le fonctionnement de l'entreprise). Je souhaite donc pouvoir garder un historique facilement accessible des différents "users" assignés à un "job". Voici donc le nouveau design de la base de données :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 $stmt = $this->ser->dbLink->prepare("SELECT j.id, j.num_interne, ...., u.id, u.username, ... FROM jobs AS j JOIN users AS u ON j.user = u.i"); //je bind les résultats sur des variables et je créé mes objets $user = new User($userId, $userUsername, ....); $job = new Job($jobId, $jobNumInterne, ..., $user);
Table "users" :
- ID
- Nom d'utilisateur
- Prénom
- Nom
Table "jobs" :
- ID
- Numéro interne
- ...
Table "jobs_users" :
- ID
- ID du travail (FK vers la table "jobs")
- Date de prise en charge
- ID de l'utilisateur (FK vers la table "users")
- Date de fin de prise en charge
Dans le cas présent, impossible pour moi de faire un SELECT avec jointures. Certains "jobs" auront que une ou deux entrées dans "jobs_users" tandis que d'autres pourraient en avoir beaucoup plus. Ma classe "Job" possède différentes méthodes dont : "getListUsers()" qui dépend des données précitées. D'autres méthodes dépendent d'autres tables que je n'ai pas décrites afin de ne pas surcharger cette discussion.
Vous avez l'état des lieux. J'ai maintenant deux questions à vous poser :
Question 1 : est-il possible d'écrire une requête SQL correspondant aux tables reprises ci-dessus (avec "jobs_users") afin de prendre en compte la relation 1 à n ?
Question 2 : est-il obligatoire (= dans les bonnes pratiques) d'instancier complètement un objet ? Dans mon cas, un objet "Job" implique la création de nombreux objets. Dans la quasi majorité des cas, je n'ai besoin de toutes les données d'un "Job" uniquement quand je le récupère par son ID unique, sinon il s'agit de récupérer que certaines informations afin de les lister. J'ai cherché du côté des design patterns sans succès. (Dans ma situation, je ne peux pas faire du lazy loading car j'envoie les données en JSON. Je dois donc savoir au moment de la requête). Je ne trouve pas propre de ne pas compléter parfaitement un objet mais je trouve également bête de gaspiller des ressources pour des données accédées que 5% du temps.
Je vous remercie pour votre aide et votre expertise.
Partager