Compare commits
142 Commits
issue_028_
...
master
Binary file not shown.
@ -0,0 +1,276 @@
|
||||
[retour au README.md](../../../README.md)
|
||||
[Retour aux Documents](../../README_DOCUMENTS.md)
|
||||
[Retour au diagramme de classes](../README_DIAGRAMMES.md)
|
||||
|
||||
# BDD
|
||||
|
||||
## Modèle Logique de Données (MLD)
|
||||
|
||||
Le MLD représente la structure de données de l'application, décrivant les entités et les relations entre elles. Voici un aperçu des principales entités du MLD :
|
||||
|
||||
### Athlète (Athlete)
|
||||
|
||||
L'entité principale représentant un athlète avec ces informations propre à lui telles que l'identifiant, le nom, le prénom, l'email, etc. Les athlètes peuvent être coach avec le boolean idCoach et être liés par des amitiés, ou par un coaching via la table `Amitie`.
|
||||
|
||||
### Amitié (Friendship)
|
||||
|
||||
Une entité qui modélise les relations d'amitié entre les athlètes et de coaching entre les athlètes et les coachs. Elle stocke les identifiants des deux utilisateurs impliqués.
|
||||
|
||||
### Notification (Notification)
|
||||
|
||||
L'entité qui stocke les notifications destinées aux athlètes, avec des détails tels que le message, la date, le statut, et le degré d'urgence.
|
||||
|
||||
### Envoi de Notification (SendNotification)
|
||||
|
||||
Une entité de liaison entre les athlètes et les notifications, indiquant quel athlète ou coach a envoyé quelle notification. Cela peut-être utile lors d'une notification d'ajout d'amie par exemple.
|
||||
|
||||
### Statistique (Statistic)
|
||||
|
||||
Les statistiques relatives à un athlètes, y compris le poids, la fréquence cardiaque moyenne, la fréquence cardiaque maximale, etc.
|
||||
|
||||
### Entraînement (Training)
|
||||
|
||||
Détails sur les sessions d'entraînement planifiés par un coach pour ses athlètes, comprenant la date, la description, la localisation, etc. Les athlètes peuvent participer à des entraînements et donner leur feedback sur l'entrainement donné.
|
||||
|
||||
### Participation (Participate)
|
||||
|
||||
Une entité de liaison entre les athlètes et les entraînements, indiquant quels athlètes participent à quels entraînements.
|
||||
|
||||
### Don (GiveParticipation)
|
||||
|
||||
Une entité de liaison entre les coachs et les entraînements, indiquant quels coachs ont attribué quels entraînements.
|
||||
|
||||
### Source de Données (DataSource)
|
||||
|
||||
L'entité représentant la source des données des enregistrements sportif, telle que le type, le modèle, la précision, etc., utilisée par les athlètes pour enregistrer une ou des activités.
|
||||
|
||||
### Activité (Activity)
|
||||
|
||||
Les détails des activités des athlètes, y compris le type, la date, les heures de début et de fin, l'effort ressenti, etc.
|
||||
|
||||
### Fréquence Cardiaque (HeartRate)
|
||||
|
||||
Les données de fréquence cardiaque enregistrées pendant les activités, avec des informations telles que l'altitude, la température, etc.
|
||||
|
||||
Ce MLD forme la base de données sous-jacente pour l'application, offrant une structure organisée pour stocker et récupérer les informations relatives aux athlètes et à leurs activités.
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
skinparam classAttributeIconSize 0
|
||||
package MLD{
|
||||
entity "Athlete" as athlete {
|
||||
{static} idAthlete
|
||||
username
|
||||
nom
|
||||
prenom
|
||||
email
|
||||
sexe
|
||||
taille
|
||||
poids
|
||||
motDePasse
|
||||
dateNaissance
|
||||
isCoach
|
||||
}
|
||||
|
||||
entity "Amitie" as friendship{
|
||||
{static}# idAthlete1
|
||||
{static}# idAthlete2
|
||||
début
|
||||
}
|
||||
|
||||
entity "Notification" as notif {
|
||||
{static} idNotif
|
||||
message
|
||||
date
|
||||
statut
|
||||
urgence
|
||||
#athleteId
|
||||
}
|
||||
|
||||
entity "Envoi" as sendNotif{
|
||||
{static}# idAthlete
|
||||
{static}# idNotif
|
||||
}
|
||||
|
||||
entity "Statistique" as stats {
|
||||
{static} idStatistique
|
||||
poids
|
||||
fcMoyenne
|
||||
fcMax
|
||||
caloriesBruleesMoy
|
||||
date
|
||||
#athleteId
|
||||
}
|
||||
|
||||
entity "Entrainement" as training {
|
||||
{static} idEntrainement
|
||||
date
|
||||
description
|
||||
latitude
|
||||
longitude
|
||||
feedback
|
||||
#athleteId
|
||||
}
|
||||
|
||||
entity "Participe" as takepart {
|
||||
{static} #athleteId
|
||||
{static} #entrainementId
|
||||
}
|
||||
|
||||
entity "Donne" as givepart {
|
||||
{static} #coachId
|
||||
{static} #entrainementId
|
||||
}
|
||||
|
||||
|
||||
entity "SourceDonnee" as source {
|
||||
{static} idSource
|
||||
type
|
||||
modele
|
||||
precision
|
||||
#athleteId
|
||||
}
|
||||
|
||||
entity "Activite" as activity {
|
||||
{static} idActivité
|
||||
type
|
||||
date
|
||||
heureDeDebut
|
||||
heureDeFin
|
||||
effortRessent
|
||||
variabilite
|
||||
variance
|
||||
ecartType
|
||||
moyenne
|
||||
maximum
|
||||
minimum
|
||||
temperatureMoyenne
|
||||
#athleteId
|
||||
#sourceId
|
||||
}
|
||||
entity "FréquenceCardiaque" as fc {
|
||||
{static} idFc
|
||||
altitude
|
||||
temps : time
|
||||
température
|
||||
bpm
|
||||
longitude
|
||||
latitude
|
||||
#activitéId
|
||||
}
|
||||
|
||||
}
|
||||
activity --> athlete
|
||||
activity --> source
|
||||
activity <-- fc
|
||||
athlete <-- source
|
||||
stats --> athlete
|
||||
takepart --> athlete
|
||||
takepart --> training
|
||||
givepart --> athlete
|
||||
givepart --> training
|
||||
sendNotif --> athlete
|
||||
sendNotif --> notif
|
||||
friendship --> athlete
|
||||
notif --> athlete
|
||||
athlete <-- friendship
|
||||
@enduml
|
||||
```
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
skinparam classAttributeIconSize 0
|
||||
package MCD{
|
||||
entity "Athlete" as athlete {
|
||||
{static} idAthlete
|
||||
username
|
||||
nom
|
||||
prenom
|
||||
email
|
||||
sexe
|
||||
taille
|
||||
poids
|
||||
motDePasse
|
||||
dateNaissance
|
||||
isCoach
|
||||
}
|
||||
|
||||
entity "Notification" as notif {
|
||||
{static} idNotif
|
||||
message
|
||||
date
|
||||
statut
|
||||
urgence
|
||||
#athleteId
|
||||
}
|
||||
|
||||
entity "Statistique" as stats {
|
||||
{static} idStatistique
|
||||
poids
|
||||
fcMoyenne
|
||||
fcMax
|
||||
caloriesBruleesMoy
|
||||
date
|
||||
#athleteId
|
||||
}
|
||||
|
||||
entity "Entrainement" as training {
|
||||
{static} idEntrainement
|
||||
date
|
||||
description
|
||||
latitude
|
||||
longitude
|
||||
feedback
|
||||
#athleteId
|
||||
}
|
||||
|
||||
entity "SourceDonnee" as source {
|
||||
{static} idSource
|
||||
type
|
||||
modele
|
||||
precision
|
||||
#athleteId
|
||||
}
|
||||
|
||||
entity "Activite" as activity {
|
||||
{static} idActivité
|
||||
type
|
||||
date
|
||||
heureDeDebut
|
||||
heureDeFin
|
||||
effortRessent
|
||||
variabilite
|
||||
variance
|
||||
ecartType
|
||||
moyenne
|
||||
maximum
|
||||
minimum
|
||||
temperatureMoyenne
|
||||
#athleteId
|
||||
#sourceId
|
||||
}
|
||||
|
||||
entity "FréquenceCardiaque" as fc {
|
||||
{static} idFc
|
||||
altitude
|
||||
temps : time
|
||||
température
|
||||
bpm
|
||||
longitude
|
||||
latitude
|
||||
#activitéId
|
||||
}
|
||||
|
||||
}
|
||||
activity "0..n" --- "1..1" athlete : réalise
|
||||
activity "1..n" --- "1..1" source : possede
|
||||
activity "1..1" --- "1..n" fc : enregistre
|
||||
athlete "1..n" --- "0..1" source : possede
|
||||
stats "0..n" --- "1..1" athlete : possede
|
||||
training "0..n" --- "1..n" athlete : participe
|
||||
training "0..n" --- "1..1" athlete : donne
|
||||
athlete "0..n" --- "1..n" athlete : est ami
|
||||
notif "0..n" --- "1..n" athlete : recoit
|
||||
notif "0..n" --- "1..1" athlete : envoie
|
||||
@enduml
|
||||
```
|
@ -1,107 +0,0 @@
|
||||
<mxfile host="app.diagrams.net" modified="2023-09-25T06:43:46.406Z" agent="Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0" etag="e-4pS3rH9xNpreRilvi5" version="21.8.2" type="device">
|
||||
<diagram name="Page-1" id="2OfyMqm8PIhWsBFCJvOv">
|
||||
<mxGraphModel dx="2049" dy="1071" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="Ym5UIEUMnJ661rIFWdHi-1" value="Sportif<br>" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="100" y="240" width="30" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Ym5UIEUMnJ661rIFWdHi-6" value="" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="230" y="170" width="340" height="890" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Ym5UIEUMnJ661rIFWdHi-7" value="Application FitWeb" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="340" y="170" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Ym5UIEUMnJ661rIFWdHi-8" value="" style="endArrow=none;html=1;rounded=0;exitX=-0.006;exitY=0.037;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="Ym5UIEUMnJ661rIFWdHi-6" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="230" y="201" as="sourcePoint" />
|
||||
<mxPoint x="570" y="200" as="targetPoint" />
|
||||
<Array as="points" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="Ym5UIEUMnJ661rIFWdHi-9" value="" style="ellipse;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="320" y="220" width="160" height="100" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Ym5UIEUMnJ661rIFWdHi-10" value="Analyser la fréquence cardique" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="332" y="255" width="136" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Ym5UIEUMnJ661rIFWdHi-22" value="" style="ellipse;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="320" y="355" width="160" height="100" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Ym5UIEUMnJ661rIFWdHi-23" value="Statistique condition physique&nbsp;&nbsp;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="340" y="375" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Ym5UIEUMnJ661rIFWdHi-26" value="Améliorer les entrainements" style="ellipse;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="320" y="485" width="158" height="100" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="gRiRGuH9TPFdmmPZYA_R-7" value="" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" target="Ym5UIEUMnJ661rIFWdHi-9" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="130" y="270" as="sourcePoint" />
|
||||
<mxPoint x="310" y="270" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="gRiRGuH9TPFdmmPZYA_R-9" value="" style="endArrow=classic;html=1;rounded=0;" parent="1" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="130" y="280" as="sourcePoint" />
|
||||
<mxPoint x="320" y="390" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="gRiRGuH9TPFdmmPZYA_R-10" value="" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=0;entryDx=0;entryDy=0;" parent="1" target="Ym5UIEUMnJ661rIFWdHi-26" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="130" y="290" as="sourcePoint" />
|
||||
<mxPoint x="320" y="485" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="gRiRGuH9TPFdmmPZYA_R-11" value="Développeur" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="712" y="930" width="30" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="gRiRGuH9TPFdmmPZYA_R-13" value="" style="endArrow=classic;html=1;rounded=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" parent="1" edge="1" source="gRiRGuH9TPFdmmPZYA_R-11">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="132" y="857.5" as="sourcePoint" />
|
||||
<mxPoint x="480" y="960" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="gRiRGuH9TPFdmmPZYA_R-15" value="<font style="font-size: 16px;">Diagramme de cas d'utilisation de l'application Fit Web</font>" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="199" y="60" width="400" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="aGqo4vDs0eBD3chBgCWU-1" value="Coach Sportif" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="712" y="630" width="30" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="aGqo4vDs0eBD3chBgCWU-5" value="Consulter les statistiques de son équipe" style="ellipse;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="318" y="610" width="158" height="100" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="aGqo4vDs0eBD3chBgCWU-6" value="Développer et maintenir l'application" style="ellipse;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="320" y="910" width="158" height="100" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="aGqo4vDs0eBD3chBgCWU-7" value="" style="endArrow=classic;html=1;rounded=0;" edge="1" parent="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="710" y="660" as="sourcePoint" />
|
||||
<mxPoint x="480" y="660" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="aGqo4vDs0eBD3chBgCWU-8" value="&nbsp;Reporter un bug" style="ellipse;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="318" y="740" width="158" height="100" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="aGqo4vDs0eBD3chBgCWU-9" value="" style="endArrow=classic;html=1;rounded=0;entryX=1;entryY=0.41;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" target="aGqo4vDs0eBD3chBgCWU-8">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="710" y="670" as="sourcePoint" />
|
||||
<mxPoint x="792" y="730" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="aGqo4vDs0eBD3chBgCWU-12" value="" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" target="aGqo4vDs0eBD3chBgCWU-8">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="140" y="330" as="sourcePoint" />
|
||||
<mxPoint x="160" y="385" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="aGqo4vDs0eBD3chBgCWU-13" value="" style="endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;rounded=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" edge="1" parent="1" source="aGqo4vDs0eBD3chBgCWU-8" target="aGqo4vDs0eBD3chBgCWU-6">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="268" y="930" as="sourcePoint" />
|
||||
<mxPoint x="318" y="880" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
@ -0,0 +1,56 @@
|
||||
[retour au README.md](../../../README.md)
|
||||
[Retour aux Documents](../../README_DOCUMENTS.md)
|
||||
[Retour au diagramme de classes](../README_DIAGRAMMES.md)
|
||||
|
||||
# Introduction au Cas d'utilisation : Suivi d'une Équipe Sportive
|
||||
|
||||
Bienvenue dans le monde dynamique du suivi d'équipe sportive, où notre application offre une plateforme complète pour les entraîneurs soucieux d'optimiser les performances de leurs athlètes. Ce diagramme de cas d'utilisation vous plonge dans les fonctionnalités clés qui facilitent la gestion d'une équipe sportive avec efficacité.
|
||||
|
||||
**Acteurs Principaux :**
|
||||
|
||||
- **Coach :** Le protagoniste central, utilisant l'application pour gérer et superviser son équipe.
|
||||
|
||||
**Fonctionnalités Clés :**
|
||||
|
||||
- **Ajouter un Athlète :** Permet au coach d'ajouter de nouveaux membres à son équipe, avec des étapes incluant la validation par l'athlète et l'authentification.
|
||||
|
||||
- **Supprimer un Athlète :** Offre la possibilité de retirer des athlètes de l'équipe, avec une authentification préalable pour garantir la légitimité de l'action.
|
||||
|
||||
- **Afficher ses Athlètes :** Permet au coach de visualiser la liste complète de ses athlètes, nécessitant une authentification pour accéder à ces informations sensibles.
|
||||
|
||||
- **Afficher les Activités de Tous les Athlètes :** Donne au coach un aperçu global des activités de toute l'équipe, nécessitant une authentification pour garantir la confidentialité des données.
|
||||
|
||||
**Flux d'Interaction :**
|
||||
|
||||
- Le processus d'ajout d'un athlète inclut des étapes telles que la validation par l'athlète et l'authentification, garantissant une intégration fluide.
|
||||
|
||||
- Les actions de suppression, affichage des athlètes et affichage des activités nécessitent une authentification préalable pour assurer la sécurité des données.
|
||||
|
||||
- Des extensions telles que la visualisation des activités d'un athlète et l'analyse des performances offrent des fonctionnalités avancées pour un suivi détaillé.
|
||||
|
||||
Explorez ce diagramme pour comprendre l'étendue des fonctionnalités que notre application offre aux entraîneurs, les aidant à gérer leurs équipes de manière efficace et à maximiser le potentiel de chaque athlète.
|
||||
|
||||
```plantuml
|
||||
left to right direction
|
||||
:Coach: as a
|
||||
|
||||
a --> (Ajouter un athlète)
|
||||
a --> (Supprimer un athlète)
|
||||
a --> (Afficher ses athlètes )
|
||||
a --> (Afficher les activités de tous les athlètes)
|
||||
(Ajouter un athlète).>(Validation par l'athlète) : <<include>>
|
||||
(Ajouter un athlète)..>(S'authentifier) : <<include>>
|
||||
(Supprimer un athlète)..>(S'authentifier) : <<include>>
|
||||
(Afficher ses athlètes )..>(S'authentifier) : <<include>>
|
||||
(Afficher les activités de tous les athlètes)..>(S'authentifier) : <<include>>
|
||||
(S'authentifier)..>(S'inscrire) : <<extends>>
|
||||
(S'inscrire).>(Inscription Coach) : <<include>>
|
||||
(S'authentifier)..>(Se connecter) : <<include>>
|
||||
(Afficher ses athlètes )..>(Voir les activités d'un athlète) : <<extends>>
|
||||
(Afficher ses athlètes )..>(Voir les stats d'un athlète) : <<extends>>
|
||||
(Afficher les activités de tous les athlètes)..>(Sélectionner une activité) : <<include>>
|
||||
(Sélectionner une activité)..>(Voir l'analyse) : <<extends>>
|
||||
(Sélectionner une activité)..>(Exporter l'analyse) : <<extends>>
|
||||
(Voir les activités d'un athlète)..>(Voir l'analyse) : <<extends>>
|
||||
(Voir les activités d'un athlète)..>(Exporter l'analyse) : <<extends>>
|
||||
```
|
@ -0,0 +1,58 @@
|
||||
[retour au README.md](../../../README.md)
|
||||
[Retour aux Documents](../../README_DOCUMENTS.md)
|
||||
[Retour au diagramme de classes](../README_DIAGRAMMES.md)
|
||||
|
||||
# Introduction au Cas d'utilisation : Gestion d'Activités pour un Athlète
|
||||
|
||||
Bienvenue dans l'univers dédié à la gestion d'activités sportives personnalisées pour les athlètes ! Ce diagramme de cas d'utilisation explore les différentes fonctionnalités offertes aux utilisateurs, mettant en avant la flexibilité et la richesse d'interactions pour une expérience utilisateur optimale.
|
||||
|
||||
**Acteurs Principaux :**
|
||||
|
||||
- **Athlète :** Le protagoniste central, utilisant l'application pour importer, gérer et analyser ses activités sportives.
|
||||
|
||||
**Fonctionnalités Clés :**
|
||||
|
||||
- **Importer des Données :** Permet à l'athlète d'importer des données d'activités depuis différentes sources, avec la possibilité de spécifier la source pour une intégration transparente.
|
||||
|
||||
- **Exporter Mes Données :** Offre la possibilité d'exporter l'ensemble des activités, avec des extensions pour exporter une activité spécifique, le tout soumis à une authentification préalable.
|
||||
|
||||
- **Ajouter une Activité :** Permet à l'athlète d'ajouter de nouvelles activités, avec des étapes inclusives telles que la saisie du titre, du type d'activité, de la source, du matériel utilisé et de la visibilité, chacune accessible via l'authentification.
|
||||
|
||||
- **Voir une Activité :** Permet à l'athlète de visualiser en détail une activité particulière, avec la possibilité d'exporter une analyse et de gérer la visibilité, soumis à une authentification.
|
||||
|
||||
- **Supprimer une Activité :** Offre la possibilité de retirer une activité, requérant une authentification pour garantir la sécurité des données.
|
||||
|
||||
**Flux d'Interaction :**
|
||||
|
||||
- Les actions telles que l'importation, l'exportation, l'ajout et la visualisation d'activités impliquent une authentification préalable pour garantir la confidentialité des données personnelles.
|
||||
|
||||
- Des inclusions précises, telles que la saisie du titre, du type d'activité, de la source, du matériel utilisé et de la visibilité, sont incorporées dans le processus d'ajout d'une activité, offrant une expérience utilisateur détaillée et conviviale.
|
||||
|
||||
Explorez ce diagramme pour comprendre la manière dont notre application place la gestion d'activités entre les mains des athlètes, les encourageant à suivre, analyser et optimiser leurs performances sportives de manière personnalisée et efficace.
|
||||
|
||||
|
||||
```plantuml
|
||||
left to right direction
|
||||
:Athlete: as a
|
||||
|
||||
a --> (Importer des données)
|
||||
(Importer des données) .> (Saisir la source) : <<include>>
|
||||
a --> (Exporter mes données)
|
||||
(Exporter mes données) .>(Exporter toutes les activités): <<extends>>
|
||||
(Exporter mes données) ..>(Exporter une activité): <<include>>
|
||||
a --> (Ajouter une activité)
|
||||
(Ajouter une activité) ..>(Saisir un titre et une description): <<include>>
|
||||
(Ajouter une activité) ..>(Saisir le type d'activité): <<include>>
|
||||
(Ajouter une activité) .>(Saisir la source): <<include>>
|
||||
(Saisir la source) ..>(Saisir le matériel utilisé): <<include>>
|
||||
(Ajouter une activité) ..>(Saisir la visibilité): <<include>>
|
||||
a --> (Voir une activité)
|
||||
(Voir une activité) ..>(Exporter l'analyse): <<extends>>
|
||||
(Voir une activité) ..>(Saisir la visibilité): <<extends>>
|
||||
a --> (Supprimer une activité)
|
||||
(Supprimer une activité) ..>(S'authentifier): <<include>>
|
||||
(Importer des données) ...>(S'authentifier): <<include>>
|
||||
(Exporter mes données) ...>(S'authentifier): <<include>>
|
||||
(Ajouter une activité) ...>(S'authentifier): <<include>>
|
||||
(Voir une activité) ...>(S'authentifier): <<include>>
|
||||
```
|
@ -0,0 +1,56 @@
|
||||
[retour au README.md](../../../README.md)
|
||||
[Retour aux Documents](../../README_DOCUMENTS.md)
|
||||
[Retour au diagramme de classes](../README_DIAGRAMMES.md)
|
||||
|
||||
# Introduction au Cas d'utilisation : Gestion des Relations Sociales pour un Athlète
|
||||
|
||||
Bienvenue dans la sphère sociale de notre application dédiée aux athlètes ! Ce diagramme de cas d'utilisation explore les fonctionnalités sociales clés offertes aux utilisateurs, mettant en lumière la connectivité et l'interaction sociale au sein de notre communauté sportive.
|
||||
|
||||
**Acteurs Principaux :**
|
||||
|
||||
- **Athlète :** Le protagoniste central, utilisant l'application pour gérer ses relations sociales et explorer les profils de ses pairs.
|
||||
|
||||
**Fonctionnalités Clés :**
|
||||
|
||||
- **Ajouter un Ami :** Permet à l'athlète d'ajouter de nouveaux amis, nécessitant la saisie du nom de l'ami et soumis à une authentification préalable.
|
||||
|
||||
- **Supprimer un Ami :** Offre la possibilité de retirer un ami, exigeant une authentification pour garantir la sécurité des données.
|
||||
|
||||
- **Voir Mes Amis :** Permet à l'athlète de visualiser la liste de ses amis, avec la possibilité d'accéder à des fonctionnalités supplémentaires comme la visualisation des profils.
|
||||
|
||||
- **Modifier Mes Informations :** Offre à l'athlète la possibilité de mettre à jour ses informations personnelles et de connexion, avec des extensions pour des détails plus spécifiques.
|
||||
|
||||
**Flux d'Interaction :**
|
||||
|
||||
- Le processus d'ajout d'un ami inclut la saisie du nom de l'ami, tandis que la suppression d'un ami et la visualisation de la liste des amis sont soumises à une authentification préalable pour protéger la confidentialité.
|
||||
|
||||
- Les modifications d'informations englobent deux extensions : la mise à jour des informations personnelles et la mise à jour des informations de connexion, offrant une personnalisation approfondie du profil athlétique.
|
||||
|
||||
- La visualisation du profil d'un ami s'étend à des fonctionnalités telles que la consultation des activités et des statistiques de l'ami, ajoutant une dimension sociale à l'expérience de suivi sportif.
|
||||
|
||||
Explorez ce diagramme pour découvrir comment notre application encourage l'interaction sociale entre les athlètes, favorisant une communauté engagée et collaborative au sein de laquelle les utilisateurs peuvent partager, interagir et se soutenir mutuellement dans leur parcours sportif.
|
||||
|
||||
|
||||
```plantuml
|
||||
left to right direction
|
||||
:Athlete: as a
|
||||
|
||||
a --> (Ajouter un ami)
|
||||
a --> (Supprimer un ami)
|
||||
a --> (Voir mes amis)
|
||||
a --> (Modifier mes informations)
|
||||
(Ajouter un ami)->(Saisir le nom de l'ami)
|
||||
(Supprimer un ami)..>(S'authentifier) : <<include>>
|
||||
(Ajouter un ami)..>(S'authentifier) : <<include>>
|
||||
(Voir mes amis)..>(S'authentifier) : <<include>>
|
||||
(Voir mes amis)..>(Lister les amis) : <<include>>
|
||||
(Modifier mes informations)..>(Informations personnelles) : <<extends>>
|
||||
(Modifier mes informations)..>(Informations de connexion) : <<extends>>
|
||||
(Modifier mes informations)..>(S'authentifier) : <<include>>
|
||||
(Lister les amis)..>(Voir son profil) : <<include>>
|
||||
(Voir son profil)..>(Voir ses activités) : <<extends>>
|
||||
(Voir son profil)..>(Voir ses statistiques) : <<extends>>
|
||||
(S'authentifier)..>(S'inscrire) : <<extends>>
|
||||
(S'authentifier)..>(Se connecter) : <<include>>
|
||||
(S'inscrire)..>(Inscription Athlète) : <<include>>
|
||||
```
|
@ -1,33 +0,0 @@
|
||||
@startuml
|
||||
class phpFITFileAnalysis
|
||||
{
|
||||
data_mesgs : array
|
||||
dev_field_descriptions : array
|
||||
options : null
|
||||
file_contents : string
|
||||
file_pointer : integer
|
||||
defn_mesgs : array
|
||||
defn_mesgs_all : array
|
||||
file_header : array
|
||||
php_trader_ext_loaded : boolean
|
||||
types : null
|
||||
garmin_timestamps : boolean
|
||||
readDataRecords : function
|
||||
fixData($options) : function
|
||||
interpolateMissingData(&$missing_keys, &$array)
|
||||
}
|
||||
|
||||
ProjectModel --|> Project
|
||||
AttributeModel --|> Element
|
||||
UMLModel --|> Element
|
||||
UMLClassDiagram --|> Element
|
||||
UMLClassView --|> View
|
||||
UMLNameCompartmentView --|> View
|
||||
UMLAttributeCompartmentView --|> View
|
||||
UMLOperationCompartmentView --|> View
|
||||
UMLReceptionCompartmentView --|> View
|
||||
UMLTemplateParameterCompartmentView --|> View
|
||||
LabelView --|> View
|
||||
|
||||
@enduml
|
||||
|
@ -0,0 +1,203 @@
|
||||
[retour au README.md](../../../README.md)
|
||||
[Retour aux Documents](../../README_DOCUMENTS.md)
|
||||
[Retour au diagramme de classes](../README_DIAGRAMMES.md)
|
||||
|
||||
# Introduction au Diagramme de Classes : Plateforme de Gestion d'Activités Sportives
|
||||
|
||||
Bienvenue dans l'écosystème dynamique de notre plateforme de gestion d'activités sportives ! Ce diagramme de classes offre une vision complète des entités et des relations qui façonnent l'expérience des utilisateurs au sein de notre système.
|
||||
|
||||
**Entités Principales :**
|
||||
|
||||
- **Utilisateur (User) :** Représente les individus inscrits sur notre plateforme, avec des détails personnels tels que le nom, le prénom, l'email, etc. Chaque utilisateur a un rôle spécifique (Athlete, Coach) qui détermine ses interactions au sein de l'application.
|
||||
|
||||
- **Rôle (Role) :** Classe abstraite qui définit les rôles spécifiques des utilisateurs (Athlete, Coach). Contient des méthodes pour gérer les amis, les entraînements, et les demandes.
|
||||
|
||||
- **Athlète (Athlete) :** Spécialisation de la classe Role, représentant les utilisateurs actifs qui enregistrent des activités sportives, des statistiques, et interagissent avec d'autres athlètes.
|
||||
|
||||
- **Activité (Activite) :** Contient des détails sur une activité sportive tels que le type, la date, la durée, la fréquence cardiaque, etc.
|
||||
|
||||
- **Notification (Notification) :** Messages pour informer les utilisateurs des actions importantes.
|
||||
|
||||
- **Entraînement (Entrainement) :** Sessions planifiées d'activités physiques avec des détails comme la date, la localisation, la description, et les retours.
|
||||
|
||||
- **Statistique (Statistique) :** Informations détaillées sur les performances sportives d'un athlète, comprenant la distance totale, le poids, le temps total, la fréquence cardiaque, etc.
|
||||
|
||||
- **Source de Données (SourceDonnees) :** Représente les sources utilisées pour collecter des données, telles que les montres connectées.
|
||||
|
||||
**Relations Clés :**
|
||||
|
||||
- Les Utilisateurs ont un rôle spécifique (Athlete, Coach) qui détermine leurs fonctionnalités.
|
||||
|
||||
- Un Athlète peut enregistrer plusieurs Activités, possède des Statistiques, et une Sources de Données qui est la plus utilisé.
|
||||
|
||||
- Les Entraînements sont liés aux Utilisateurs, permettant une planification efficace.
|
||||
|
||||
- Les Notifications informent les Utilisateurs des événements importants tels qu'une demande d'amis ou une notification d'avertissement de ban.
|
||||
|
||||
Explorez ce diagramme pour comprendre comment notre plateforme offre une expérience complète, de la gestion des utilisateurs à l'enregistrement des activités sportives et au suivi des performances.
|
||||
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
class User {
|
||||
- id: int
|
||||
- username: String
|
||||
- nom: string
|
||||
- prenom: string
|
||||
- email: string
|
||||
- motDePasse: string
|
||||
- sexe: string
|
||||
- taille: float
|
||||
- poids: float
|
||||
- dateNaissance: \DateTime
|
||||
+ getId(): int
|
||||
+ getUsername(): string
|
||||
+ setUsername(string $username): void
|
||||
+ setId(int $id): void
|
||||
+ getNom(): string
|
||||
+ setNom(string $nom): void
|
||||
+ getPrenom(): string
|
||||
+ setPrenom(string $prenom): void
|
||||
+ getEmail(): string
|
||||
+ setEmail(string $email): void
|
||||
+ getMotDePasse(): string
|
||||
+ setMotDePasse(string $motDePasse): void
|
||||
+ getSexe(): string
|
||||
+ setSexe(string $sexe): void
|
||||
+ getTaille(): float
|
||||
+ setTaille(float $taille): void
|
||||
+ getPoids(): float
|
||||
+ setPoids(float $poids): void
|
||||
+ getDateNaissance(): \DateTime
|
||||
+ setDateNaissance(\DateTime $dateNaissance): void
|
||||
+ getRole(): Role
|
||||
+ setRole(Role $role): void
|
||||
+ addNotification($notification): void
|
||||
+ deleteNotification($index): void
|
||||
+ isValidPassword(string $password): bool
|
||||
+ __toString(): string
|
||||
}
|
||||
abstract class Role {
|
||||
- id: int
|
||||
- usersRequests: array
|
||||
+ getUsersList(): array
|
||||
+ getUsersRequests(): array
|
||||
+ addUsersRequests(RelationshipRequest $request): void
|
||||
+ removeRequest(RelationshipRequest $req): bool
|
||||
+ CheckAdd(User $user): bool
|
||||
+ addUser(User $user): bool
|
||||
+ removeUser(User $user): bool
|
||||
+ addTraining(Training $training): bool
|
||||
+ getTrainingsList(): array
|
||||
}
|
||||
abstract class Coach extends Role {
|
||||
}
|
||||
class CoachAthlete extends Coach {
|
||||
+ CheckAdd(User $user): bool
|
||||
}
|
||||
class Athlete extends Role {
|
||||
+ getActivities(): array
|
||||
+ addActivity(Activity $myActivity): bool
|
||||
+ CheckAdd(User $user): bool
|
||||
}
|
||||
class Activite {
|
||||
- idActivity: int
|
||||
- type: String
|
||||
- date: \DateTime
|
||||
- heureDebut: \DateTime
|
||||
- heureFin: \DateTime
|
||||
- effortRessenti: int
|
||||
- variability: float
|
||||
- variance: float
|
||||
- standardDeviation: float
|
||||
- average: int
|
||||
- maximum: int
|
||||
- minimum: int
|
||||
- avrTemperature: float
|
||||
- hasAutoPause: bool
|
||||
+ getIdActivity(): int
|
||||
+ getType(): String
|
||||
+ getDate(): \DateTime
|
||||
+ getHeureDebut(): \DateTime
|
||||
+ getHeureFin(): \DateTime
|
||||
+ getEffortRessenti(): int
|
||||
+ getVariability(): float
|
||||
+ getVariance(): float
|
||||
+ getStandardDeviation(): float
|
||||
+ getAverage(): float
|
||||
+ getMaximum(): int
|
||||
+ getMinimum(): int
|
||||
+ getAvrTemperature(): float
|
||||
+ setType(String $type): void
|
||||
+ setEffortRessenti(int $effortRessenti): void
|
||||
+ __toString(): String
|
||||
}
|
||||
class Notification {
|
||||
- type: string
|
||||
- message: string
|
||||
- toUserId: int
|
||||
+ getType(): string
|
||||
+ setType(string $type): void
|
||||
+ getMessage(): string
|
||||
+ setMessage(string $message): void
|
||||
+ getToUserId(): int
|
||||
+ setToUserId(int $toUserId): void
|
||||
+ __construct(int $toUserId,string $type, string $message)
|
||||
+ __toString(): string
|
||||
}
|
||||
class Entrainement {
|
||||
- idTraining: int
|
||||
- date: \DateTime
|
||||
- latitude: float
|
||||
- longitude: float
|
||||
- description: String
|
||||
- feedback: String
|
||||
+ getId(): int
|
||||
+ getDate(): \DateTime
|
||||
+ getLocation(): String
|
||||
+ getDescription(): String
|
||||
+ getFeedback(): String
|
||||
+ __toString(): String
|
||||
}
|
||||
class Statistique {
|
||||
- idStat: int
|
||||
- distanceTotale: float
|
||||
- poids: float
|
||||
- tempsTotal: time
|
||||
- FCmoyenne: int
|
||||
- FCmin: int
|
||||
- FCmax: int
|
||||
- cloriesBrulees: int
|
||||
+ getIdStat(): int
|
||||
+ getDistanceTotale(): float
|
||||
+ getPoids(): float
|
||||
+ getTempsTotal(): time
|
||||
+ getFCmoyenne(): int
|
||||
+ getFCmin(): int
|
||||
+ getFCmax(): int
|
||||
+ getCloriesBrulees(): int
|
||||
+ __toString(): String
|
||||
}
|
||||
class SourceDonnees {
|
||||
- idSource: int
|
||||
- nom: String
|
||||
- type: String
|
||||
- precision: enum
|
||||
- dateDerniereUtilisation: \DateTime
|
||||
+ getIdSource(): int
|
||||
+ getNom(): String
|
||||
+ getType(): String
|
||||
+ getPrecision(): enum
|
||||
+ getDateDerniereUtilisation(): \DateTime
|
||||
+ __toString(): String
|
||||
}
|
||||
User -> Role : role
|
||||
Role -> User : usersList
|
||||
Athlete -> Statistique : statsList
|
||||
Athlete -> Activite : activityList
|
||||
Athlete -> SourceDonnees : sdList
|
||||
User -> Notification : notificationList
|
||||
User -> Entrainement : trainingsList
|
||||
Activite -> SourceDonnees : maSource
|
||||
@enduml
|
||||
```
|
@ -0,0 +1,91 @@
|
||||
[retour au README.md](../../../README.md)
|
||||
[Retour aux Documents](../../README_DOCUMENTS.md)
|
||||
[Retour au diagramme de classes](../README_DIAGRAMMES.md)
|
||||
|
||||
# Introduction au Diagramme de la Couche d'Accès aux Données
|
||||
|
||||
Bienvenue dans le cœur de notre système, où les données prennent vie à travers des ensembles de données (repositories) structurés et performants. Ce diagramme met en lumière la conception de la couche d'accès aux données de notre application, offrant un aperçu clair de la gestion des entités clées telles que les utilisateurs, les notifications, les demandes de relations et les entraînements.
|
||||
|
||||
**Principes Fondamentaux :**
|
||||
|
||||
- **IGenericRepository :** Une abstraction générique établissant les contrats essentiels pour l'accès aux données. Définissant des opérations standardisées telles que la récupération, la mise à jour, l'ajout et la suppression d'entités.
|
||||
|
||||
- **Interfaces Spécialisées :** Des interfaces telles que `IUserRepository`, `INotificationRepository`, `IRelationshipRequestRepository` et `ITrainingRepository` étendent les fonctionnalités génériques pour répondre aux besoins spécifiques de chaque entité.
|
||||
|
||||
**Repositories Concrets :**
|
||||
|
||||
- **UserRepository :** Gère les données relatives aux utilisateurs, permettant des opérations de récupération, de mise à jour et de suppression avec une efficacité optimale.
|
||||
|
||||
- **NotificationRepository :** Responsable de la gestion des notifications, assurant un accès structuré et une manipulation sécurisée de ces informations cruciales.
|
||||
|
||||
- **RelationshipRequestRepository :** Facilite la gestion des demandes de relations entre utilisateurs (amitiés), garantissant une interaction claire et ordonnée au sein de l'application.
|
||||
|
||||
- **TrainingRepository :** Permet l'accès et la manipulation des données liées aux entraînements, facilitant le suivi des performances athlétiques.
|
||||
|
||||
Explorez ce diagramme pour découvrir la robustesse de notre architecture de gestion des données, mettant en œuvre des pratiques de développement SOLID pour assurer une expérience utilisateur fiable et évolutive.
|
||||
|
||||
```plantuml
|
||||
@startuml couche_acces_aux_donnees
|
||||
interface IGenericRepository {
|
||||
+ getItemById(int id) : object
|
||||
+ getNbItems() : int
|
||||
+ getItems(int index, int count, string orderingPropertyName, bool descending) : array
|
||||
+ getItemsByName(string substring, int index, int count, string orderingPropertyName, bool descending) : array
|
||||
+ getItemByName(string substring, int index, int count, string orderingPropertyName, bool descending) : object
|
||||
+ updateItem(oldItem, newItem) : void
|
||||
+ addItem(item) : void
|
||||
+ deleteItem(item) : bool
|
||||
}
|
||||
interface IUserRepository extends IGenericRepository {
|
||||
}
|
||||
interface INotificationRepository extends IGenericRepository {
|
||||
}
|
||||
interface IRelationshipRequestRepository extends IGenericRepository {
|
||||
}
|
||||
interface ITrainingRepository extends IGenericRepository {
|
||||
}
|
||||
class NotificationRepository implements INotificationRepository {
|
||||
- notifications : array
|
||||
+ getItemById(int id) : object
|
||||
+ getNbItems() : int
|
||||
+ getItems(int index, int count, string orderingPropertyName, bool descending) : array
|
||||
+ getItemsByName(string substring, int index, int count, string orderingPropertyName, bool descending) : array
|
||||
+ getItemByName(string substring, int index, int count, string orderingPropertyName, bool descending) : object
|
||||
+ updateItem(oldItem, newItem) : void
|
||||
+ addItem(item) : void
|
||||
+ deleteItem(item) : bool
|
||||
}
|
||||
class RelationshipRequestRepository implements IRelationshipRequestRepository {
|
||||
- requests : array
|
||||
+ getItemById(int id) : object
|
||||
+ getNbItems() : int
|
||||
+ getItems(int index, int count, string orderingPropertyName, bool descending) : array
|
||||
+ getItemsByName(string substring, int index, int count, string orderingPropertyName, bool descending) : array
|
||||
+ getItemByName(string substring, int index, int count, string orderingPropertyName, bool descending) : object
|
||||
+ updateItem(oldItem, newItem) : void
|
||||
+ addItem(item) : void
|
||||
+ deleteItem(item) : bool
|
||||
}
|
||||
class TrainingRepository implements ITrainingRepository {
|
||||
- trainings : array
|
||||
+ getItemById(int id) : object
|
||||
+ getNbItems() : int
|
||||
+ getItems(int index, int count, string orderingPropertyName, bool descending) : array
|
||||
+ getItemsByDate(date, int index, int count, string orderingPropertyName, bool descending) : array
|
||||
+ updateItem(oldItem, newItem) : void
|
||||
+ addItem(item) : void
|
||||
+ deleteItem(item) : bool
|
||||
}
|
||||
class UserRepository implements IUserRepository {
|
||||
- users : array
|
||||
+ getItemById(int id) : object
|
||||
+ getNbItems() : int
|
||||
+ getItems(int index, int count, string orderingPropertyName, bool descending) : array
|
||||
+ getItemsByName(string substring, int index, int count, string orderingPropertyName, bool descending) : array
|
||||
+ getItemByName(string substring, int index, int count, string orderingPropertyName, bool descending) : object
|
||||
+ updateItem(oldItem, newItem) : void
|
||||
+ addItem(item) : void
|
||||
+ deleteItem(item) : bool
|
||||
}
|
||||
@enduml
|
||||
```
|
@ -1,21 +0,0 @@
|
||||
[retour au README.md](../../../README.md)
|
||||
[Retour aux Documents](../../README_DOCUMENTS.md)
|
||||
|
||||
## Diagramme de séquence systeme
|
||||
- Création de compte
|
||||
```plantuml
|
||||
actor User as u
|
||||
u->Systeme : demandePageConnexion()
|
||||
alt User déjà connecté
|
||||
Systeme-->u : redirectionPageCompte()
|
||||
end
|
||||
Systeme-->u : PageConnexion()
|
||||
alt User possède déjà un compte
|
||||
u->Systeme:InfosConnexion()
|
||||
else
|
||||
u->Systeme:CreerCompte()
|
||||
Systeme-->u :PageCreationCompte()
|
||||
u->Systeme:InfosCreationCompte()
|
||||
end
|
||||
Systeme-->u :Connecter()
|
||||
```
|
@ -1,182 +1,201 @@
|
||||
[retour au README.md](../../../README.md)
|
||||
[Retour aux Documents](../../README_DOCUMENTS.md)
|
||||
[Retour aux Documents](../../README_DOCUMENTS.md)
|
||||
[Retour au diagramme de classes](../README_DIAGRAMMES.md)
|
||||
|
||||
# Introduction au Modèle de Données de l'Application
|
||||
|
||||
L'architecture de données de notre application de suivi d'activités sportives repose sur un modèle robuste, avec des entités clés pour représenter les activités, les athlètes et les coachs et la récupération de ces données au sein de notre application. Découvrez les composants principaux de notre modèle de données :
|
||||
|
||||
## Activité
|
||||
L'entité Activité représente une session d'activité sportive avec des détails variés tels que le type d'activité, la date, la durée, l'effort ressenti, etc. Le `ActiviteEntity` encapsule ces données, tandis que le `ActiviteGateway` gère la communication avec la base de données pour les activités.
|
||||
|
||||
## Athlète
|
||||
L'entité Athlète représente un utilisateur de l'application qui participe à des activités sportives. Le `AthleteEntity` stocke les détails de l'athlète, et le `AtheletGateway` facilite l'accès et la gestion des données des athlètes.
|
||||
|
||||
## Coach
|
||||
L'entité Coach représente un utilisateur qui peut superviser et coacher d'autres athlètes. Le `CoachEntity` stocke les détails du coach, tandis que le `CoachGateway` gère les interactions avec la base de données.
|
||||
|
||||
## Mapper
|
||||
Les mappers, tels que `ActiviteMapper`, `AthleteMapper`, et `CoachMapper`, facilitent la conversion entre les entités et les modèles utilisés dans l'application.
|
||||
|
||||
## Connexion à la Base de Données
|
||||
La classe `Connection` étend de `PDO` et assure la connexion à la base de données. Chaque Gateway utilise cette connexion pour interagir avec la base de données.
|
||||
|
||||
|
||||
## Diagramme de classe
|
||||
```plantuml
|
||||
@startuml
|
||||
class ActiviteEntity {
|
||||
- idActivite
|
||||
- type
|
||||
- date
|
||||
- heureDebut
|
||||
- heureFin
|
||||
- effortRessenti
|
||||
- variabilite
|
||||
- variance
|
||||
- ecartType
|
||||
- moyenne
|
||||
- maximum
|
||||
- minimum
|
||||
- temperatureMoyenne
|
||||
+ getIdActivite()
|
||||
+ getType()
|
||||
+ getDate()
|
||||
+ getHeureDebut()
|
||||
+ getHeureFin()
|
||||
+ getEffortRessenti()
|
||||
+ getVariabilite()
|
||||
+ getVariance()
|
||||
+ getEcartType()
|
||||
+ getMoyenne()
|
||||
+ getMaximum()
|
||||
+ getMinimum()
|
||||
+ getTemperatureMoyenne()
|
||||
+ setIdActivite(idActivite)
|
||||
+ setType(type)
|
||||
+ setDate(date)
|
||||
+ setHeureDebut(heureDebut)
|
||||
+ setHeureFin(heureFin)
|
||||
+ setEffortRessenti(effortRessenti)
|
||||
+ setVariabilite(variabilite)
|
||||
+ setVariance(variance)
|
||||
+ setEcartType(ecartType)
|
||||
+ setMoyenne(moyenne)
|
||||
+ setMaximum(maximum)
|
||||
+ setMinimum(minimum)
|
||||
+ setTemperatureMoyenne(temperatureMoyenne)
|
||||
- idActivite: int
|
||||
- type: string
|
||||
- date: string
|
||||
- heureDebut: string
|
||||
- heureFin: string
|
||||
- effortRessenti: int
|
||||
- variabilite: int
|
||||
- variance: int
|
||||
- ecartType: int
|
||||
- moyenne: int
|
||||
- maximum: int
|
||||
- minimum: int
|
||||
- temperatureMoyenne: int
|
||||
+ getIdActivite(): int
|
||||
+ getType(): string
|
||||
+ getDate(): string
|
||||
+ getHeureDebut(): string
|
||||
+ getHeureFin(): string
|
||||
+ getEffortRessenti(): int
|
||||
+ getVariabilite(): int
|
||||
+ getVariance(): int
|
||||
+ getEcartType(): int
|
||||
+ getMoyenne(): int
|
||||
+ getMaximum(): int
|
||||
+ getMinimum(): int
|
||||
+ getTemperatureMoyenne(): int
|
||||
+ setIdActivite(idActivite: int): void
|
||||
+ setType(type: string): void
|
||||
+ setDate(date: string): void
|
||||
+ setHeureDebut(heureDebut: string): void
|
||||
+ setHeureFin(heureFin: string): void
|
||||
+ setEffortRessenti(effortRessenti: int): void
|
||||
+ setVariabilite(variabilite: int): void
|
||||
+ setVariance(variance: int): void
|
||||
+ setEcartType(ecartType: int): void
|
||||
+ setMoyenne(moyenne: int): void
|
||||
+ setMaximum(maximum: int): void
|
||||
+ setMinimum(minimum: int): void
|
||||
+ setTemperatureMoyenne(temperatureMoyenne: int): void
|
||||
}
|
||||
|
||||
class ActiviteGateway {
|
||||
- connection
|
||||
+ __construct(connection: Connection)
|
||||
+ getActivite()
|
||||
+ getActiviteById(activiteId: int)
|
||||
+ getActiviteByType(type: string)
|
||||
+ getActiviteByDate(date: string)
|
||||
+ getActiviteByTimeRange(startTime: string, endTime: string)
|
||||
+ getActiviteByEffort(effortRessenti: int)
|
||||
+ getActiviteByVariability(variabilite: int)
|
||||
+ getActiviteByTemperature(temperatureMoyenne: int)
|
||||
+ addActivite(activite: ActiviteEntity)
|
||||
+ updateActivite(oldActivite: ActiviteEntity, newActivite: ActiviteEntity)
|
||||
+ deleteActivite(idActivite: int)
|
||||
+ getActivite(): ?array
|
||||
+ getActiviteById(activiteId: int): ?array
|
||||
+ getActiviteByType(type: string): ?array
|
||||
+ getActiviteByDate(date: string): ?array
|
||||
+ getActiviteByTimeRange(startTime: string, endTime: string): ?array
|
||||
+ getActiviteByEffort(effortRessenti: int): ?array
|
||||
+ getActiviteByVariability(variabilite: int): ?array
|
||||
+ getActiviteByTemperature(temperatureMoyenne: int): ?array
|
||||
+ addActivite(activite: ActiviteEntity): bool
|
||||
+ updateActivite(oldActivite: ActiviteEntity, newActivite: ActiviteEntity): bool
|
||||
+ deleteActivite(idActivite: int): bool
|
||||
}
|
||||
|
||||
class ActiviteMapper {
|
||||
+ map(data: array): ActiviteEntity
|
||||
+ ActiviteEntityToModel(activiteEntity: ActiviteEntity): Activite
|
||||
}
|
||||
|
||||
class AthleteEntity {
|
||||
+ getIdAthlete()
|
||||
+ getNom()
|
||||
+ getPrenom()
|
||||
+ getEmail()
|
||||
+ getSexe()
|
||||
+ getTaille()
|
||||
+ getPoids()
|
||||
+ getMotDePasse()
|
||||
+ getDateNaissance()
|
||||
+ setIdAthlete(idAthlete)
|
||||
+ setNom(nom)
|
||||
+ setPrenom(prenom)
|
||||
+ setEmail(email)
|
||||
+ setSexe(sexe)
|
||||
+ setTaille(taille)
|
||||
+ setPoids(poids)
|
||||
+ setMotDePasse(motDePasse)
|
||||
+ setDateNaissance(dateNaissance)
|
||||
- idAthlete: int
|
||||
- nom: string
|
||||
- prenom: string
|
||||
- email: string
|
||||
- sexe: string
|
||||
- taille: float
|
||||
- poids: float
|
||||
- motDePasse: string
|
||||
- dateNaissance: string
|
||||
+ getIdAthlete(): int
|
||||
+ getNom(): string
|
||||
+ getPrenom(): string
|
||||
+ getEmail(): string
|
||||
+ getSexe(): string
|
||||
+ getTaille(): float
|
||||
+ getPoids(): float
|
||||
+ getMotDePasse(): string
|
||||
+ getDateNaissance(): string
|
||||
+ setIdAthlete(idAthlete: int): void
|
||||
+ setNom(nom: string): void
|
||||
+ setPrenom(prenom: string): void
|
||||
+ setEmail(email: string): void
|
||||
+ setSexe(sexe: string): void
|
||||
+ setTaille(taille: float): void
|
||||
+ setPoids(poids: float): void
|
||||
+ setMotDePasse(motDePasse: string): void
|
||||
+ setDateNaissance(dateNaissance: string): void
|
||||
}
|
||||
|
||||
class AthleteGateway {
|
||||
- connection: Connexion
|
||||
+ __construct(connection: Connexion)
|
||||
+ getAthlete(): array
|
||||
+ getAthleteById(userId: int): array
|
||||
+ getAthleteByName(name: string): array
|
||||
+ getAthleteByFirstName(firstName: string): array
|
||||
+ getAthleteByEmail(email: string): array
|
||||
+ getAthleteByGender(gender: string): array
|
||||
+ getAthleteByHeight(height: int): array
|
||||
+ getAthleteByWeight(weight: int): array
|
||||
+ getAthleteByBirthDate(birthdate: string): array
|
||||
class AtheletGateway {
|
||||
+ __construct(connection: Connection)
|
||||
+ getAthlete(): ?array
|
||||
+ getAthleteById(userId: int): ?array
|
||||
+ getAthleteByName(name: string): ?array
|
||||
+ getAthleteByFirstName(firstName: string): ?array
|
||||
+ getAthleteByEmail(email: string): ?array
|
||||
+ getAthleteByGender(gender: string): ?array
|
||||
+ getAthleteByHeight(height: int): ?array
|
||||
+ getAthleteByWeight(weight: int): ?array
|
||||
+ getAthleteByBirthDate(birthdate: string): ?array
|
||||
+ addAthlete(athlete: AthleteEntity): bool
|
||||
+ updateAthlete(oldAthlete: AthleteEntity, newAthlete: AthleteEntity): bool
|
||||
+ deleteAthlete(idAthlete: int): bool
|
||||
}
|
||||
|
||||
class AthleteMapper {
|
||||
+ fromSqlToEntity(data: array): array
|
||||
+ athleteEntityToModel(athleteEntity: AthleteEntity): User
|
||||
+ athleteToEntity(user: User): AthleteEntity
|
||||
}
|
||||
|
||||
class CoachEntity {
|
||||
- idCoach
|
||||
- nom
|
||||
- prenom
|
||||
- email
|
||||
- sexe
|
||||
- taille
|
||||
- poids
|
||||
- motDePasse
|
||||
- dateNaissance
|
||||
|
||||
+ getIdCoach()
|
||||
+ getNom()
|
||||
+ getPrenom()
|
||||
+ getEmail()
|
||||
+ getSexe()
|
||||
+ getTaille()
|
||||
+ getPoids()
|
||||
+ getMotDePasse()
|
||||
+ getDateNaissance()
|
||||
|
||||
+ setIdCoach(idCoach)
|
||||
+ setNom(nom)
|
||||
+ setPrenom(prenom)
|
||||
+ setEmail(email)
|
||||
+ setSexe(sexe)
|
||||
+ setTaille(taille)
|
||||
+ setPoids(poids)
|
||||
+ setMotDePasse(motDePasse)
|
||||
+ setDateNaissance(dateNaissance)
|
||||
- idCoach: int
|
||||
- nom: string
|
||||
- prenom: string
|
||||
- email: string
|
||||
- sexe: string
|
||||
- taille: float
|
||||
- poids: float
|
||||
- motDePasse: string
|
||||
- dateNaissance: string
|
||||
+ getIdCoach(): int
|
||||
+ getNom(): string
|
||||
+ getPrenom(): string
|
||||
+ getEmail(): string
|
||||
+ getSexe(): string
|
||||
+ getTaille(): float
|
||||
+ getPoids(): float
|
||||
+ getMotDePasse(): string
|
||||
+ getDateNaissance(): string
|
||||
+ setIdCoach(idCoach: int): void
|
||||
+ setNom(nom: string): void
|
||||
+ setPrenom(prenom: string): void
|
||||
+ setEmail(email: string): void
|
||||
+ setSexe(sexe: string): void
|
||||
+ setTaille(taille: float): void
|
||||
+ setPoids(poids: float): void
|
||||
+ setMotDePasse(motDePasse: string): void
|
||||
+ setDateNaissance(dateNaissance: string): void
|
||||
}
|
||||
|
||||
class CoachGateway {
|
||||
- connection: Connexion
|
||||
|
||||
+ __construct(connection: Connexion)
|
||||
+ getCoach(): array
|
||||
+ getCoachById(userId: int): array
|
||||
+ getCoachByName(name: string): array
|
||||
+ getCoachByFirstName(firstName: string): array
|
||||
+ getCoachByEmail(email: string): array
|
||||
+ getCoachByGender(gender: string): array
|
||||
+ getCoachByHeight(height: int): array
|
||||
+ getCoachByBirthDate(birthdate: string): array
|
||||
+ __construct(connection: Connection)
|
||||
+ getCoach(): ?array
|
||||
+ getCoachById(userId: int): ?array
|
||||
+ getCoachByName(name: string): ?array
|
||||
+ getCoachByFirstName(firstName: string): ?array
|
||||
+ getCoachByEmail(email: string): ?array
|
||||
+ getCoachByGender(gender : string): ?array
|
||||
+ getCoachByHeight(height: int): ?array
|
||||
+ getCoachByBirthDate(birthdate: string): ?array
|
||||
+ addCoach(coach: CoachEntity): bool
|
||||
+ updateCoach(oldCoach: CoachEntity, newCoach: CoachEntity): bool
|
||||
+ deleteCoach(idCoach: int): bool
|
||||
}
|
||||
|
||||
class CoachMapper {
|
||||
+map(data: array): CoachEntity
|
||||
+CoachEntityToModel(coachEntity: CoachEntity): User
|
||||
+CoachToEntity(user: User): CoachEntity
|
||||
+ map(data: array): CoachEntity
|
||||
+ CoachEntityToModel(coachEntity: CoachEntity): User
|
||||
+ CoachToEntity(user: User): CoachEntity
|
||||
}
|
||||
class Connection extends PDO {
|
||||
- stmt
|
||||
+ __construct(dsn: string, username: string, password: string)
|
||||
+ executeQuery(query: string, parameters: array): bool
|
||||
+ executeWithErrorHandling(query: string, params: array): array
|
||||
+ getResults(): array
|
||||
}
|
||||
|
||||
ActiviteEntity --o AthleteEntity
|
||||
ActiviteEntity --o CoachEntity
|
||||
AthleteEntity --o ActiviteEntity
|
||||
CoachEntity --o ActiviteEntity
|
||||
|
||||
AthleteEntity --|> User
|
||||
CoachEntity --|> User
|
||||
|
||||
ActiviteMapper --o ActiviteEntity
|
||||
AthleteMapper --o AthleteEntity
|
||||
AthleteMapper --|> User
|
||||
CoachMapper --o CoachEntity
|
||||
CoachMapper --|> User
|
||||
|
||||
```
|
||||
Connection <- ActiviteGateway : connection
|
||||
Connection <- AtheletGateway : connection
|
||||
Connection <- CoachGateway : connection
|
||||
AthleteMapper -> AthleteEntity
|
||||
CoachMapper -> CoachEntity
|
||||
ActiviteMapper -> ActiviteEntity
|
||||
ActiviteMapper -> ActiviteGateway
|
||||
CoachMapper -> CoachGateway
|
||||
AthleteMapper -> AtheletGateway
|
||||
@enduml
|
||||
```
|
After Width: | Height: | Size: 35 KiB |
@ -0,0 +1,50 @@
|
||||
[retour au README.md](../../../README.md)
|
||||
[Retour aux Documents](../../README_DOCUMENTS.md)
|
||||
[Retour au diagramme de classes](../README_DIAGRAMMES.md)
|
||||
|
||||
# Introduction au Diagramme de Séquence : Gestion des Demandes d'Amis
|
||||
|
||||
Bienvenue dans le processus dynamique de gestion des demandes d'amis au sein de notre application ! Ce diagramme de séquence met en évidence les étapes clés impliquées dans la gestion des demandes d'amis entre utilisateurs.
|
||||
|
||||
**Acteurs Principaux :**
|
||||
|
||||
- **Utilisateur (u) :** L'individu interagissant avec l'application, recevant et répondant aux demandes d'amis.
|
||||
|
||||
**Flux d'Interaction :**
|
||||
|
||||
1. **Réception d'une Demande d'Ami :** Lorsqu'un utilisateur reçoit une demande d'ami, le modèle (Model) notifie le contrôleur (Controller) de la nouvelle demande, spécifiant l'identifiant de l'utilisateur émetteur.
|
||||
|
||||
2. **Affichage de la Demande d'Ami :** Le contrôleur transmet l'information à la vue (View), qui affiche la demande d'ami à l'utilisateur.
|
||||
|
||||
3. **Affichage de la Page des Demandes d'Amis :** L'utilisateur visualise la page des demandes d'amis dans l'interface utilisateur.
|
||||
|
||||
4. **Réponse à la Demande d'Ami :** L'utilisateur prend une décision quant à la demande d'ami, en répondant par un choix binaire (accepter ou refuser).
|
||||
|
||||
5. **Enregistrement de la Réponse :** La vue (View) transmet la réponse de l'utilisateur au contrôleur, qui enregistre cette réponse.
|
||||
|
||||
6. **Envoi de la Réponse :** Le contrôleur communique avec le modèle pour envoyer la réponse, indiquant si la demande a été acceptée (true) ou refusée (false).
|
||||
|
||||
À travers ce diagramme de séquence, découvrez comment notre application gère efficacement le processus de gestion des demandes d'amis, offrant aux utilisateurs une expérience transparente et réactive lors de l'établissement de connexions sociales au sein de la plateforme.
|
||||
|
||||
````plantuml
|
||||
@startuml
|
||||
actor User as u
|
||||
boundary View as v
|
||||
control Controller as c
|
||||
entity Model as m
|
||||
|
||||
m-->c: pendingRequests: Request[]
|
||||
|
||||
c-->v: DisplayPendingRequests(pendingRequests)
|
||||
v-->u: Show Friend Requests
|
||||
|
||||
u->v: RespondToRequest(requestId, response)
|
||||
v-->c: RecordResponse(requestId, response)
|
||||
|
||||
c->m: UpdateRequestStatus(requestId, response)
|
||||
m-->c: updateStatus: success/failure
|
||||
c-->v: NotifyUpdateResult(updateStatus)
|
||||
v-->u: Show Response Result
|
||||
|
||||
@enduml
|
||||
``````
|
@ -0,0 +1,31 @@
|
||||
[retour au README.md](../../../README.md)
|
||||
[Retour aux Documents](../../README_DOCUMENTS.md)
|
||||
[Retour au diagramme de classes](../README_DIAGRAMMES.md)
|
||||
|
||||
# Introduction au Diagramme de Séquence : Recherche d'Amis
|
||||
|
||||
Bienvenue dans le processus dynamique de recherche d'amis au sein de notre application ! Ce diagramme de séquence met en lumière les étapes clés impliquées lorsque les utilisateurs recherchent des amis en utilisant un pseudo spécifique.
|
||||
|
||||
**Acteurs Principaux :**
|
||||
|
||||
- **Utilisateur (u) :** L'individu interagissant avec l'application, initié à la recherche d'amis.
|
||||
|
||||
**Flux d'Interaction :**
|
||||
|
||||
1. **Accès à la Fonctionnalité de Recherche :** L'utilisateur déclenche la fonctionnalité de recherche d'amis depuis son interface utilisateur.
|
||||
|
||||
2. **Saisie du Pseudo :** L'utilisateur entre le pseudo de l'ami qu'il souhaite rechercher.
|
||||
|
||||
3. **Requête de Recherche :** La vue (View) transmet la demande de recherche au contrôleur (Controller), qui déclenche une requête GET au serveur pour récupérer la liste des amis correspondant au pseudo saisi.
|
||||
|
||||
4. **Traitement de la Requête :** Le modèle (Model) récupère la liste d'amis correspondante en utilisant l'identifiant de l'utilisateur et notifie le contrôleur du résultat.
|
||||
|
||||
5. **Notification des Utilisateurs :** Le modèle informe également les utilisateurs concernés (émetteur et destinataire) de l'action de recherche effectuée.
|
||||
|
||||
6. **Rendu de la Vue :** Le contrôleur reçoit la liste d'amis du modèle et rend cette liste à la vue.
|
||||
|
||||
7. **Affichage des Résultats :** La vue affiche les résultats de la recherche à l'utilisateur, montrant les amis qui correspondent au pseudo saisi.
|
||||
|
||||
À travers ce diagramme de séquence, découvrez comment notre application facilite le processus de recherche d'amis, fournissant aux utilisateurs une interface conviviale et réactive pour élargir leur réseau social au sein de la plateforme.
|
||||
|
||||
<img src="AjouterAmis.png" alt="Diagramme de Séquence : Recherche d'Amis" width="1000"/>
|
@ -0,0 +1,41 @@
|
||||
[retour au README.md](../../../README.md)
|
||||
[Retour aux Documents](../../README_DOCUMENTS.md)
|
||||
[Retour au diagramme de classes](../README_DIAGRAMMES.md)
|
||||
|
||||
# Introduction au Processus de Connexion sur la Plateforme
|
||||
|
||||
Bienvenue sur notre plateforme de gestion d'activités sportives ! Pour offrir une expérience fluide et sécurisée, nous avons mis en place un processus de connexion intuitif. Découvrez comment accéder à votre compte ou créer un nouveau compte en quelques étapes simples.
|
||||
|
||||
**Étapes du Processus :**
|
||||
|
||||
1. **Demande de Page de Connexion :** L'utilisateur démarre en exprimant le désir de se connecter à la plateforme.
|
||||
|
||||
2. **Vérification de la Connexion Préexistante :** Le système vérifie si l'utilisateur est déjà connecté. En cas de connexion active, l'utilisateur est redirigé directement vers sa page de compte.
|
||||
|
||||
3. **Page de Connexion :** Si l'utilisateur n'est pas encore connecté, il est dirigé vers la page de connexion, où il peut saisir ses informations d'identification.
|
||||
|
||||
4. **Choix pour les Utilisateurs Possédant un Compte :** Si l'utilisateur a déjà un compte, il peut fournir ses informations de connexion existantes.
|
||||
|
||||
5. **Création de Compte pour les Nouveaux Utilisateurs :** Pour ceux qui n'ont pas encore de compte, l'option de création de compte est disponible. L'utilisateur peut fournir les détails nécessaires pour créer son compte.
|
||||
|
||||
6. **Page de Création de Compte :** Une page dédiée guide l'utilisateur tout au long du processus de création de compte, lui permettant de saisir les informations nécessaires.
|
||||
|
||||
7. **Validation et Connexion :** Une fois que les informations de connexion ou de création de compte sont fournies, le système procède à la vérification et connecte l'utilisateur à son compte.
|
||||
|
||||
|
||||
```plantuml
|
||||
actor User as u
|
||||
u->Systeme : demandePageConnexion()
|
||||
alt User déjà connecté
|
||||
Systeme-->u : redirectionPageCompte()
|
||||
end
|
||||
Systeme-->u : PageConnexion()
|
||||
alt User possède déjà un compte
|
||||
u->Systeme:InfosConnexion()
|
||||
else
|
||||
u->Systeme:CreerCompte()
|
||||
Systeme-->u :PageCreationCompte()
|
||||
u->Systeme:InfosCreationCompte()
|
||||
end
|
||||
Systeme-->u :Connecter()
|
||||
```
|
@ -0,0 +1,64 @@
|
||||
[retour au README.md](../../../README.md)
|
||||
[Retour aux Documents](../../README_DOCUMENTS.md)
|
||||
[Retour au diagramme de classes](../README_DIAGRAMMES.md)
|
||||
|
||||
# Introduction au Diagramme de Séquence : Gestion des Amis
|
||||
|
||||
Bienvenue dans le processus dynamique de gestion des amis au sein de notre application ! Ce diagramme de séquence met en lumière les interactions entre l'utilisateur et l'application, ainsi que le flux d'informations entre les différentes composantes du système.
|
||||
|
||||
**Acteurs Principaux :**
|
||||
|
||||
- **Utilisateur (u) :** L'individu interagissant avec l'application, souhaitant consulter et gérer sa liste d'amis.
|
||||
|
||||
**Flux d'Interaction :**
|
||||
|
||||
1. **Demande de la Page d'Amis :** L'utilisateur déclenche la demande de la page d'amis, amorçant le processus d'affichage de sa liste d'amis.
|
||||
|
||||
2. **Récupération des Amis :** Le contrôleur (Controller) reçoit la demande et interagit avec le modèle (Model) pour récupérer la liste d'amis associée à l'identifiant de l'utilisateur.
|
||||
|
||||
- *Cas de Récupération Réussi :* Si la récupération est réussie, le modèle transmet la liste d'amis au contrôleur.
|
||||
|
||||
- *Cas d'Échec de Récupération :* En cas d'échec, une notification d'erreur est renvoyée.
|
||||
|
||||
3. **Affichage de la Liste d'Amis :** Le contrôleur rend la vue (View) en utilisant la liste d'amis récupérée, qui est ensuite affichée à l'utilisateur.
|
||||
|
||||
4. **Suppression d'un Ami :** L'utilisateur décide de supprimer un ami spécifique en cliquant sur l'option correspondante.
|
||||
|
||||
5. **Traitement de la Suppression :** Le contrôleur, en réponse à la demande de suppression, envoie une requête au modèle pour effectuer la suppression de l'ami identifié par son identifiant utilisateur (idUser).
|
||||
|
||||
- *Cas de Suppression Réussie :* Si la suppression est réussie, le modèle renvoie la liste d'amis mise à jour.
|
||||
|
||||
- *Cas d'Échec de Suppression :* En cas d'échec, une notification d'erreur est renvoyée.
|
||||
|
||||
6. **Affichage de la Liste d'Amis Mise à Jour :** La vue est mise à jour avec la nouvelle liste d'amis, qui est ensuite affichée à l'utilisateur.
|
||||
|
||||
À travers ce diagramme de séquence, découvrez comment notre application gère de manière fluide et réactive les interactions de l'utilisateur avec sa liste d'amis, garantissant une expérience utilisateur cohérente et sans heurts.
|
||||
|
||||
```plantuml
|
||||
actor User as u
|
||||
boundary View as v
|
||||
control Controller as c
|
||||
entity Model as m
|
||||
|
||||
u->v: Request Friends Page
|
||||
v->c: Get /Friends
|
||||
c->m: getFriends(userId)
|
||||
alt successful retrieval
|
||||
m-->c: friendsList: User[]
|
||||
else retrieval failed
|
||||
m-->c: error
|
||||
end
|
||||
c-->v: renderView(friendsList)
|
||||
v-->u: Display Friends
|
||||
|
||||
u->v: clickDeleteFriend(idUser)
|
||||
v->c: Post: deleteFriend(idUser)
|
||||
c->m: deleteFriend(idUser)
|
||||
alt successful deletion
|
||||
m-->c: updatedFriendsList: User[]
|
||||
else deletion failed
|
||||
m-->c: error
|
||||
end
|
||||
c-->v: renderView(updatedFriendsList)
|
||||
v-->u: Display Updated Friends
|
||||
```
|
@ -1,17 +1,2 @@
|
||||
# Activer la réécriture d'URL
|
||||
RewriteEngine On
|
||||
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
|
||||
RewriteRule ^ index.php [QSA,L]
|
||||
|
||||
<Files *>
|
||||
Order Allow,Deny
|
||||
Deny from all
|
||||
</Files>
|
||||
|
||||
<Files .htaccess>
|
||||
Order Allow,Deny
|
||||
Deny from all
|
||||
</Files>
|
||||
AddType text/css .css
|
||||
AddType application/javascript .js
|
@ -1,19 +1,31 @@
|
||||
FROM php:8.2-apache
|
||||
FROM php:8.2-apache as base
|
||||
# Installation de dépendances nécessaires pour Composer
|
||||
RUN apt-get update && apt-get install -y \
|
||||
git \
|
||||
unzip
|
||||
|
||||
# Installation de Composer
|
||||
# TODO : should use a image with composer install
|
||||
|
||||
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
|
||||
|
||||
RUN docker-php-ext-install pdo pdo_mysql
|
||||
|
||||
COPY . /var/www/html
|
||||
# Copy configs
|
||||
COPY ./config/virtual-host.conf /etc/apache2/sites-available/000-default.conf
|
||||
COPY ./config/httpd.conf /etc/apache2/httpd.conf
|
||||
|
||||
# Setup App
|
||||
RUN mkdir -p /app/public && chown -R www-data:www-data /app
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# add sources code
|
||||
COPY . /app
|
||||
|
||||
ENV VOLUME_PATH /app/public
|
||||
|
||||
WORKDIR /var/www/html
|
||||
RUN chown -R www-data:www-data /var/www/html
|
||||
RUN composer install
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
CMD ["apache2-foreground"]
|
@ -1,20 +1,22 @@
|
||||
<?php
|
||||
|
||||
use Dotenv\Dotenv;
|
||||
use Shared\Log;
|
||||
|
||||
$dotenv = Dotenv::createImmutable(__DIR__);
|
||||
$dotenv->load();
|
||||
|
||||
$dotenv = Dotenv::createUnsafeImmutable(__DIR__,'.env');
|
||||
$dotenv->safeLoad();
|
||||
// echo($_ENV);
|
||||
// apenrently getEnv is not a good thing cause
|
||||
// const DB_HOST = $_ENV['DB_HOST'] ?? 'localhost';
|
||||
// const DB_DATABASE = $_ENV['DB_DATABASE'] ?? 'heartTrack';
|
||||
// const DB_USER = $_ENV['DB_USER'] ?? 'toto';
|
||||
// const DB_PASSWORD = $_ENV['DB_PASSWORD'] ?? 'achanger';
|
||||
// const APP_ENV = $_ENV['APP_ENV'] ?? 'development';
|
||||
const DB_HOST ='localhost';
|
||||
const DB_DATABASE = 'heartTrack';
|
||||
const DB_USER = 'toto';
|
||||
const DB_PASSWORD = 'achanger';
|
||||
define("APP_ENV", 'development');
|
||||
|
||||
const APP_ENV = 'console';
|
||||
const DB_HOST = 'localhost';
|
||||
const DB_DATABASE = 'heartTrack';
|
||||
const DB_USER = 'toto';
|
||||
const DB_PASSWORD = 'achanger';
|
||||
//const APP_ENV = 'console';
|
||||
|
||||
const DSN = "mysql:host=" . DB_HOST . ";dbname=" . DB_DATABASE;
|
||||
const DSN = "mysql:host=" . DB_HOST . ";dbname=" . DB_DATABASE;
|
||||
|
@ -0,0 +1 @@
|
||||
SetEnv ASSET_PREFIX containers/HeartDev-web/
|
@ -1,21 +1,19 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
index index.php index.html index.htm;
|
||||
root /usr/share/nginx/html;
|
||||
error_page 404 /index.php;
|
||||
|
||||
root /var/www/html;
|
||||
index index.php index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
location ~ \.php$ {
|
||||
include fastcgi_params;
|
||||
fastcgi_pass php:9000; # service name defined in docker-compose.yml file
|
||||
fastcgi_param REQUEST_METHOD $request_method;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
}
|
||||
include fastcgi_params;
|
||||
}
|
||||
|
||||
location ~ /\.ht {
|
||||
deny all;
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
try_files $uri /index.php;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
<VirtualHost *:80>
|
||||
ServerName default
|
||||
|
||||
<Directory />
|
||||
Options FollowSymLinks
|
||||
AllowOverride None
|
||||
Require all denied
|
||||
</Directory>
|
||||
|
||||
<Directory ${VOLUME_PATH}>
|
||||
AllowOverride All
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
DocumentRoot ${VOLUME_PATH}
|
||||
|
||||
AccessFileName .htaccess
|
||||
<FilesMatch "^\.ht">
|
||||
Require all denied
|
||||
</FilesMatch>
|
||||
|
||||
LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
|
||||
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
|
||||
LogFormat "%h %l %u %t \"%r\" %>s %O" common
|
||||
LogFormat "%{Referer}i -> %U" referer
|
||||
LogFormat "%{User-agent}i" agent
|
||||
|
||||
CustomLog /proc/self/fd/1 combined
|
||||
|
||||
<FilesMatch \.php$>
|
||||
SetHandler application/x-httpd-php
|
||||
</FilesMatch>
|
||||
|
||||
# Multiple DirectoryIndex directives within the same context will add
|
||||
# to the list of resources to look for rather than replace
|
||||
# https://httpd.apache.org/docs/current/mod/mod_dir.html#directoryindex
|
||||
DirectoryIndex disabled
|
||||
DirectoryIndex index.php index.html
|
||||
</VirtualHost>
|
@ -1,15 +1,42 @@
|
||||
version: '3'
|
||||
services:
|
||||
web:
|
||||
|
||||
nginx:
|
||||
image: nginx:latest
|
||||
ports:
|
||||
- "8080:80"
|
||||
- "3000:80"
|
||||
volumes:
|
||||
- ./public:/var/www/html
|
||||
- ./config/nginx.conf:/etc/nginx/conf.d
|
||||
links:
|
||||
- php
|
||||
php:
|
||||
image: php:7.4-fpm
|
||||
- ./config/nginx.conf:/etc/nginx/conf.d/default.conf
|
||||
- .:/var/www
|
||||
depends_on:
|
||||
- mysql
|
||||
- web
|
||||
|
||||
web:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./config/Dockerfile
|
||||
ports:
|
||||
- 9000:9000
|
||||
volumes:
|
||||
- ./src:/var/www/html
|
||||
- .:/var/www
|
||||
depends_on:
|
||||
- mysql
|
||||
environment:
|
||||
DB_HOST: mysql
|
||||
DB_PORT: port
|
||||
DB_DATABASE: test
|
||||
DB_USER: user
|
||||
DB_PASSWORD: pass
|
||||
APP_ENV: development
|
||||
|
||||
mysql:
|
||||
image: mysql:latest
|
||||
container_name: my-mysql-container
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: pass
|
||||
MYSQL_DATABASE: test
|
||||
MYSQL_USER: user
|
||||
MYSQL_PASSWORD: pass
|
||||
ports:
|
||||
- "3307:3306"
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,9 +1,68 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
require_once __DIR__ . '/../config/config.php';
|
||||
if (APP_ENV === 'console') {
|
||||
require_once __DIR__ . '/../src/console/Console.php';
|
||||
}
|
||||
elseif (APP_ENV === 'development') {
|
||||
require_once __DIR__ . DIRECTORY_SEPARATOR . '../src/app/index.test.php';
|
||||
}
|
||||
|
||||
use App\AppCreator;
|
||||
use App\Router\Middleware\LoggingMiddleware;
|
||||
use App\Router\Request\RequestFactory;
|
||||
use Manager\UserManager;
|
||||
use Manager\DataManager;
|
||||
|
||||
use Repository\IUserRepository;
|
||||
use Shared\ArgumentControllerResolver;
|
||||
use Shared\IArgumentResolver;
|
||||
use Stub\AuthService;
|
||||
use Stub\NotificationRepository;
|
||||
use Stub\TrainingRepository;
|
||||
use Stub\UserRepository;
|
||||
use Stub\RelationshipRequestRepository;
|
||||
use Repository\INotificationRepository;
|
||||
use App\Router\Middleware\AuthMiddleware;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
use Network\IAuthService;
|
||||
use Network\IFriendRequestService;
|
||||
use Network\RelationshipService;
|
||||
use Network\INotificationService;
|
||||
use Stub\NotificationService;
|
||||
|
||||
|
||||
use Stub\StubData;
|
||||
use Twig\Environment;
|
||||
use Twig\Loader\FilesystemLoader;
|
||||
use Shared\IHashPassword;
|
||||
use Shared\HashPassword;
|
||||
|
||||
|
||||
$appFactory = new AppCreator();
|
||||
$appFactory->registerService(IArgumentResolver::class, ArgumentControllerResolver::class);
|
||||
$appFactory->registerService(UserManager::class, UserManager::class);
|
||||
$appFactory->registerService(DataManager::class, StubData::class);
|
||||
$appFactory->registerService(IAuthService::class, AuthService::class);
|
||||
$appFactory->registerService(IFriendRequestService::class, RelationshipService::class);
|
||||
$appFactory->registerService(IHashPassword::class, HashPassword::class);
|
||||
$appFactory->registerService(INotificationService::class, NotificationService::class);
|
||||
$appFactory->registerService(INotificationRepository::class, NotificationRepository::class);
|
||||
$appFactory->registerService(IUserRepository::class, UserRepository::class);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$appFactory->registerService(\Twig\Loader\LoaderInterface::class, function() {
|
||||
return new FilesystemLoader(__DIR__ . '/../src/app/views/Templates');
|
||||
});
|
||||
|
||||
$appFactory->registerService(\Twig\Environment::class,\Twig\Environment::class);
|
||||
|
||||
// Connexion à la base de données
|
||||
// $databaseContext = DatabaseContext::getInstance();
|
||||
|
||||
$appFactory->AddControllers();
|
||||
|
||||
|
@ -0,0 +1,15 @@
|
||||
document.getElementById('saveButton').addEventListener('click', function() {
|
||||
var preferences = {
|
||||
notifications: document.getElementById('notif').checked,
|
||||
theme: document.getElementById('theme').value
|
||||
};
|
||||
|
||||
fetch('/index.php/', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(preferences),
|
||||
})
|
||||
.catch((error) => console.error('Error:', error));
|
||||
});
|
@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use App\Controller\BaseController;
|
||||
use App\Controller\FrontController;
|
||||
use App\Router\Request\HttpRequest;
|
||||
use App\Router\Middleware\IHttpMiddleware;
|
||||
use App\Router\Request\IRequest;
|
||||
use App\Router\Route;
|
||||
use App\Views\Directives\Navigate;
|
||||
use Shared\Attributes\Route as RouteAttribute;
|
||||
use App\Router\Router;
|
||||
use App\Router\Session;
|
||||
use Shared\Log;
|
||||
|
||||
class App
|
||||
{
|
||||
private string $appName;
|
||||
private int $version;
|
||||
|
||||
private ?IHttpMiddleware $middlewarePipeline = null;
|
||||
|
||||
private Container $container;
|
||||
|
||||
private Router $router;
|
||||
|
||||
private array $controllers = [];
|
||||
|
||||
private FrontController $frontController;
|
||||
|
||||
private Session $session;
|
||||
|
||||
|
||||
public function __construct(string $appName, int $version, \App\Container $diContainer)
|
||||
{
|
||||
$this->appName = $appName;
|
||||
$this->version = $version;
|
||||
$this->container = $diContainer;
|
||||
$this->router = new Router("");
|
||||
$this->frontController = new FrontController($this->router,$this->container);
|
||||
$this->session = Session::getInstance();
|
||||
}
|
||||
|
||||
public function use(IHttpMiddleware $middleware)
|
||||
{
|
||||
if ($this->middlewarePipeline === null) {
|
||||
$this->middlewarePipeline = $middleware;
|
||||
} else {
|
||||
// Chain the new middleware to the end of the existing pipeline
|
||||
$currentMiddleware = $this->middlewarePipeline;
|
||||
while ($currentMiddleware->getNext() !== null) {
|
||||
$currentMiddleware = $currentMiddleware->getNext();
|
||||
}
|
||||
$currentMiddleware->setNext($middleware);
|
||||
}
|
||||
}
|
||||
|
||||
public function getAppName(): string
|
||||
{
|
||||
return $this->appName;
|
||||
}
|
||||
|
||||
/* public function twigConfigure(array $extensionClassNames = []): void
|
||||
{
|
||||
if (!$this->container->has(\Twig\Environment::class)) {
|
||||
throw new \LogicException('You cannot use the "twigConfigure" method if the Twig Bundle is not available. Try running "composer require twig/twig".');
|
||||
}
|
||||
|
||||
$twigEnvironment = $this->container->get(\Twig\Environment::class);
|
||||
|
||||
if (empty($extensionClassNames)) {
|
||||
$twigEnvironment->addExtension(new Navigate($this->router));
|
||||
|
||||
} else {
|
||||
foreach ($extensionClassNames as $extensionClassName) {
|
||||
if (class_exists($extensionClassName)) {
|
||||
$extensionInstance = new $extensionClassName();
|
||||
if ($extensionInstance instanceof \Twig\Extension\ExtensionInterface) {
|
||||
$twigEnvironment->addExtension($extensionInstance);
|
||||
} else {
|
||||
throw new \InvalidArgumentException("Class '$extensionClassName' does not implement Twig\Extension\ExtensionInterface.");
|
||||
}
|
||||
} else {
|
||||
throw new \InvalidArgumentException("Class '$extensionClassName' does not exist.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
public function getVersion(): int
|
||||
{
|
||||
return $this->version;
|
||||
}
|
||||
|
||||
public function run(IRequest $request)
|
||||
{
|
||||
if ($this->middlewarePipeline == null) {
|
||||
return $this->frontController->dispatch($request);
|
||||
}
|
||||
// Exécutez le middleware en utilisant le pipeline
|
||||
return $this->middlewarePipeline->handle($request, function($request) {
|
||||
// Logique de gestion principale de la requête ici
|
||||
$this->frontController->dispatch($request);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public function mapControllers(): void
|
||||
{
|
||||
$classes = $this->container->getAllRegisteredClassNames();
|
||||
|
||||
foreach ($classes as $class) {
|
||||
if ($this->isController($class)) {
|
||||
$this->mapControllerRoutes($class);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
function mapControllerRoutes(string $controllerClass): void
|
||||
{
|
||||
$reflectionClass = new \ReflectionClass($controllerClass);
|
||||
$attributes = $reflectionClass->getAttributes(RouteAttribute::class);
|
||||
$prefix = '';
|
||||
if (!empty($attributes)) {
|
||||
|
||||
$prefix = $attributes[0]->newInstance()->getPath();
|
||||
}
|
||||
|
||||
foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
|
||||
|
||||
foreach ($method->getAttributes(RouteAttribute::class) as $attribute) {
|
||||
|
||||
/** @var RouteAttribute $route */
|
||||
$route = $attribute->newInstance();
|
||||
|
||||
$this->router->addControllerRoute(
|
||||
implode('|', $route->getMethods()),
|
||||
$prefix . $route->getPath(),
|
||||
$controllerClass,
|
||||
$method->getName(),
|
||||
$route->getName()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function isController(string $class): bool
|
||||
{
|
||||
$reflectionClass = new \ReflectionClass($class);
|
||||
return $reflectionClass->isSubclassOf(BaseController::class);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use App\Controller\BaseController;
|
||||
use Shared\Log;
|
||||
use Twig\Loader\FilesystemLoader;
|
||||
|
||||
class AppCreator
|
||||
{
|
||||
private Container $container;
|
||||
|
||||
private array $services = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->container = new Container;
|
||||
}
|
||||
|
||||
public function registerService(string $serviceId, callable|string $service): self
|
||||
{
|
||||
$this->container->set($serviceId, $service);
|
||||
$this->services[] = $serviceId;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance or perform actions based on the current application environment.
|
||||
*
|
||||
* @return App|null An instance of the App class in the 'development' environment, or null in other environments.
|
||||
*/
|
||||
public function create(): ?App
|
||||
{
|
||||
// Check the application environment
|
||||
switch (APP_ENV) {
|
||||
case 'console':
|
||||
// Load the Console.php file in case of the 'console' environment
|
||||
require_once __DIR__ . '/../console/Console.php';
|
||||
break;
|
||||
case 'development':
|
||||
// Create a new instance of the App class in the 'development' environment
|
||||
return new App("HeartTrack", 1, $this->container);
|
||||
break;
|
||||
case 'html':
|
||||
// Load the index.test.php file in case of the 'html' environment
|
||||
require_once __DIR__ . '/index.test.php';
|
||||
break;
|
||||
default:
|
||||
// Handle other environment cases here, if necessary
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function AddControllers($namespacePrefix = 'App\Controller', $pathToControllers = __DIR__ . '/controller'): self
|
||||
{
|
||||
$controllerFiles = glob($pathToControllers . '/*.php');
|
||||
|
||||
foreach ($controllerFiles as $file) {
|
||||
// Get class name from file name
|
||||
$class = basename($file, '.php');
|
||||
$fullClassName = $namespacePrefix . '\\' . $class;
|
||||
if (!class_exists($fullClassName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Use reflection to check if class extends BaseController
|
||||
$reflectionClass = new \ReflectionClass($fullClassName);
|
||||
if ($reflectionClass->isSubclassOf(BaseController::class)) {
|
||||
// Register in DI container
|
||||
$this->container->set($fullClassName, function () use ($fullClassName) {
|
||||
$controllerInstance = new $fullClassName();
|
||||
$controllerInstance->setContainer($this->container);
|
||||
return $controllerInstance;
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getServiceRegistered(): array
|
||||
{
|
||||
return $this->services;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Shared\Log;
|
||||
use Twig\Environment;
|
||||
use Twig\Loader\FilesystemLoader;
|
||||
|
||||
class Container implements ContainerInterface
|
||||
{
|
||||
private array $entries = [];
|
||||
|
||||
public function get(string $id)
|
||||
{
|
||||
|
||||
if ($this->has($id)) {
|
||||
$entry = $this->entries[$id];
|
||||
if (is_callable($entry)) {
|
||||
return $entry($this);
|
||||
}
|
||||
|
||||
$id = $entry;
|
||||
}
|
||||
|
||||
return $this->resolve($id);
|
||||
}
|
||||
|
||||
|
||||
public function has(string $id): bool
|
||||
{
|
||||
return isset($this->entries[$id]);
|
||||
}
|
||||
|
||||
public function set(string $id, callable|string $concrete): void
|
||||
{
|
||||
$this->entries[$id] = $concrete;
|
||||
|
||||
}
|
||||
|
||||
public function resolve(string $id)
|
||||
{
|
||||
// 1. Inspect the class that we are trying to get from the container
|
||||
try {
|
||||
$reflectionClass = new \ReflectionClass($id);
|
||||
} catch (\ReflectionException $e) {
|
||||
throw new \Exception($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
if (!$reflectionClass->isInstantiable()) {
|
||||
throw new \Exception('Class "' . $id . '" is not instantiable');
|
||||
}
|
||||
|
||||
// 2. Inspect the constructor of the class
|
||||
$constructor = $reflectionClass->getConstructor();
|
||||
|
||||
if (!$constructor) {
|
||||
return new $id;
|
||||
}
|
||||
|
||||
// 3. Inspect the constructor parameters (dependencies)
|
||||
$parameters = $constructor->getParameters();
|
||||
|
||||
if (!$parameters) {
|
||||
return new $id;
|
||||
}
|
||||
|
||||
// 4. If the constructor parameter is a class then try to resolve that class using the container
|
||||
$dependencies = array_map(
|
||||
function (\ReflectionParameter $param) use ($id) {
|
||||
$name = $param->getName();
|
||||
$type = $param->getType();
|
||||
|
||||
// Check for a default value
|
||||
if ($param->isDefaultValueAvailable()) {
|
||||
return $param->getDefaultValue();
|
||||
}
|
||||
|
||||
if (!$type) {
|
||||
throw new \Exception(
|
||||
'Failed to resolve class "' . $id . '" because param "' . $name . '" is missing a type hint'
|
||||
);
|
||||
}
|
||||
|
||||
if ($type instanceof \ReflectionUnionType) {
|
||||
throw new \Exception(
|
||||
'Failed to resolve class "' . $id . '" because of union type for param "' . $name . '"'
|
||||
);
|
||||
}
|
||||
|
||||
if ($type instanceof \ReflectionNamedType && !$type->isBuiltin()) {
|
||||
return $this->get($type->getName());
|
||||
}
|
||||
|
||||
throw new \Exception(
|
||||
'Failed to resolve class "' . $id . '" because invalid param "' . $name . '"'
|
||||
);
|
||||
},
|
||||
$parameters
|
||||
);
|
||||
|
||||
return $reflectionClass->newInstanceArgs($dependencies);
|
||||
}
|
||||
|
||||
public function getAllRegisteredClassNames(): array
|
||||
{
|
||||
return array_keys($this->entries);
|
||||
}
|
||||
}
|
@ -0,0 +1,176 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Container;
|
||||
use App\Router\Request\IRequest;
|
||||
use App\Router\Response\Response;
|
||||
use Shared\Attributes\Route;
|
||||
use Twig\Environment;
|
||||
use Data\Core\Preferences;
|
||||
use Shared\Log;
|
||||
|
||||
class AthleteController extends BaseController
|
||||
{
|
||||
|
||||
#[Route(path: '/search-ath', name: 'search-ath', methods: ['GET'])]
|
||||
public function searchUser(string $username, IRequest $req): Response
|
||||
{
|
||||
$taberror = [];
|
||||
$utiliArray = [
|
||||
[
|
||||
'nom' => 'John',
|
||||
'prenom' => 'Doe',
|
||||
'img' => 'john_doe',
|
||||
'username' => 'johndoe',
|
||||
],
|
||||
[
|
||||
'nom' => 'Alice',
|
||||
'prenom' => 'Smith',
|
||||
'img' => 'alice_smith',
|
||||
'username' => 'alicesmith',
|
||||
],
|
||||
];
|
||||
// if(!Validation::val_string($name)){
|
||||
try {
|
||||
//code...
|
||||
// $model->userMgr->getUser($name);
|
||||
return $this->render('./page/addfriend.html.twig', [
|
||||
'css' => $this->preference->getCookie(),
|
||||
'pp' => "test2",
|
||||
'user' => "Doe",
|
||||
'role' => "Athlète",
|
||||
'friendship' => [],
|
||||
'analyzes' => [],
|
||||
'mails' => [],
|
||||
'users' => $utiliArray,
|
||||
'infoUser' => [],
|
||||
'exos' => [],
|
||||
'member' => [],
|
||||
'responce' => "Notification d'ajout envoyée à $username"
|
||||
]);
|
||||
} catch (\Throwable $th) {
|
||||
//throw $th;
|
||||
// return $this->render("addfriend.html.twig", ['tabError' => $taberror ]);
|
||||
}
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
#[Route(path: '/analyses', name: 'analyses', methods: ['GET'])]
|
||||
public function analyses(): Response
|
||||
{
|
||||
return $this->render('./page/analyze.html.twig', [
|
||||
'css' => $this->preference->getCookie(),
|
||||
'pp' => "test2",
|
||||
'user' => "Doe",
|
||||
'role' => "Athlète",
|
||||
'friendship' => [],
|
||||
'analyzes' => [],
|
||||
'mails' => [],
|
||||
'users' => [],
|
||||
'infoUser' => [],
|
||||
'exos' => [],
|
||||
'member' => []
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
#[Route(path: '/exercice', name: 'exercice', methods: ['GET'])] // 8
|
||||
public function exercice(): Response
|
||||
{
|
||||
return $this->render('./page/exercice.html.twig', [
|
||||
'css' => $this->preference->getCookie(),
|
||||
'pp' => "test2",
|
||||
'user' => "Doe",
|
||||
'role' => "Athlète",
|
||||
'friendship' => [],
|
||||
'analyzes' => [],
|
||||
'mails' => [],
|
||||
'users' => [],
|
||||
'infoUser' => [],
|
||||
'exos' => [],
|
||||
'member' => []
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route(path: '/add-friend', name: 'add-friend', methods: ['POST'])]
|
||||
public function addFriend(string $username, IRequest $req): Response
|
||||
{
|
||||
$taberror = [];
|
||||
$utiliArray = [
|
||||
[
|
||||
'nom' => 'John',
|
||||
'prenom' => 'Doe',
|
||||
'img' => 'john_doe',
|
||||
'username' => 'johndoe',
|
||||
],
|
||||
[
|
||||
'nom' => 'Alice',
|
||||
'prenom' => 'Smith',
|
||||
'img' => 'alice_smith',
|
||||
'username' => 'alicesmith',
|
||||
],
|
||||
];
|
||||
// if(!Validation::val_string($name)){
|
||||
try {
|
||||
//code...
|
||||
// $model->userMgr->addFriend($name);
|
||||
return $this->render('./page/addfriend.html.twig', [
|
||||
'css' => $this->preference->getCookie(),
|
||||
'pp' => "test2",
|
||||
'user' => "Doe",
|
||||
'role' => "Athlète",
|
||||
'friendship' => [],
|
||||
'analyzes' => [],
|
||||
'mails' => [],
|
||||
'users' => $utiliArray,
|
||||
'infoUser' => [],
|
||||
'exos' => [],
|
||||
'member' => [],
|
||||
'responce' => "Notification d'ajout envoyée à $username"
|
||||
]);
|
||||
} catch (\Throwable $th) {
|
||||
//throw $th;
|
||||
// return $this->render("addfriend.html.twig", ['tabError' => $taberror ]);
|
||||
}
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#[Route(path: '/friend', name: 'friend', methods: ['GET'])]
|
||||
public function friend(): Response
|
||||
{
|
||||
$utiliArray = [
|
||||
[
|
||||
'nom' => 'John',
|
||||
'prenom' => 'Doe',
|
||||
'img' => 'john_doe',
|
||||
'username' => 'johndoe',
|
||||
],
|
||||
[
|
||||
'nom' => 'Alice',
|
||||
'prenom' => 'Smith',
|
||||
'img' => 'alice_smith',
|
||||
'username' => 'alicesmith',
|
||||
],
|
||||
];
|
||||
return $this->render('./page/addfriend.html.twig',[
|
||||
'css' => $this->preference->getCookie(),
|
||||
'pp' => "test2",
|
||||
'user' => "Doe",
|
||||
'role' => "Athlète",
|
||||
'friendship' => [],
|
||||
'analyzes' => [],
|
||||
'mails' => [],
|
||||
'users' => $utiliArray,
|
||||
'infoUser' => [],
|
||||
'exos' => [],
|
||||
'member' => [],
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Container;
|
||||
use App\Router\Request\IRequest;
|
||||
use App\Router\Response\Response;
|
||||
use App\Router\Response\IResponse;
|
||||
|
||||
use Couchbase\UserManager;
|
||||
use Shared\Attributes\Route;
|
||||
use Shared\Validation;
|
||||
use Twig\Environment;
|
||||
use Data\Core\Preferences;
|
||||
use Shared\Log;
|
||||
|
||||
class AuthController extends BaseController
|
||||
{
|
||||
|
||||
|
||||
#[Route('/login', name: 'login',methods: ['POST'])]
|
||||
public function login(IRequest $request): IResponse {
|
||||
|
||||
$error = [];
|
||||
try {
|
||||
$log=Validation::clean_string($request->getBody()['email']);
|
||||
$mdp=Validation::clean_string($request->getBody()['password']);
|
||||
} catch (\Throwable $th) {
|
||||
$error = "Wrong cred";
|
||||
}
|
||||
|
||||
if($this->container->get(UserManager::class)->login($log,$mdp)){
|
||||
return $this->redirectToRoute('/');
|
||||
}
|
||||
else{
|
||||
$error [] = "Erreur de connexion. Essayez encore";
|
||||
}
|
||||
return $this->render('./page/login.html.twig', ['error' => $error]);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#[Route('/log', name: 'baseLog',methods: ['GET'])]
|
||||
public function index(IRequest $request): IResponse {
|
||||
|
||||
return $this->render('./page/login.html.twig',[
|
||||
'css' => $this->preference->getCookie(),
|
||||
'pp' => "test2",
|
||||
'user' => "Doe",
|
||||
'role' => "Athlète",
|
||||
'friendship' => [],
|
||||
'analyzes' => [],
|
||||
'mails' => [],
|
||||
'users' => [],
|
||||
'infoUser' => [],
|
||||
'exos' => [],
|
||||
'member' => []
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
#[Route('/register', name: 'register' , methods:['GET'])]
|
||||
public function register(IRequest $request): IResponse
|
||||
{
|
||||
if ($request->getMethod() == 'POST') {
|
||||
$nom = $request->getBody()['nom'];
|
||||
|
||||
$prenom = $request->getBody()['prenom'];
|
||||
|
||||
$username = $request->getBody()['username'];
|
||||
|
||||
$email = $request->getBody()['email'];
|
||||
|
||||
$motDePasse = $request->getBody()['motDePasse'];
|
||||
|
||||
$sexe = $request->getBody()['sexe'];
|
||||
|
||||
$taille = $request->getBody()['taille'];
|
||||
|
||||
$poids = $request->getBody()['poids'];
|
||||
|
||||
$dateNaissanceStr = $request->getBody()['nom'];
|
||||
$dateNaissance = new \DateTime($dateNaissanceStr);
|
||||
|
||||
|
||||
if (!$dateNaissance) {
|
||||
throw new \Exception("Date de naissance non valide. Format attendu : YYYY-MM-DD");
|
||||
}
|
||||
|
||||
$roleName = $request->getBody()['roleName'];
|
||||
|
||||
|
||||
$registrationData = [
|
||||
'nom' => $nom,
|
||||
'prenom' => $prenom,
|
||||
'username' => $username,
|
||||
'email' => $email,
|
||||
'sexe' => $sexe,
|
||||
'taille' => $taille,
|
||||
'poids' => $poids,
|
||||
'dateNaissance' => $dateNaissance,
|
||||
'roleName' => $roleName
|
||||
];
|
||||
|
||||
try {
|
||||
if ($this->container->get(UserManager::class)->register($email, $motDePasse, $registrationData)) {
|
||||
return $this->redirectToRoute('/');
|
||||
} else {
|
||||
|
||||
$error [] = 'L\'inscription a échoué. Veuillez réessayer.';
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$error [] = 'Erreur lors de l\'inscription: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->render('/register.html.twig');
|
||||
}
|
||||
|
||||
#[Route(path: '/mdp', name: 'mdp', methods: ['POST'])]
|
||||
public function mdp(string $ancienMotDePasse,string $nouveauMotDePasse,string $confirmerMotDePasse, IRequest $req): Response
|
||||
{
|
||||
|
||||
// CONFIRMER LES DONNESS !!!!! IMPORTANT
|
||||
|
||||
return $this->render('./page/settings.html.twig',[
|
||||
'css' => $this->preference->getCookie(),
|
||||
'pp' => "test2",
|
||||
'user' => "Doe",
|
||||
'role' => "Athlète",
|
||||
'friendship' => [],
|
||||
'analyzes' => [],
|
||||
'mails' => [],
|
||||
'users' => [],
|
||||
'infoUser' => [],
|
||||
'exos' => [],
|
||||
'member' => []
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
?>
|
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
use Data\Core\Preferences;
|
||||
|
||||
use App\Container;
|
||||
use App\Router\Response\RedirectResponse;
|
||||
use App\Router\Response\Response;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
|
||||
abstract class BaseController
|
||||
{
|
||||
|
||||
protected Preferences $preference;
|
||||
|
||||
public function __construct(){
|
||||
$this->preference = new Preferences();
|
||||
}
|
||||
protected ContainerInterface $container;
|
||||
|
||||
public function setContainer(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
protected function renderView(string $view, array $parameters = []): string
|
||||
{
|
||||
if (!$this->container->has(\Twig\Environment::class)) {
|
||||
throw new \LogicException('You cannot use the "renderView" method if the Twig Bundle is not available. Try running "composer require symfony/twig-bundle".');
|
||||
}
|
||||
|
||||
return $this->container->get(\Twig\Environment::class)->render($view, $parameters);
|
||||
}
|
||||
/**
|
||||
* Renders a view.
|
||||
*
|
||||
* If an invalid form is found in the list of parameters, a 422 status code is returned.
|
||||
* Forms found in parameters are auto-cast to form views.
|
||||
*/
|
||||
protected function render(string $view, array $parameters = [], Response $response = null): Response
|
||||
{
|
||||
$content = $this->renderView($view, $parameters);
|
||||
$response ??= new Response();
|
||||
|
||||
/* if (200 === $response->getStatusCode()) {
|
||||
foreach ($parameters as $v) {
|
||||
if ($v instanceof FormInterface && $v->isSubmitted() && !$v->isValid()) {
|
||||
$response->setStatusCode(422);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
$response->setContent($content);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
protected function redirect(string $url, int $status = 302): RedirectResponse
|
||||
{
|
||||
return new RedirectResponse($url, $status);
|
||||
}
|
||||
|
||||
protected function redirectToRoute(string $route, array $parameters = [], int $status = 302): RedirectResponse
|
||||
{
|
||||
return $this->redirect($this->generateUrl($route, $parameters), $status);
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO : Should hanle ierror if the route is not existing
|
||||
* */
|
||||
protected function generateUrl(string $route, array $parameters = []): string
|
||||
{
|
||||
return $this->container->get(\App\Router\Router::class)->generate($route, $parameters);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
// namespace App\Controller;
|
||||
|
||||
// use App\Container;
|
||||
// use App\Router\Request\IRequest;
|
||||
// use App\Router\Response\Response;
|
||||
// use App\Router\Response\IResponse;
|
||||
|
||||
// use Shared\Attributes\Route;
|
||||
// use Twig\Environment;
|
||||
// use Data\Core\Preferences;
|
||||
// use Shared\Log;
|
||||
|
||||
|
||||
|
||||
// #[Route(path: '/coach', name: 'coach')]
|
||||
// class CoachController extends BaseController
|
||||
// {
|
||||
|
||||
// private ICoachManager $coachManager;
|
||||
// private $security;
|
||||
|
||||
// public function __construct(DataManager $dataManager, Security $security)
|
||||
// {
|
||||
// $this->coachManager = $dataManager->coachMgr;
|
||||
// $this->security = $security;
|
||||
// }
|
||||
|
||||
// #[Route(path: '/', name: 'home', methods: ['GET'])]
|
||||
// public function index(): Response
|
||||
// {
|
||||
// return $this->render('./page/home.html.twig',[
|
||||
// 'css' => $this->preference->getCookie(),
|
||||
// 'pp' => "test2",
|
||||
// 'user' => "Doe",
|
||||
// 'role' => "Athlète",
|
||||
// 'friendship' => [],
|
||||
// 'analyzes' => [],
|
||||
// 'mails' => [],
|
||||
// 'users' => [],
|
||||
// 'infoUser' => [],
|
||||
// 'exos' => [],
|
||||
// 'member' => []
|
||||
// ]);
|
||||
// }
|
||||
// #[Route('/global-stats', name: 'coach_global_stats', methods: ['GET'])]
|
||||
// public function globalStats(): Response
|
||||
// {
|
||||
// // Add logic to fetch and process global stats
|
||||
// return $this->render('coach/global_stats.html.twig');
|
||||
// }
|
||||
|
||||
// #[Route(path: '/exercice', name: 'exercice', methods: ['GET'])] // 8
|
||||
// public function exercice(): Response
|
||||
// {
|
||||
// return $this->render('./page/exercice.html.twig',[
|
||||
// 'css' => $this->preference->getCookie(),
|
||||
// 'pp' => "test2",
|
||||
// 'user' => "Doe",
|
||||
// 'role' => "Athlète",
|
||||
// 'friendship' => [],
|
||||
// 'analyzes' => [],
|
||||
// 'mails' => [],
|
||||
// 'users' => [],
|
||||
// 'infoUser' => [],
|
||||
// 'exos' => [],
|
||||
// 'member' => []
|
||||
// ]);
|
||||
// }
|
||||
|
||||
// #[Route(path: '/coaching', name: 'coaching', methods: ['GET'])]
|
||||
// public function coaching(): Response
|
||||
// {
|
||||
// return $this->render('./page/coaching.html.twig',[
|
||||
// 'css' => $this->preference->getCookie(),
|
||||
// 'pp' => "test2",
|
||||
// 'user' => "Doe",
|
||||
// 'role' => "Athlète",
|
||||
// 'friendship' => [],
|
||||
// 'analyzes' => [],
|
||||
// 'mails' => [],
|
||||
// 'users' => [],
|
||||
// 'infoUser' => [],
|
||||
// 'exos' => [],
|
||||
// 'member' => []
|
||||
// ]);
|
||||
// }
|
||||
|
||||
// #[Route('/list-athletes', name: 'coach_list_athletes')]
|
||||
// public function listAthletes(): Response
|
||||
// {
|
||||
// $coach = $this->security->getUser();
|
||||
// $athletes = $this->coachManager->getAthletesForCoach($coach);
|
||||
// return $this->render('coach/list_athletes.html.twig', [
|
||||
// 'athletes' => $athletes,
|
||||
// ]);
|
||||
// }
|
||||
// #[Route('/athlete-analysis/{athleteId}', name: 'coach_athlete_analysis', methods: ['GET'])]
|
||||
// public function athleteAnalysis($athleteId): Response
|
||||
// {
|
||||
// // Fetch and process data specific to the athlete
|
||||
// return $this->render('coach/athlete_analysis.html.twig', [
|
||||
// 'athleteId' => $athleteId,
|
||||
// ]);
|
||||
// }
|
||||
// #[Route('/add-athlete/{athleteId}', name: 'coach_add_athlete', methods: ['POST'])]
|
||||
// public function addAthlete(IRequest $request, $athleteId): IResponse
|
||||
// {
|
||||
// // Implement logic to add athlete
|
||||
// // ...
|
||||
|
||||
// return $this->redirectToRoute('coach_list_athletes');
|
||||
// }
|
||||
|
||||
// // #[Route('/remove-athlete', name: 'coach_remove_athlete', methods: ['POST'])]
|
||||
// // public function removeAthlete(int $athleteId, IRequest $request): IResponse
|
||||
// // {
|
||||
|
||||
// // return $this->redirectToRoute("/athletes");
|
||||
// // }
|
||||
|
||||
|
||||
// }
|
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
namespace App\Controller;
|
||||
use App\Container;
|
||||
use App\Router\Request\IRequest;
|
||||
use App\Router\Response\Response;
|
||||
use App\Router\Router;
|
||||
use Shared\Exception\NotFoundHttpException;
|
||||
use Shared\Exception\NotImplementedException;
|
||||
use Shared\IArgumentResolver;
|
||||
use Shared\Log;
|
||||
|
||||
class FrontController {
|
||||
private Router $router;
|
||||
|
||||
private Container $container;
|
||||
|
||||
public function __construct(Router $router, Container $container) {
|
||||
$this->router = $router;
|
||||
$this->container = $container;
|
||||
|
||||
}
|
||||
|
||||
public function dispatch(IRequest $request) {
|
||||
try {
|
||||
$match = $this->router->match($request);
|
||||
if (!is_null($match)) {
|
||||
$method = $match['target'];
|
||||
|
||||
$controller = $this->getController($match['target']);
|
||||
$callable = array($controller,$method[1]);
|
||||
$request->addToBody($match['params']);
|
||||
|
||||
if (!is_callable($callable)){
|
||||
throw new NotImplementedException('Controller target is not callable' .'Handle when route target is not a callable : not handle');
|
||||
}
|
||||
$argumentResolver = $this->container->get(IArgumentResolver::class);
|
||||
$arguments = $argumentResolver->getArguments($request, $callable);
|
||||
|
||||
// check role
|
||||
$response = call_user_func_array($callable, $arguments);
|
||||
|
||||
// should handle response properly like if it's a HTML, STING, JSON,....
|
||||
$response->send();
|
||||
} else {
|
||||
$this->handleError(404, "Page not found");
|
||||
}
|
||||
} catch (NotFoundHttpException $e) {
|
||||
$this->handleError(404, $e->getMessage());
|
||||
}
|
||||
catch(\Throwable $e){
|
||||
$this->handleError(501, $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private function getController($controllerSpec) {
|
||||
if (is_array($controllerSpec)) {
|
||||
$controllerName = $controllerSpec[0];
|
||||
} else {
|
||||
$controllerName = $controllerSpec;
|
||||
}
|
||||
|
||||
return $this->container->get($controllerName);
|
||||
}
|
||||
|
||||
// TODO : Don't work need Antoine help
|
||||
private function handleError(int $statusCode, $message) : void {
|
||||
if (!$this->container->has(\Twig\Environment::class)) {
|
||||
throw new \LogicException('You cannot use the "renderView" method if the Twig Bundle is not available. Try running "composer require symfony/twig-bundle".');
|
||||
}
|
||||
|
||||
$response = new Response($this->container->get(\Twig\Environment::class)->render('./error/error.html.twig',['title'=> $message , "code" => $statusCode, "name" => $message, "descr" => $message ]),$statusCode);
|
||||
$response->send();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
// namespace App\Controller;
|
||||
|
||||
// use App\Container;
|
||||
// use App\Router\Request\IRequest;
|
||||
// use App\Router\Response\Response;
|
||||
// use Shared\Attributes\Route;
|
||||
// use Twig\Environment;
|
||||
// use Data\Core\Preferences;
|
||||
// use Shared\Log;
|
||||
|
||||
// class HeartRateController extends BaseController
|
||||
// {
|
||||
|
||||
|
||||
// #[Route(path: '/import', name: 'import', methods: ['GET'])]
|
||||
// public function import(): Response
|
||||
// {
|
||||
// return $this->render('./page/import.html.twig',[
|
||||
// 'css' => $this->preference->getCookie(),
|
||||
// 'pp' => "test2",
|
||||
// 'user' => "Doe",
|
||||
// 'role' => "Athlète",
|
||||
// 'friendship' => [],
|
||||
// 'analyzes' => [],
|
||||
// 'mails' => [],
|
||||
// 'users' => [],
|
||||
// 'infoUser' => [],
|
||||
// 'exos' => [],
|
||||
// 'member' => []
|
||||
// ]);
|
||||
// }
|
||||
|
||||
|
||||
// }
|
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
// namespace App\Controller;
|
||||
|
||||
// use App\Container;
|
||||
// use App\Router\Request\IRequest;
|
||||
// use App\Router\Response\Response;
|
||||
// use App\Router\Response\IResponse;
|
||||
|
||||
// use Shared\Attributes\Route;
|
||||
// use Twig\Environment;
|
||||
// use Data\Core\Preferences;
|
||||
// use Shared\Log;
|
||||
|
||||
|
||||
|
||||
// #[Route(path: '/coach', name: 'coach')]
|
||||
// class CoachController extends BaseController
|
||||
// {
|
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Container;
|
||||
use App\Router\Request\IRequest;
|
||||
use App\Router\Response\Response;
|
||||
use Shared\Attributes\Route;
|
||||
use Twig\Environment;
|
||||
use Data\Core\Preferences;
|
||||
use Shared\Log;
|
||||
|
||||
class UserController extends BaseController
|
||||
{
|
||||
|
||||
|
||||
#[Route(path: '/', name: 'home', methods: ['GET'])]
|
||||
public function index(): Response
|
||||
{
|
||||
|
||||
return $this->render('./page/home.html.twig',[
|
||||
'css' => $this->preference->getCookie(),
|
||||
'pp' => "test2",
|
||||
'user' => "Doe",
|
||||
'role' => "Athlète",
|
||||
'friendship' => [],
|
||||
'analyzes' => [],
|
||||
'mails' => [],
|
||||
'users' => [],
|
||||
'infoUser' => [],
|
||||
'exos' => [],
|
||||
'member' => []
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
#[Route(path: '/settings', name: 'settings', methods: ['GET'])]
|
||||
public function settings(IRequest $req): Response
|
||||
{
|
||||
return $this->render('./page/settings.html.twig',[
|
||||
'css' => $this->preference->getCookie(),
|
||||
'pp' => "test2",
|
||||
'user' => "Doe",
|
||||
'role' => "Athlète",
|
||||
'friendship' => [],
|
||||
'analyzes' => [],
|
||||
'mails' => [],
|
||||
'users' => [],
|
||||
'infoUser' => [],
|
||||
'exos' => [],
|
||||
'member' => []
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
#[Route(path: '/preferences', name: 'preferences', methods: ['POST'])]
|
||||
public function preferences(string $theme, IRequest $req): Response
|
||||
{
|
||||
|
||||
// VALIDER LES DONNEES
|
||||
$this->preference->majCookie($theme);
|
||||
|
||||
return $this->render('./page/settings.html.twig',[
|
||||
'css' => $this->preference->getCookie(),
|
||||
'pp' => "test2",
|
||||
'user' => "Doe",
|
||||
'role' => "Athlète",
|
||||
'friendship' => [],
|
||||
'analyzes' => [],
|
||||
'mails' => [],
|
||||
'users' => [],
|
||||
'infoUser' => [],
|
||||
'exos' => [],
|
||||
'member' => []
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
<?php
|
||||
namespace App\Router;
|
||||
|
||||
/**
|
||||
* Represents a single route in the application.
|
||||
*/
|
||||
class Route
|
||||
{
|
||||
/**
|
||||
* The name of the route.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
private ?string $name;
|
||||
|
||||
/**
|
||||
* The path for the route.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private string $path;
|
||||
|
||||
/**
|
||||
* The callable to be executed when the route is matched.
|
||||
*
|
||||
* @var callable
|
||||
*/
|
||||
private $callable;
|
||||
|
||||
/**
|
||||
* Constructor for the Route.
|
||||
*
|
||||
* @param string $path The path for the route.
|
||||
* @param callable $callable The callable to be executed for this route.
|
||||
* @param array|null $params Optional parameters for the route.
|
||||
* @param string|null $name Optional name for the route.
|
||||
*/
|
||||
public function __construct(string $path, callable $callable, array $params = null, string $name = null)
|
||||
{
|
||||
$this->path = $path;
|
||||
$this->callable = $callable;
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the route.
|
||||
*
|
||||
* @return string|null The name of the route.
|
||||
*/
|
||||
public function getName(): ?string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the route.
|
||||
*
|
||||
* @param string|null $name The name to set.
|
||||
*/
|
||||
public function setName(?string $name): void
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the callable associated with the route.
|
||||
*
|
||||
* @return callable The callable for this route.
|
||||
*/
|
||||
public function getCallable()
|
||||
{
|
||||
return $this->callable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the path for the route.
|
||||
*
|
||||
* @return string The path for the route.
|
||||
*/
|
||||
public function getPath(): string
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the callable for the route.
|
||||
*
|
||||
* @param callable $callable The callable to set for this route.
|
||||
*/
|
||||
public function setCallable(callable $callable)
|
||||
{
|
||||
$this->callable = $callable;
|
||||
}
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
namespace App\Router;
|
||||
use App\Router\Request\IRequest;
|
||||
/**
|
||||
* Router class to manage a collection of routes in the application.
|
||||
* It provides functionalities to add routes and check if a given URL matches any of the defined routes.
|
||||
*/
|
||||
class Router {
|
||||
|
||||
/**
|
||||
* The base path for routing.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private string $path;
|
||||
|
||||
/**
|
||||
* Collection of routes.
|
||||
*
|
||||
* @var \AltoRouter
|
||||
*/
|
||||
private \AltoRouter $routes;
|
||||
|
||||
/**
|
||||
* Supported HTTP verbs.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public static $verbs = ['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE'];
|
||||
|
||||
/**
|
||||
* Constructor for Router.
|
||||
*
|
||||
* @param string $path The base path for the router.
|
||||
*/
|
||||
public function __construct(string $path = "/PHP/project/index.php") {
|
||||
$this->path = $path;
|
||||
$this->routes = new \AltoRouter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new Route to the collection.
|
||||
*
|
||||
* @param string $method The HTTP method.
|
||||
* @param Route $route The route object.
|
||||
* @throws \InvalidArgumentException If method is not supported.
|
||||
*/
|
||||
public function add(string $method, Route $route) {
|
||||
if (!in_array($method, self::$verbs)) {
|
||||
throw new \InvalidArgumentException("Method not supported");
|
||||
}
|
||||
$this->routes->map($method, $route->getPath(), $route->getCallable(), $route->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a route for a controller action.
|
||||
*
|
||||
* @param string $method The HTTP method.
|
||||
* @param string $path The path for the route.
|
||||
* @param mixed $controller The controller object.
|
||||
* @param string $action The action method in the controller.
|
||||
* @param string $name (Optional) The name of the route.
|
||||
* @throws \InvalidArgumentException If method is not supported.
|
||||
*/
|
||||
public function addControllerRoute(string $method, string $path, $controller, string $action, string $name = '') {
|
||||
if (!in_array($method, self::$verbs)) {
|
||||
throw new \InvalidArgumentException("Method not supported");
|
||||
}
|
||||
$this->routes->map($method, $path, [$controller, $action], $name);
|
||||
}
|
||||
|
||||
// TODO: Implement the extractParams method.
|
||||
// public function extractParams(string $path) {}
|
||||
|
||||
/**
|
||||
* Adds a GET route.
|
||||
*
|
||||
* @param string $path The path for the route.
|
||||
* @param callable $callable The callback function.
|
||||
* @param string $name The name of the route.
|
||||
*/
|
||||
public function get(string $path, callable $callable, $name) {
|
||||
$this->routes->map('GET', $path, $callable, $name);
|
||||
}
|
||||
|
||||
// Similar methods for post, put, etc. can be added here.
|
||||
|
||||
/**
|
||||
* Checks if the request can be processed.
|
||||
*
|
||||
* @param IRequest $request The request object.
|
||||
* @return array|null The matched route or null if no match.
|
||||
*/
|
||||
public function match(IRequest $request): ?array {
|
||||
return $this->routes->match($request->getRequestUri(), $request->getMethod()) ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all routes.
|
||||
*
|
||||
* @return array The array of routes.
|
||||
*/
|
||||
public function getRoutes() {
|
||||
return []; // TODO: Implement the actual logic to return routes.
|
||||
}
|
||||
|
||||
|
||||
public function generate (string $routeName, array $params = array()): string
|
||||
{
|
||||
return $this->routes->generate($routeName,$params);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,121 @@
|
||||
<?php
|
||||
/*
|
||||
Use the static method getInstance to get the object.
|
||||
*/
|
||||
namespace App\Router;
|
||||
|
||||
class Session
|
||||
{
|
||||
const SESSION_STARTED = TRUE;
|
||||
const SESSION_NOT_STARTED = FALSE;
|
||||
|
||||
// The state of the session
|
||||
private $sessionState = self::SESSION_NOT_STARTED;
|
||||
|
||||
// THE only instance of the class
|
||||
private static $instance;
|
||||
|
||||
|
||||
private function __construct() {}
|
||||
|
||||
|
||||
/**
|
||||
* Returns THE instance of 'Session'.
|
||||
* The session is automatically initialized if it wasn't.
|
||||
*
|
||||
* @return object
|
||||
**/
|
||||
|
||||
public static function getInstance()
|
||||
{
|
||||
if ( !isset(self::$instance))
|
||||
{
|
||||
self::$instance = new self;
|
||||
}
|
||||
|
||||
self::$instance->startSession();
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* (Re)starts the session.
|
||||
*
|
||||
* @return bool TRUE if the session has been initialized, else FALSE.
|
||||
**/
|
||||
|
||||
private function startSession()
|
||||
{
|
||||
if ( $this->sessionState == self::SESSION_NOT_STARTED )
|
||||
{
|
||||
$this->sessionState = session_start();
|
||||
}
|
||||
|
||||
return $this->sessionState;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stores datas in the session.
|
||||
* Example: $instance->foo = 'bar';
|
||||
*
|
||||
* @param name Name of the datas.
|
||||
* @param value Your datas.
|
||||
* @return void
|
||||
**/
|
||||
|
||||
public function __set( $name , $value )
|
||||
{
|
||||
$_SESSION[$name] = $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets datas from the session.
|
||||
* Example: echo $instance->foo;
|
||||
*
|
||||
* @param name Name of the datas to get.
|
||||
* @return mixed Datas stored in session.
|
||||
**/
|
||||
|
||||
public function __get( string $name )
|
||||
{
|
||||
if ( isset($_SESSION[$name]))
|
||||
{
|
||||
return $_SESSION[$name];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function __isset( $name )
|
||||
{
|
||||
return isset($_SESSION[$name]);
|
||||
}
|
||||
|
||||
|
||||
public function __unset( $name )
|
||||
{
|
||||
unset( $_SESSION[$name] );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Destroys the current session.
|
||||
*
|
||||
* @return bool TRUE is session has been deleted, else FALSE.
|
||||
**/
|
||||
|
||||
public function destroy()
|
||||
{
|
||||
if ( $this->sessionState == self::SESSION_STARTED )
|
||||
{
|
||||
$this->sessionState = !session_destroy();
|
||||
unset( $_SESSION );
|
||||
|
||||
return !$this->sessionState;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
namespace App\Router\Middleware;
|
||||
use App\Router\Request\IRequest;
|
||||
use Shared\Validation\Validator;
|
||||
|
||||
class RequestValidationMiddleware extends Middleware {
|
||||
private $validator;
|
||||
private $rules;
|
||||
|
||||
public function __construct(Validator $validator, array $rules) {
|
||||
$this->validator = $validator;
|
||||
$this->rules = $rules;
|
||||
}
|
||||
|
||||
public function handle(IRequest $request, callable $next) {
|
||||
$this->validateRequest($request);
|
||||
return parent::handle($request, $next);
|
||||
}
|
||||
|
||||
private function validateRequest(IRequest $request) {
|
||||
foreach ($this->rules as $param => $ruleSet) {
|
||||
foreach ($ruleSet as $rule) {
|
||||
$this->validator->rule($param, $rule['callback'], $rule['message']);
|
||||
}
|
||||
}
|
||||
|
||||
$requestData = array_merge($request->getQueryParameters(), $request->getRequestParameters());
|
||||
$this->validator->assert($requestData);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// $validationRules = [
|
||||
// 'email' => [
|
||||
// ['callback' => Validator::required(), 'message' => 'Email is required.'],
|
||||
// ['callback' => Validator::email(), 'message' => 'Email must be a valid email address.']
|
||||
// ],
|
||||
// // Add more rules as needed
|
||||
// ];
|
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
namespace App\Router\Middleware;
|
||||
|
||||
use App\Router\Request\IRequest;
|
||||
|
||||
interface IHttpMiddleware {
|
||||
public function handle(IRequest $request, callable $next);
|
||||
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
namespace App\Router\Middleware;
|
||||
|
||||
use App\Router\Request\IRequest;
|
||||
|
||||
class LoggingMiddleware extends Middleware {
|
||||
public function handle(IRequest $request, callable $next) {
|
||||
// Logique de journalisation
|
||||
echo "LoggingMiddleware: Log request - Method: {$request->getMethod()}, URI: {$request->getRequestUri()}\n";
|
||||
return parent::handle($request, $next);
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Router\Middleware;
|
||||
|
||||
use App\Router\Request\IRequest;
|
||||
|
||||
abstract class Middleware implements IHttpMiddleware {
|
||||
protected $next;
|
||||
|
||||
public function setNext(IHttpMiddleware $nextMiddleware) {
|
||||
$this->next = $nextMiddleware;
|
||||
}
|
||||
|
||||
public function handle(IRequest $request, callable $next) {
|
||||
if ($this->next !== null) {
|
||||
return $this->next->handle($request, $next);
|
||||
}
|
||||
return $next($request);
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace App\Router\Request;
|
||||
|
||||
interface ContentStrategy {
|
||||
public function getContent(): array;
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
namespace App\Router\Request;
|
||||
|
||||
// should maybe change this
|
||||
class ContentStrategyFactory {
|
||||
private static $strategyMap = [
|
||||
'application/json' => JsonContentStrategy::class,
|
||||
// Format...
|
||||
];
|
||||
|
||||
public static function createContentStrategy(string $contentType, string $requestMethod): ContentStrategy {
|
||||
foreach (self::$strategyMap as $type => $className) {
|
||||
if ($contentType === $type || in_array($requestMethod, ['PUT', 'PATCH', 'DELETE'])) {
|
||||
return new $className();
|
||||
}
|
||||
}
|
||||
return new FormContentStrategy();
|
||||
}
|
||||
|
||||
public static function registerStrategy(string $contentType, string $className): void {
|
||||
self::$strategyMap[$contentType] = $className;
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
namespace App\Router\Request;
|
||||
|
||||
|
||||
class FormContentStrategy implements ContentStrategy {
|
||||
public function getContent(): array {
|
||||
return $_POST;
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
namespace App\Router\Request;
|
||||
|
||||
class HttpRequest implements IRequest {
|
||||
private $queryParameters;
|
||||
private $requestParameters;
|
||||
private $method;
|
||||
private $requestUri;
|
||||
private $headers;
|
||||
|
||||
private array $body;
|
||||
|
||||
public function __construct(
|
||||
array $query,
|
||||
array $server,
|
||||
array $headers,
|
||||
ContentStrategy $contentStrategy,
|
||||
array $body
|
||||
) {
|
||||
$this->queryParameters = $query;
|
||||
$this->requestUri = $server['REQUEST_URI'] ?? '';
|
||||
$this->method = strtoupper($server['REQUEST_METHOD'] ?? 'GET');
|
||||
$this->headers = $headers;
|
||||
$this->requestParameters = $contentStrategy->getContent();
|
||||
$this->body = $body;
|
||||
}
|
||||
|
||||
public function getQueryParameters(): array {
|
||||
return $this->queryParameters;
|
||||
}
|
||||
|
||||
public function getRequestParameters(): array {
|
||||
return $this->requestParameters;
|
||||
}
|
||||
|
||||
public function getMethod(): string {
|
||||
return $this->method;
|
||||
}
|
||||
|
||||
public function getRequestUri(): string {
|
||||
return $this->requestUri;
|
||||
}
|
||||
|
||||
public function getHeaders(): array {
|
||||
return $this->headers;
|
||||
}
|
||||
|
||||
public function getBody(): array{
|
||||
return $this->body;
|
||||
}
|
||||
public function addToBody(string|array $attributes){
|
||||
$this->body[] = $attributes;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
namespace App\Router\Request;
|
||||
|
||||
|
||||
interface IRequest
|
||||
{
|
||||
public function getRequestUri();
|
||||
|
||||
public function getBody();
|
||||
public function addToBody(string|array $attributes);
|
||||
|
||||
public function getHeaders();
|
||||
public function getMethod();
|
||||
public function getQueryParameters(): array;
|
||||
public function getRequestParameters(): array;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
namespace App\Router\Request;
|
||||
|
||||
class JsonContentStrategy implements ContentStrategy {
|
||||
public function getContent(): array {
|
||||
$rawContent = file_get_contents('php://input');
|
||||
return json_decode($rawContent, true) ?? [];
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
namespace App\Router\Request;
|
||||
|
||||
class RequestFactory {
|
||||
|
||||
public static function createFromGlobals(): IRequest {
|
||||
$query = $_GET;
|
||||
$server = $_SERVER;
|
||||
$headers = self::getRequestHeaders();
|
||||
|
||||
$contentType = $headers['Content-Type'] ?? '';
|
||||
$contentStrategy = ContentStrategyFactory::createContentStrategy($contentType, $server['REQUEST_METHOD']);
|
||||
|
||||
return new HttpRequest($query, $server, $headers, $contentStrategy,[]);
|
||||
}
|
||||
// should not be heare
|
||||
private static function getRequestHeaders(): array {
|
||||
$headers = [];
|
||||
foreach ($_SERVER as $key => $value) {
|
||||
if (substr($key, 0, 5) === 'HTTP_') {
|
||||
$header = str_replace(' ', '-', ucwords(str_replace('_', ' ', strtolower(substr($key, 5)))));
|
||||
$headers[$header] = $value;
|
||||
}
|
||||
}
|
||||
return $headers;
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
namespace App\Router\Response;
|
||||
|
||||
interface IResponse {
|
||||
public function getContent(): string;
|
||||
public function setContent(string $content): void;
|
||||
public function getStatusCode(): int;
|
||||
public function setStatusCode(int $statusCode): void;
|
||||
public function getHeaders(): array;
|
||||
public function setHeader(string $key, string $value): void;
|
||||
public function send(): void;
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace App\Router\Response;
|
||||
|
||||
class RedirectResponse implements IResponse
|
||||
{
|
||||
private $content;
|
||||
private $statusCode;
|
||||
private $headers;
|
||||
private $url;
|
||||
|
||||
public function __construct(string $url, int $statusCode = 302, array $headers = [])
|
||||
{
|
||||
$this->url = $url;
|
||||
$this->statusCode = $statusCode;
|
||||
$this->headers = $headers;
|
||||
$this->content = '';
|
||||
}
|
||||
|
||||
public function getContent(): string
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function setContent(string $content): void
|
||||
{
|
||||
$this->content = $content;
|
||||
}
|
||||
|
||||
public function getStatusCode(): int
|
||||
{
|
||||
return $this->statusCode;
|
||||
}
|
||||
|
||||
public function setStatusCode(int $statusCode): void
|
||||
{
|
||||
$this->statusCode = $statusCode;
|
||||
}
|
||||
|
||||
public function getHeaders(): array
|
||||
{
|
||||
return $this->headers;
|
||||
}
|
||||
|
||||
public function setHeader(string $key, string $value): void
|
||||
{
|
||||
$this->headers[$key] = $value;
|
||||
}
|
||||
|
||||
public function send(): void
|
||||
{
|
||||
http_response_code($this->statusCode);
|
||||
|
||||
foreach ($this->headers as $name => $value) {
|
||||
header("$name: $value");
|
||||
}
|
||||
|
||||
header("Location: " . $this->url);
|
||||
|
||||
// Optionally echo content if any
|
||||
echo $this->content;
|
||||
|
||||
exit();
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
namespace App\Router\Response;
|
||||
|
||||
class Response implements IResponse {
|
||||
private string $content;
|
||||
private int $statusCode;
|
||||
private array $headers;
|
||||
|
||||
public function __construct(string $content = "", int $statusCode = 200, array $headers = []) {
|
||||
$this->content = $content;
|
||||
$this->statusCode = $statusCode;
|
||||
$this->headers = $headers;
|
||||
}
|
||||
|
||||
public function getContent(): string {
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function setContent(string $content): void {
|
||||
$this->content = $content;
|
||||
}
|
||||
|
||||
public function getStatusCode(): int {
|
||||
return $this->statusCode;
|
||||
}
|
||||
|
||||
public function setStatusCode(int $statusCode): void {
|
||||
$this->statusCode = $statusCode;
|
||||
}
|
||||
|
||||
public function getHeaders(): array {
|
||||
return $this->headers;
|
||||
}
|
||||
|
||||
public function setHeader(string $key, string $value): void {
|
||||
$this->headers[$key] = $value;
|
||||
}
|
||||
|
||||
public function send(): void {
|
||||
foreach ($this->headers as $key => $value) {
|
||||
header("{$key}: {$value}");
|
||||
}
|
||||
http_response_code($this->statusCode);
|
||||
echo $this->content;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -0,0 +1,71 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||
<meta name="description" content="" />
|
||||
<meta name="author" content="" />
|
||||
<title>{% block title %}{% endblock %}</title>
|
||||
<link href="/css/{% block css %}base_theme{% endblock %}.css" rel="stylesheet" />
|
||||
<script src="https://use.fontawesome.com/releases/v6.3.0/js/all.js" crossorigin="anonymous"></script>
|
||||
</head>
|
||||
<body class="bg-primary">
|
||||
<div id="layoutAuthentication">
|
||||
<div id="layoutAuthentication_content">
|
||||
<main>
|
||||
{% block main %}
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-5">
|
||||
<div class="card shadow-lg border-0 rounded-lg mt-5">
|
||||
<div class="card-header"><h3 class="text-center font-weight-light my-4">Connexion</h3></div>
|
||||
<div class="card-body">
|
||||
<form>
|
||||
<div class="form-floating mb-3">
|
||||
<input class="form-control" id="inputEmail" type="email" placeholder="nom@exemple.com" />
|
||||
<label for="inputEmail">Adresse eMail</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input class="form-control" id="inputPassword" type="password" placeholder="Mot de passe" />
|
||||
<label for="inputPassword">Mot de passe</label>
|
||||
</div>
|
||||
<div class="form-check mb-3">
|
||||
<input class="form-check-input" id="inputRememberPassword" type="checkbox" value="" />
|
||||
<label class="form-check-label" for="inputRememberPassword">Mémoriser le mot de passe</label>
|
||||
</div>
|
||||
<div class="d-flex align-items-center justify-content-between mt-4 mb-0">
|
||||
<a class="small" href="password.html">Mot de passe oublié ?</a>
|
||||
<a class="btn btn-primary" href="index.html">Se connecter</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="card-footer text-center py-3">
|
||||
<div class="small"><a href="register.html">Besoin d'un compte ? Inscrivez-vous !</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
</main>
|
||||
</div>
|
||||
<div id="layoutAuthentication_footer">
|
||||
<footer class="py-4 bg-light mt-auto">
|
||||
<div class="container-fluid px-4">
|
||||
<div class="d-flex align-items-center justify-content-between small">
|
||||
<div class="text-muted">Copyright © HeartTrack 2023</div>
|
||||
<div>
|
||||
<a href="#">Politique de confidentialité</a>
|
||||
·
|
||||
<a href="#">Termes & Conditions d'utilisations</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
|
||||
<script src="js/scripts.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,14 @@
|
||||
{% extends "errorbase.html.twig" %}
|
||||
|
||||
{% block title %}{{code}} : {{title}}{% endblock %}
|
||||
|
||||
|
||||
{% block nb %}
|
||||
{% if code == 404 %}
|
||||
<img class="mb-4 img-error" src="assets/img/error-404-monochrome.svg"/>
|
||||
{% else %}
|
||||
<h1 class="display-1">{{code}}</h1>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block descr %}{{descr}}{% endblock %}
|
@ -0,0 +1,33 @@
|
||||
{% extends "base.html.twig" %}
|
||||
|
||||
{% block pp %}{{pp}}{% endblock %}
|
||||
|
||||
{% block css %}{{css}}{% endblock %}
|
||||
|
||||
{% block title %}Exercices - HearthTrack{% endblock %}
|
||||
|
||||
{% block user %}{{user}} - {{role}}{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="container-fluid px-4">
|
||||
<h1 class="mt-4">Exercices</h1>
|
||||
<ol class="breadcrumb mb-4">
|
||||
<li class="breadcrumb-item"><a href="/">Accueil</a></li>
|
||||
<li class="breadcrumb-item active">Exercices</li>
|
||||
</ol>
|
||||
|
||||
<div class="card-body">
|
||||
<div class="datatable-container">
|
||||
<form method="post" action="/exercices">
|
||||
Type : <input type="text" name="type"/>
|
||||
Intensité : <input type="text" name="intensite"/>
|
||||
Date : <input type="text" name="date"/>
|
||||
<button class="btn btn-primary btn-mrg" id="btnNavbarSearch" type="submit">Ajouter l'exercice</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h1>{{responce}}</h1>
|
||||
{% endblock %}
|
@ -0,0 +1,64 @@
|
||||
{% extends "base.html.twig" %}
|
||||
|
||||
{% block pp %}{{pp}}{% endblock %}
|
||||
|
||||
{% block css %}{{css}}{% endblock %}
|
||||
|
||||
{% block title %}Coaching - HearthTrack{% endblock %}
|
||||
|
||||
{% block user %}{{user}} - {{role}}{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="container-fluid px-4">
|
||||
<h1 class="mt-4">Coaching</h1>
|
||||
<ol class="breadcrumb mb-4">
|
||||
<li class="breadcrumb-item"><a href="/">Accueil</a></li>
|
||||
<li class="breadcrumb-item active">Coaching</li>
|
||||
</ol>
|
||||
|
||||
<div class="card-body">
|
||||
<div class="datatable-container">
|
||||
<table id="datatablesSimple" class="datatable-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Nom</th>
|
||||
<th>Prénom</th>
|
||||
<th style="
|
||||
padding-left: 42%;
|
||||
">
|
||||
<form class="d-none d-md-inline-block form-inline ms-auto me-0 me-md-3 my-2 my-md-0" method="get" action="/search-member">
|
||||
<div class="input-group">
|
||||
<input class="form-control" name="username" type="text" placeholder="Rechercher..." aria-label="Rechercher..." aria-describedby="btnNavbarSearch" />
|
||||
<button class="btn btn-primary" id="btnNavbarSearch" type="submit"><i class="fas fa-search"></i></button>
|
||||
</div>
|
||||
</form>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for utili in users %}
|
||||
<tr>
|
||||
<td><style> .image-ronde{ clip-path:ellipse(50% 50%); } </style>
|
||||
<img src="/assets/img/person/{{utili.img}}.png" width="35px" height="35px" class="image-ronde"></td>
|
||||
<td>{{utili.nom}}</td>
|
||||
<td>{{utili.prenom}}</td>
|
||||
<td style="
|
||||
padding-left: 45%;">
|
||||
<form method="post" action="/add-member">
|
||||
<input type="hidden" name="username" value="{{ utili.username }}">
|
||||
<button class="btn btn-primary" type="submit">Ajouter un membre</button>
|
||||
</form>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h1>{{responce}}</h1>
|
||||
{% endblock %}
|
@ -0,0 +1 @@
|
||||
<a href="/log">Se connecter</button>
|
@ -0,0 +1,40 @@
|
||||
{% extends "authbase.html.twig" %}
|
||||
|
||||
{% block css %}{{css}}{% endblock %}
|
||||
|
||||
{% block title %}Connexion - HearthTrack{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-5">
|
||||
<div class="card shadow-lg border-0 rounded-lg mt-5">
|
||||
<div class="card-header"><h3 class="text-center font-weight-light my-4">Connexion</h3></div>
|
||||
<div class="card-body">
|
||||
<form>
|
||||
<div class="form-floating mb-3">
|
||||
<input class="form-control" id="inputEmail" type="email" placeholder="nom@exemple.com" />
|
||||
<label for="inputEmail">Adresse eMail</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input class="form-control" id="inputPassword" type="password" placeholder="Mot de passe" />
|
||||
<label for="inputPassword">Mot de passe</label>
|
||||
</div>
|
||||
<div class="form-check mb-3">
|
||||
<input class="form-check-input" id="inputRememberPassword" type="checkbox" value="" />
|
||||
<label class="form-check-label" for="inputRememberPassword">Mémoriser le mot de passe</label>
|
||||
</div>
|
||||
<div class="d-flex align-items-center justify-content-between mt-4 mb-0">
|
||||
<a class="small" href="password.html">Mot de passe oublié ?</a>
|
||||
<a class="btn btn-primary" href="index.html">Se connecter</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="card-footer text-center py-3">
|
||||
<div class="small"><a href="register.html">Besoin d'un compte ? Inscrivez-vous !</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -0,0 +1,33 @@
|
||||
{% extends "authbase.html.twig" %}
|
||||
|
||||
{% block css %}{{css}}{% endblock %}
|
||||
|
||||
{% block title %}Mot de passe oublié - HearthTrack{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-5">
|
||||
<div class="card shadow-lg border-0 rounded-lg mt-5">
|
||||
<div class="card-header"><h3 class="text-center font-weight-light my-4">Récupération du mot de passe</h3></div>
|
||||
<div class="card-body">
|
||||
<div class="small mb-3 text-muted">Entrez votre adresse eMail pour recevoir un lien pour changer de mot de passe</div>
|
||||
<form method="post" action="/password">
|
||||
<div class="form-floating mb-3">
|
||||
<input class="form-control" id="email" name="email" type="email" placeholder="name@example.com" />
|
||||
<label for="email">Adresse eMail</label>
|
||||
</div>
|
||||
<div class="d-flex align-items-center justify-content-between mt-4 mb-0">
|
||||
<a class="small" href="/log">Retour à la connexion</a>
|
||||
<button class="btn btn-primary" type="submit">Réinitialiser votre mot de passe</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="card-footer text-center py-3">
|
||||
<div class="small"><a href="/regist">Besoin d'un compte ? Inscrivez-vous !</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -0,0 +1,95 @@
|
||||
{% extends "authbase.html.twig" %}
|
||||
|
||||
{% block css %}{{css}}{% endblock %}
|
||||
|
||||
{% block title %}Inscription - HearthTrack{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-7">
|
||||
<div class="card shadow-lg border-0 rounded-lg mt-5">
|
||||
<div class="card-header"><h3 class="text-center font-weight-light my-4">Créer un compte</h3></div>
|
||||
<div class="card-body">
|
||||
<form method="post" action="/register">
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<div class="form-floating mb-3 mb-md-0">
|
||||
<input class="form-control" id="inputFirstName" type="text" placeholder="Entrez votre nom" />
|
||||
<label for="inputFirstName">Nom de famille</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-floating">
|
||||
<input class="form-control" id="inputLastName" type="text" placeholder="Entrez votre prénom" />
|
||||
<label for="inputLastName">Prénom</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<div class="form-floating mb-3 mb-md-0">
|
||||
<label for="inputUsername"></label><input class="form-control" id="inputUsername" type="text" placeholder="Entrez votre pseudonyme" />
|
||||
<label for="inputFirstName">Nom d'utilisateur</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-floating">
|
||||
<label for="inputLastName">Sexe</label>
|
||||
<label for="gender"></label><select id="gender" name="gender">
|
||||
<option value="male">Homme</option>
|
||||
<option value="female">Femme</option>
|
||||
<option value="unknown">Ne se prononce pas</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input class="form-control" id="inputEmail" type="email" placeholder="nom@exemple.com" />
|
||||
<label for="inputEmail">Adresse eMail</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input class="form-control" id="inputDateNaissance" type="date" placeholder="" />
|
||||
<label for="inputEmail">Date de naissance</label>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<div class="form-floating mb-3 mb-md-0">
|
||||
<input class="form-control" id="inputTaille" type="text" placeholder="Entrez votre taille" />
|
||||
<label for="inputPassword">Taille</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-floating mb-3 mb-md-0">
|
||||
<label for="inputPoids"></label><input class="form-control" id="inputPoids" type="text" placeholder="Entrez votre poids" />
|
||||
<label for="inputPasswordConfirm">Poids</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<div class="form-floating mb-3 mb-md-0">
|
||||
<input class="form-control" id="inputPassword" type="password" placeholder="Créez un mot de passe" />
|
||||
<label for="inputPassword">Mot de passe</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-floating mb-3 mb-md-0">
|
||||
<input class="form-control" id="inputPasswordConfirm" type="password" placeholder="Confirmez votre mot de passe" />
|
||||
<label for="inputPasswordConfirm">Confirmer le mot de passe</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 mb-0">
|
||||
<div class="d-grid"><a class="btn btn-primary btn-block" href="login.html.twig">Créer un compte</a></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="card-footer text-center py-3">
|
||||
<div class="small"><a href="login.html.twig">Avez-vous déjà un compte ? Connectez-vous ?</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Views\Directives;
|
||||
use App\Router\Router;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFunction;
|
||||
|
||||
class Navigate extends AbstractExtension
|
||||
{
|
||||
private Router $router;
|
||||
public function __construct( Router $router)
|
||||
{
|
||||
$this->router = $router;
|
||||
}
|
||||
|
||||
public function getFunctions(): array
|
||||
{
|
||||
return [
|
||||
new TwigFunction('navigate', [$this, 'getPath']),
|
||||
];
|
||||
}
|
||||
public function getPath(string $name, array $parameters = []): string
|
||||
{
|
||||
return $this->router->generate($name, $parameters);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
document.getElementById('saveButton').addEventListener('click', function() {
|
||||
var preferences = {
|
||||
notifications: document.getElementById('notif').checked,
|
||||
theme: document.getElementById('theme').value
|
||||
};
|
||||
|
||||
fetch('/savePreferences', {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(preferences),
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => console.log(data))
|
||||
.catch((error) => console.error('Error:', error));
|
||||
});
|
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Console;
|
||||
|
||||
use Manager\ActivityManager;
|
||||
use Manager\AthleteManager;
|
||||
use Manager\CoachManager;
|
||||
use Manager\DataManager;
|
||||
use Manager\UserManager;
|
||||
use Network\RelationshipService;
|
||||
use Stub\NotificationService;
|
||||
use Stub\StubData;
|
||||
|
||||
class Model
|
||||
{
|
||||
public UserManager $userMgr;
|
||||
public CoachManager $coachMgr;
|
||||
public DataManager $dataManager;
|
||||
public AthleteManager $athleteMgr;
|
||||
public ActivityManager $activityMgr;
|
||||
public function __construct()
|
||||
{
|
||||
$this->dataManager = new StubData();
|
||||
$authService = new \Stub\AuthService($this->dataManager->userRepository, new \Shared\HashPassword());
|
||||
$notificationService = new NotificationService($this->dataManager->notificationRepository,$this->dataManager->userRepository);
|
||||
$relationshipService = new RelationshipService($this->dataManager->relationshipRequestRepository,$notificationService);
|
||||
$this->userMgr = new UserManager($this->dataManager,$authService,$relationshipService);
|
||||
$this->athleteMgr = new AthleteManager($this->dataManager,$authService);
|
||||
$this->coachMgr = new CoachManager($this->dataManager,$authService);
|
||||
$this->activityMgr = new ActivityManager($this->dataManager,$authService);
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
<?php
|
||||
namespace Data\Core;
|
||||
|
||||
use Model\User;
|
||||
use Model\Athlete;
|
||||
use Model\CoachAthlete;
|
||||
use Repository\IUserRepository;
|
||||
use Shared\IHashPassword;
|
||||
|
||||
class AuthService implements IAuthService {
|
||||
private IUserRepository $userRepository;
|
||||
private IHashPassword $passwordHacher;
|
||||
private ?User $currentUser = null;
|
||||
|
||||
public function __construct(IUserRepository $userRepository, IHashPassword $passwordHacher) {
|
||||
$this->userRepository = $userRepository;
|
||||
$this->passwordHacher = $passwordHacher;
|
||||
}
|
||||
|
||||
public function login(string $email, string $password): bool {
|
||||
$user = $this->userRepository->getItemByEmail($email);
|
||||
if ($user === null || !$this->validatePassword($password, $user->getPasswordHash())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->currentUser = $user;
|
||||
// Add session handling logic here
|
||||
return true;
|
||||
}
|
||||
|
||||
public function register(string $email, string $password, array $data): bool {
|
||||
if ($this->userRepository->getItemByEmail($email)) {
|
||||
throw new \Exception('User already exists');
|
||||
}
|
||||
|
||||
$hashedPassword = $this->passwordHacher->hashPassword($password);
|
||||
$prenom = $data['prenom'];
|
||||
$username = $data['username'];
|
||||
$nom = $data['nom'];
|
||||
$email = $data['email'];
|
||||
$sexe = $data['sexe'];
|
||||
$taille = $data['taille'];
|
||||
$poids = $data['poids'];
|
||||
$dateNaissance = $data['dateNaissance'] ;
|
||||
$roleName = $data['roleName'];
|
||||
$role = null;
|
||||
if($roleName == "Coach"){
|
||||
$role = new CoachAthlete();
|
||||
}
|
||||
else if($roleName == "Athlete"){
|
||||
$role = new Athlete();
|
||||
}
|
||||
// Create a new user instance (you should expand on this with more data as needed)
|
||||
$user = new User(
|
||||
random_int(0, 100),
|
||||
$nom,
|
||||
$prenom,
|
||||
$username,
|
||||
$email,
|
||||
$hashedPassword,
|
||||
$sexe,
|
||||
$taille,
|
||||
$poids,
|
||||
$dateNaissance,
|
||||
//should use reflexion
|
||||
$role
|
||||
);
|
||||
$this->userRepository->addItem($user);
|
||||
$this->currentUser = $user;
|
||||
// Add session handling logic here
|
||||
return true;
|
||||
}
|
||||
|
||||
public function logout(): void {
|
||||
$this->currentUser = null;
|
||||
// Add session handling logic here
|
||||
}
|
||||
|
||||
public function getCurrentUser(): ?User {
|
||||
return $this->currentUser;
|
||||
}
|
||||
|
||||
private function validatePassword(string $password, string $hash): bool {
|
||||
// Implement password validation logic (e.g., using password_verify if using bcrypt)
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Data\Core;
|
||||
|
||||
class Preferences {
|
||||
private String $cookie;
|
||||
private Array $theme;
|
||||
|
||||
public function __construct(){
|
||||
if (isset($_COOKIE['preferences'])){
|
||||
$this->cookie = $_COOKIE['preferences'];
|
||||
} else {
|
||||
$this->cookie = setcookie('preferences', 'base_theme', time()+(3600*24)*7);
|
||||
}
|
||||
$this->theme = array(
|
||||
'base_theme',
|
||||
'dark_theme',
|
||||
'pink_theme'
|
||||
);
|
||||
}
|
||||
|
||||
public function majCookie(String $maj){
|
||||
try{
|
||||
foreach($this->theme as $t){
|
||||
$this->cookie = $maj;
|
||||
setcookie('preferences', $maj);
|
||||
}
|
||||
} catch (\Exception $e){
|
||||
throw new \ValueError;
|
||||
}
|
||||
}
|
||||
|
||||
public function getCookie():String{
|
||||
return $this->cookie;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue