diff --git a/basededonnee/associations.txt b/basededonnee/associations.txt
new file mode 100644
index 0000000..e69de29
diff --git a/basededonnee/bdphp/connexionsimple.php b/basededonnee/bdphp/connexionsimple.php
new file mode 100644
index 0000000..4a8077c
--- /dev/null
+++ b/basededonnee/bdphp/connexionsimple.php
@@ -0,0 +1,44 @@
+
+
+
+ !!! ERREUR DE CONNEXION !!!
+ Code : = $ex->getCode() ?>
+ Message : = $ex->getMessage() ?>
+
+
Exécution stoppée <-") ;
+}
+
+// Poursuite de l'exécution du script ?>
+Connecté à = $dsn ?>
+
+
diff --git a/basededonnee/codemysql/basedonneee.sql b/basededonnee/codemysql/basedonneee.sql
new file mode 100644
index 0000000..106e50f
--- /dev/null
+++ b/basededonnee/codemysql/basedonneee.sql
@@ -0,0 +1,156 @@
+
+-- MySQL dump 10.13 Distrib 5.5.27, for Win64 (x86)
+--
+-- Host: localhost Database: cinema
+-- ------------------------------------------------------
+-- Server version 5.5.27
+
+
+
+-- note pour l'execution, 'sur mon ordinateur personnel' dans le terminal
+-- sudo mysql --local-infile=1 -p < codemysql/basedonneee.sql (obliger de sudo pour que ca marche sur mon ordi perso)
+-- et aussi sudo mysql -p pour juste lancer
+-- comment faire tourner mon code sur workbench
+-- j'ai modifier les chemins des loads data
+-- pour utiliser un chemin relatif* (car chemin relatif ne marche pas dans
+-- workbench, mais fonctionne dans les fichiers de script. (il doit y avoir une option pour sur WB)
+
+
+
+DROP DATABASE IF EXISTS siterecette;
+CREATE DATABASE siterecette;
+
+DROP USER IF EXISTS 'admin'@'localhost';
+CREATE USER 'admin'@'localhost' IDENTIFIED BY 'adminpass123';
+GRANT ALL PRIVILEGES ON siterecette.* TO 'admin'@'localhost';
+USE siterecette;
+
+--
+-- Table structure for table acteur
+--
+
+DROP TABLE IF EXISTS Recette;
+CREATE TABLE Recette (
+ num_recette INT NOT NULL,
+ titre_recette VARCHAR(60) NOT NULL,
+ slug VARCHAR(200) NOT NULL,
+ description_recette VARCHAR(1000) NOT NULL,
+ photo VARCHAR(200) NOT NULL,
+ publication_date DATE NOT NULL,
+ temps_de_preparation INT NOT NULL
+
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+
+
+
+--
+-- Table structure for table realisateur
+--
+
+DROP TABLE IF EXISTS Tag;
+CREATE TABLE Tag (
+ num_tag INT NOT NULL,
+ nom_tag VARCHAR(30) NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+
+
+--
+-- Table structure for table salle
+--
+
+DROP TABLE IF EXISTS Ingredient;
+CREATE TABLE Ingredient (
+ num_ingredient INT NOT NULL,
+ nom_ingredient INT NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+
+
+--
+-- Table structure for table film
+--
+
+DROP TABLE IF EXISTS Listeingredient;
+CREATE TABLE Listeingredient (
+ num_recette INT NOT NULL,
+ num_ingredient INT NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+
+
+
+--
+-- Table structure for table projection
+--
+
+DROP TABLE IF EXISTS Referencetag;
+CREATE TABLE Referencetag (
+ num_recette INT NOT NULL,
+ num_tag INT NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+
+DROP TABLE IF EXISTS User;
+CREATE TABLE User (
+ num_user INT NOT NULL,
+ username VARCHAR(20) NOT NULL,
+ userpassword VARCHAR(60) NOT NULL
+
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+
+
+
+--
+-- CONTRAINTES
+--
+-- en utilisant les 'alter table' sinon on peut directement les specifier dans les create table
+ALTER TABLE Recette
+ ADD CONSTRAINT pk_recette PRIMARY KEY (num_recette);
+ALTER TABLE Ingredient
+ ADD CONSTRAINT pk_ingredient PRIMARY KEY (num_ingredient);
+ALTER TABLE Tag
+ ADD CONSTRAINT pk_tag PRIMARY KEY (num_tag);
+
+ALTER TABLE User
+ ADD CONSTRAINT pk_user PRIMARY KEY (num_user);
+
+
+ALTER TABLE Listeingredient
+ ADD CONSTRAINT fk_numrecette_ingredient FOREIGN KEY (num_recette) REFERENCES Recette (num_recette),
+ ADD CONSTRAINT fk_recette_numingredient FOREIGN KEY (num_ingredient) REFERENCES Ingredient (num_ingredient);
+
+ALTER TABLE Referencetag
+ ADD CONSTRAINT fk_numrecette_tag FOREIGN KEY (num_recette) REFERENCES Recette (num_recette),
+ ADD CONSTRAINT fk_recette_numtag FOREIGN KEY (num_tag) REFERENCES Tag (num_tag);
+
+-- si besoin exemple de chargement csv
+
+-- LOAD DATA LOCAL INFILE 'nom.csv'
+-- INTO TABLE nom
+-- FIELDS TERMINATED BY ','
+-- ENCLOSED BY '"'
+-- LINES TERMINATED BY '\n'
+-- IGNORE 1 ROWS;
+ -- les chemin ./filename.csv ne marche que dans le terminal avec le cli mysql via la commande $
+
+
+
+-- select * from column;
+
+INSERT INTO Recette (num_recette,titre_recette,slug,description_recette,photo,publication_date,temps_de_preparation)
+values(1,"nomdrecette","slugdpage","descriptiondrecette","urldephoto",'2023-12-31',500),
+(2,"nomdrecette","slugdpage","descriptiondrecette","urldephoto",'2023-12-31',500),
+(3,"nomdrecette","slugdpage","descriptiondrecette","urldephoto",'2023-12-31',500);
+
+
+-- select * from Recette;
+
+-- INSERT INTO Tag (num_tag,nom_tag)
+-- values(1,"nomdtag");
+
+
+-- INSERT INTO Referencetag(num_recette, num_tag)
+-- values(1,1);
+
+-- INSERT INTO Ingredient(num_ingredient,nom_ingredient)
+-- values(2,2);
+
+-- INSERT INTO Listeingredient(num_recette,num_ingredient)
+-- values(1,2);
diff --git a/basededonnee/contraintelisteingredientprobleme.txt b/basededonnee/contraintelisteingredientprobleme.txt
new file mode 100644
index 0000000..7b535b4
--- /dev/null
+++ b/basededonnee/contraintelisteingredientprobleme.txt
@@ -0,0 +1,16 @@
+
+
+quand on créer une recette
+(le but c'est que quand on en créer une
+on est en même temps au moins une instance d'association
+qui enregistre cette recette et ses ingrédients simultanément
+de manière obligatoire)
+
+idée 1 : on ignore l'obligation d'associer une liste d'ingredients a une recette à sa création.
+
+idée 2 : les ingredients d'une liste d'ingredients qui est associés a une recette sont représenter comme une suite de caractère en une ligne séparer par des espace ce qui ferait un seul élément respectant la normalisation 2NF
+
+idée 3 : ajouter des règles de contraintes à la créations d'une recette par exemple quand on créer une recette il faut que ...
+soit dans la base de données soit juste dans le backend
+
+idée ... :
\ No newline at end of file
diff --git a/basededonnee/entité.txt b/basededonnee/entité.txt
new file mode 100644
index 0000000..8210c99
--- /dev/null
+++ b/basededonnee/entité.txt
@@ -0,0 +1,45 @@
+
+
+
+
+recettes ID
+ Titre
+ Slug
+ Description
+ Photo
+ Date d'ajout
+
+
+liste-recettes (entités)
+-Id listerecettes
+
+
+Recette-Ingrédients
+
+ ID_Recette
+ ID_Ingrédient
+
+Recette-Tags
+
+ ID_Recette
+ ID_Tag
+
+Ingrédients
+
+ ID
+ Nom
+ Image
+
+Tag
+
+ ID
+ Nom
+
+Utilisateurs
+
+ ID
+ Username
+ MDP (Hashé, bien entendu...)
+
+
+. Permission (utilisateurs)
diff --git a/basededonnee/test.drawio b/basededonnee/test.drawio
new file mode 100644
index 0000000..ec4b522
--- /dev/null
+++ b/basededonnee/test.drawio
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projetphp/README.md b/projetphp/README.md
new file mode 100644
index 0000000..9a34211
--- /dev/null
+++ b/projetphp/README.md
@@ -0,0 +1,57 @@
+# Les recettes des Papis
+
+## Installation
+ - Décompressez l'archive du site.
+ - Pointez votre domaine sur le dossier "public".
+ - Modifiez les fichiers de configuration dans "config".
+
+## Informations pratiques sur le PHP.
+
+ - Ce site utilise le principe des routes. Afin de ne pas avoir x fichiers publiques identiques pour chaque page.
+ - Tout est géré par le fichier public/index.php.
+ - index.php va charger le Kernel (Noyau) de l'application.
+ - Le noyau fonctionne sur le principe d'élément unique. La méthode ``Kernel::getInstance()`` va permettre d'avoir l'unique instance de la classe Kernel.
+ - Une fois ``Kernel::getInstance()->init()`` déclenché, le noyau enregistre l'autoloading des fichiers, puis enregistre la configuration.
+ - La configuration sont des fichiers dans le dossier config/ qui vont renvoyer un tableau clé/valeur. Exemple
+
+```php
+ // Fichier config/test.php
+ "Val1",
+ 'cle_2' => "Val2",
+ // ...
+ ] ?>
+```
+
+- Les fichiers de configuration sont chargés via la méthode ``ConfigFactory::loadConfigFile()`` qui va vérifier si le fichier de configuration existe et le charge en conséquence.
+- On enchaine ensuite sur le Router.
+- Le Router est une classe utilitaire qui va permettre de faire le lien entre la route saisie ``/test/...`` de l'utilisateur et les routes enregistrés par le site.
+- Le Router va d'abord commencer par récupérer la route voulue par l'utilisateur.
+- Puis, le router va rechercher tous les Controllers existants.
+- Un Controller est une classe qui va permettre de définir les routes et de dire, qu'est-ce qui se passe quand je prends cette route. Les routes du Controller sont définis par la methode ``Controller::defineRoutes()``
+- Pour définir les routes dans la méthode précédente, vous pouvez soit créer un objet ``Route`` en remplissant tous les champs, ou bien la méthode ``Controller::Route()`` qui va préremplir certains champs.
+- Exemple de Controller
+```php
+ class TestController extends Controller {
+
+ public static function defineRoutes(): array {
+ return [
+ self::Route( routeUrl: '/test', routeName: "Test", routeAction: "test" ),
+ new Route( routeUrl: "/test2", routeName: "Test2", routeController: "TestController", routeAction: "test2", routeMethods = [ 'GET' ] )
+ ];
+ }
+
+ public function test(){
+ echo "Je suis déclenché lorsque j'atteinds la route /test";
+ }
+
+ public function test2(){
+ echo "Je suis déclenché lorsque j'atteinds la route /test2 !!!";
+ }
+ }
+```
+- Retournons au routeur, pour chercher les controllers, il va scanner les fichiers du dossier src/Domain avec un Iterator Récursif. (Pour se simplifier un peu la tâche.)
+- Il va traiter le nom du chemin absolu pour obtenir le nom de la classe, puis va vérifier si cette classe est une sous-classe de Controller.
+- Après avoir trouvé tous les Controllers, il va récupérer toutes les routes de chaque controller.
+- Enfin, il va vérifier si la route utilisateur correspond à une des routes dans sa liste, si ça correspond, le Router va charger la méthode ``new {RouteController}()->{RouteAction}()``
+- Si par exemple, le router trouve la route ``/test`` voulu par l'utilisateur, il va déclencher la méthode ``new TestController()->test()``.
\ No newline at end of file
diff --git a/projetphp/config/BDD.php b/projetphp/config/BDD.php
new file mode 100644
index 0000000..6f1ab5d
--- /dev/null
+++ b/projetphp/config/BDD.php
@@ -0,0 +1,53 @@
+
+ Code : = $ex->getCode() ?>
Message : = $ex->getMessage() ?>
+
+
+
+
diff --git a/projetphp/config/general.php b/projetphp/config/general.php
new file mode 100644
index 0000000..862b32d
--- /dev/null
+++ b/projetphp/config/general.php
@@ -0,0 +1,8 @@
+ 'http://127.0.0.1:8080/',
+ 'website_name' => 'Les recettes des Papis',
+
+ 'website_path' => APP_ROOT,
+];
\ No newline at end of file
diff --git a/projetphp/config/route_arguments.php b/projetphp/config/route_arguments.php
new file mode 100644
index 0000000..88b0198
--- /dev/null
+++ b/projetphp/config/route_arguments.php
@@ -0,0 +1,6 @@
+ '([0-9]+)',
+ '{chars}' => '([A-Za-z]+)',
+ '{string}' => '([0-9A-Za-z]+)',
+];
\ No newline at end of file
diff --git a/projetphp/config/views.php b/projetphp/config/views.php
new file mode 100644
index 0000000..28e6f05
--- /dev/null
+++ b/projetphp/config/views.php
@@ -0,0 +1,4 @@
+ 'base'
+];
\ No newline at end of file
diff --git a/projetphp/public/assets/css/style.css b/projetphp/public/assets/css/style.css
new file mode 100644
index 0000000..9e6b0eb
--- /dev/null
+++ b/projetphp/public/assets/css/style.css
@@ -0,0 +1,182 @@
+/* Sommaire :
+- body et html
+- Header et ses contenues
+- Body contenue
+ - Content
+ - Page de présentation des recettes
+ - Page d'une recette
+- Footer
+
+*/
+
+/*Tout*/
+html, body{
+ height: 100%;
+ text-align: center;
+ /*font-size: 98%;*/
+}
+
+
+/*Header et son contenu*/
+#header {
+ display: flex;
+ flex-direction: row;
+ padding: 3px;
+ padding-left: 2%;
+ padding-bottom: 10px;
+ background-color: blanchedalmond;
+}
+
+#logo {
+ background-color: aqua;
+ background-image: url("Logo.jpg");
+ /*background:no-repeat;*/
+ height: 103px;
+ width: 141px;
+}
+
+.logo{
+ height: 100%;
+ width: 100%;
+ border: 1px white solid;
+ border-radius: 4px;
+ box-shadow: 1px 1px 1px black;
+}
+
+nav {
+ flex: 9;
+ text-align: initial;
+ letter-spacing: 2px;
+ padding: 10px;
+}
+
+.nav-list {
+ list-style-type: none;
+ margin: 0;
+ padding: 0;
+ background-color: rgb(255, 217, 160);
+ display: flex;
+ border: 1px solid rgba(0,0,0,.125);
+ border-radius: 40px;
+}
+
+
+.nav-element {
+ line-height: 2.5;
+ padding: 10px;
+}
+
+/*Body et son contenu */
+body {
+ background-color: blanchedalmond;
+ display: flex;
+ flex-direction: column;
+ margin: 0;
+ padding: 0;
+ height: 100%;
+}
+
+.sidebar {
+ background-color: aquamarine;
+ border: 1px solid rgba(0,0,0,.125);
+ border-radius: 10px;
+ width: 128px;
+}
+
+
+.main-body {
+ display: flex;
+ flex-direction: row;
+ overflow: auto;
+ flex: 1;
+ background-clip: border-box;
+ padding-right: 5%;
+ padding-left: 5%;
+}
+
+/* content : le cadre de base du centre de notre site
+*/
+.content {
+ background-color: #ffe4bb;
+ text-align: left;
+ width: 100%;
+ height: 100%;
+ border: 1px solid rgba(0,0,0,.125);
+ border-radius: 6px;
+ overflow: auto;
+}
+
+/*Recettes :
+ représente le contenue centrale de la page.
+*/
+.recettes {
+ --UneVariable: calc( 100vw / 500 );
+ display: grid;
+ grid-template-columns: repeat(var(--UneVariable), 1fr);
+ grid-gap: 10px;
+ grid-auto-rows: minmax(300px, auto);
+ grid-auto-columns: auto;
+}
+
+/* Classe recette icone :
+ C'est la classe de chaques éléments de notre liste de recette
+*/
+.recette-icone{
+ border: 3px solid rgba(0,0,0,.125);
+ border-radius: 40px;
+ text-align: left;
+ padding: 15px;
+ vertical-align: middle;
+ box-shadow: 3px 5px 5px black;
+ width: 500px;
+}
+
+.recette-preview-image{
+ max-width: calc( 10vh + 10vw );
+ max-height: calc( 10vh + 10vw );
+ border: 1px solid rgb(252, 223, 57);
+ border-radius: 25px;
+}
+
+/*Ici commence le CSS pour la page de chaques recettes */
+/*contenue*/
+.recette-content {
+ display: flex;
+ flex-direction: column;
+}
+
+/*titre*/
+.recette-title {
+ text-align: center;
+}
+
+/*image*/
+.recette-image {
+ background-color: red;
+ aspect-ratio: 1/1;
+ max-height: calc( 30vh + 30vw );
+ max-width: calc( 30vh + 30vw );
+ border: 1px solid white;
+ border-radius: 30px;
+}
+
+.recette-div-image {
+ display: flex;
+ justify-content: center;
+}
+
+/*description*/
+.recette-desc {
+ padding : 10px;
+}
+
+
+/*Footer et son contenue*/
+footer{
+ padding: 25px;
+ background: rgb(11, 189, 144);
+ color: white;
+}
+
+
+
diff --git a/projetphp/public/assets/images/Logo.jpg b/projetphp/public/assets/images/Logo.jpg
new file mode 100644
index 0000000..8310814
Binary files /dev/null and b/projetphp/public/assets/images/Logo.jpg differ
diff --git a/projetphp/public/index.php b/projetphp/public/index.php
new file mode 100644
index 0000000..79a13f7
--- /dev/null
+++ b/projetphp/public/index.php
@@ -0,0 +1,28 @@
+getpdo(),$bd->getname());
+
+//public static function add(int $num_recette, string $titre_recette, string $slug, string $description_recette, string $photo, string $publication_date, int $temps_de_preparation ): Bool{
+
+$test::add(5,"a",'a','a','a','2028-12-31',1);
+$recetest = $test::getAll();
+echo $recetest->slug;
diff --git a/projetphp/src/Domain/Controller.php b/projetphp/src/Domain/Controller.php
new file mode 100644
index 0000000..4311c0b
--- /dev/null
+++ b/projetphp/src/Domain/Controller.php
@@ -0,0 +1,38 @@
+ static::class,
+ 'routeMethods' => [ 'GET' ],
+ 'pageHeadTitle' => 'Page',
+ ];
+
+ $args = array_merge($defaults, $args);
+ return new Route( ...$args );
+ }
+
+ /**
+ * Permet de définir les routes du controller sous le format d'une liste d'objets Route.
+ * Vous pouvez utiliser la method self::Route() pour préremplir des champs.
+ *
+ * @return Route[]
+ * @see self::Route()
+ */
+ abstract public static function defineRoutes(): array;
+
+}
\ No newline at end of file
diff --git a/projetphp/src/Domain/Model.php b/projetphp/src/Domain/Model.php
new file mode 100644
index 0000000..940c23b
--- /dev/null
+++ b/projetphp/src/Domain/Model.php
@@ -0,0 +1,12 @@
+
+
+
\ No newline at end of file
diff --git a/projetphp/src/Domain/Pages/PagesController.php b/projetphp/src/Domain/Pages/PagesController.php
new file mode 100644
index 0000000..3d8612b
--- /dev/null
+++ b/projetphp/src/Domain/Pages/PagesController.php
@@ -0,0 +1,35 @@
+ 'bla' ] );
+ }
+
+ public function test( string $id ): void {
+ echo "Coucou" . $id;
+ }
+
+}
\ No newline at end of file
diff --git a/projetphp/src/Domain/Recettes/Recettes.php b/projetphp/src/Domain/Recettes/Recettes.php
new file mode 100644
index 0000000..5912cb5
--- /dev/null
+++ b/projetphp/src/Domain/Recettes/Recettes.php
@@ -0,0 +1,33 @@
+
+column="Recette";
+ $this->num_recette=$num_recette;
+ $this->titre_recette=$titre_recette;
+ $this->slug=$slug;
+ $this->description_recette=$description_recette;
+ $this->photo=$photo;
+ $this->publication_date=$publication_date;
+ $this->temps_de_preparation=$temps_de_preparation;
+
+ }
+
+}
+
+
+
+?>
\ No newline at end of file
diff --git a/projetphp/src/Domain/Recettes/RecettesAPIController.php b/projetphp/src/Domain/Recettes/RecettesAPIController.php
new file mode 100644
index 0000000..ec76612
--- /dev/null
+++ b/projetphp/src/Domain/Recettes/RecettesAPIController.php
@@ -0,0 +1,16 @@
+recettes->list', routeAction: 'list', routeMethods: ['POST'] ),
+ ];
+
+ }
+}
\ No newline at end of file
diff --git a/projetphp/src/Domain/Recettes/RecettesController.php b/projetphp/src/Domain/Recettes/RecettesController.php
new file mode 100644
index 0000000..1ed1dc8
--- /dev/null
+++ b/projetphp/src/Domain/Recettes/RecettesController.php
@@ -0,0 +1,24 @@
+index', routeAction: 'index', pageHeadTitle: 'Liste des recettes' ),
+ self::Route( routeUrl: '/recettes/{string}', routeName: 'recettes->show', routeAction: 'show', pageHeadTitle: 'Recette' ),
+ ];
+
+ }
+
+ public function index(): View {
+ return new View( 'recettes/index', [] );
+ }
+
+}
\ No newline at end of file
diff --git a/projetphp/src/Domain/Recettes/RecettesManagementController.php b/projetphp/src/Domain/Recettes/RecettesManagementController.php
new file mode 100644
index 0000000..1a4cdab
--- /dev/null
+++ b/projetphp/src/Domain/Recettes/RecettesManagementController.php
@@ -0,0 +1,17 @@
+create', routeAction: 'create' ),
+ self::Route( routeUrl: '/recettes/edit/{int}', routeName: 'recettes->edit', routeAction: 'edit' ),
+ ];
+
+ }
+}
\ No newline at end of file
diff --git a/projetphp/src/Domain/Recettes/RecettesRepository.php b/projetphp/src/Domain/Recettes/RecettesRepository.php
new file mode 100644
index 0000000..75b21b7
--- /dev/null
+++ b/projetphp/src/Domain/Recettes/RecettesRepository.php
@@ -0,0 +1,40 @@
+
+
diff --git a/projetphp/src/Domain/Repository.php b/projetphp/src/Domain/Repository.php
new file mode 100644
index 0000000..1d96973
--- /dev/null
+++ b/projetphp/src/Domain/Repository.php
@@ -0,0 +1,99 @@
+
+
+
+prepare($sql) ;
+$statement->execute() or die(var_dump($statement->errorInfo())) ;
+$results = $statement->fetchAll(PDO::FETCH_OBJ) ;
+//print_r($results);
+if(empty($results))return null;
+return (array)$results;
+}
+
+
+public static function selectgetByID($id,$tablename,$idname): ?Recettes{
+$sql = "SELECT * FROM " . $tablename . " WHERE " . $idname ." = " . $id;
+print_r($sql);
+$pdo=BDD::getPDO();
+$statement = $pdo->prepare($sql) ;
+$statement->execute() or die(var_dump($statement->errorInfo())) ;
+$results = $statement->fetchAll(PDO::FETCH_OBJ);
+$valuearray = (array)$results[0];
+//print_r($valuearray);
+//$results = un array de 1 dimension de taille 1 elt avec chaque attribut $result[0]->attribut echo print_r($results[0]->titre_recette);
+if(empty($valuearray))return null;
+return new Recettes(...$valuearray); // '...' unpack l'array et comme les clés correspondent a celles du constructeurs ça marche.
+
+
+}
+
+
+public static function insertaddall(array $attributesattributes,string $tablename,string $attributesname, string $idname): bool{
+
+$pdo = BDD::getPDO();
+
+$sql = "INSERT INTO " . $tablename . " " . $attributesname;
+
+//je vais utiliser bind value car en fonction de quel entitee arrive on a des str ou des int c'est plus dur de generaliser si nécessaire de gerer des ,'str',int,int,'str', etc.
+if(empty($attributesattributes))return false;
+
+$attribtag="val"; $interativ=0;
+$attribbind=" VALUES (";
+foreach($attributesattributes[0] as $a){
+$interativ++;
+$attribtagn=$attribtag . $interativ;
+if($interativ>1){$attribbind = $attribbind . ", ";}
+$attribbind = $attribbind . ":" . $attribtagn;
+}
+$attribbind = $attribbind . ")";
+$query = $sql . $attribbind;
+$statement = $pdo->prepare($query);
+// Liaison des paramètres à des valeurs
+$interativ=0;
+foreach($attributesattributes as $attributes)
+foreach($attributes as $attribute){
+$interativ++;
+$attribtagn=$attribtag . $interativ;
+$statement->bindValue($attribtagn, $attribute);
+}
+$statement->execute() or die(var_dump($statement->errorInfo())) ;
+
+ return true;
+}
+
+
+public static function insertadd(array $attributes,$tablename,$attributesname, $idname, $isentity): bool{
+// vérification id n'existe pas déjà :
+if($isentity){
+$isitalreadyusedid = self::selectgetById($attributes[0],$tablename,$idname); //le dernier param = id, accessible ainsi car simple array des attributs d'une seule entitee,
+// à modifier pour insertall si on fait la verif dedans mais distinguer les array attributs d'entitee et d'association, la verif des associations doit être autre (si idtable1 combinee a idtable2 existe deja dans un même enregistrement)
+if(!empty($isitalreadyusedid)) return false;}
+//je vais utiliser bind value car en fonction de quel entitee arrive on a des str ou des int c'est plus dur de generaliser si nécessaire de gerer des ,'str',int,int,'str', etc.
+//le mieux serait de mettre tout le code de insertadd dans une fonction insertadds qui gère une multiinsertion, insertadd appelle insertadds pour un seul elt.
+(array)$attributesattributes=[$attributes];
+return self::insertaddall($attributesattributes,$tablename,$attributesname,$idname);
+}
+
+}
+
+
+
+
+?>
diff --git a/projetphp/src/Domain/Utilisateurs/AuthentificationController.php b/projetphp/src/Domain/Utilisateurs/AuthentificationController.php
new file mode 100644
index 0000000..04c1d30
--- /dev/null
+++ b/projetphp/src/Domain/Utilisateurs/AuthentificationController.php
@@ -0,0 +1,57 @@
+auth', routeAction: 'auth', routeMethods: ['POST'] ),
+ self::Route( routeUrl: '/api/auth/logout', routeName: 'api->auth->logout', routeAction: 'logout', routeMethods: ['POST'] ),
+
+ ];
+
+ }
+
+ public function login(): View {
+ return new View( 'login' );
+ }
+
+ public function auth(): JSONResponse {
+
+ Request::setCORS();
+
+ $username = Request::get( 'username' );
+ $password = Request::get( 'password' );
+
+ // TODO : Récupération de l'utilisateur et verify_password.
+
+ $userId = 1;
+ Authentification::loginUser( $userId );
+ JSONResponse::sendSuccess( [ 'user_id' => $userId ] );
+
+ }
+
+ public function logout(): JSONResponse {
+
+ if( !Authentification::isLoggedIn() ) {
+ return JSONResponse::sendError( [ 'message' => 'Alrady disconnected' ] );
+ }
+
+ Authentification::destroySession();
+ return JSONResponse::sendSuccess( [ 'message' => 'Logged out' ] );
+
+ }
+
+}
\ No newline at end of file
diff --git a/projetphp/src/Exceptions/ConfigFailedLoadingException.php b/projetphp/src/Exceptions/ConfigFailedLoadingException.php
new file mode 100644
index 0000000..aea3887
--- /dev/null
+++ b/projetphp/src/Exceptions/ConfigFailedLoadingException.php
@@ -0,0 +1,28 @@
+configFilePath = $configFilePath;
+ $this->message = "Failed to load configuration file '{$configFilePath}'.";
+ parent::__construct();
+ }
+
+}
\ No newline at end of file
diff --git a/projetphp/src/Exceptions/InvalidRouteException.php b/projetphp/src/Exceptions/InvalidRouteException.php
new file mode 100644
index 0000000..4b97e00
--- /dev/null
+++ b/projetphp/src/Exceptions/InvalidRouteException.php
@@ -0,0 +1,15 @@
+clientRoute = $clientRoute;
+ $message = "{$clientRoute} doesn't exist";
+ parent::__construct($message, 404);
+ }
+
+}
\ No newline at end of file
diff --git a/projetphp/src/Exceptions/InvalidViewException.php b/projetphp/src/Exceptions/InvalidViewException.php
new file mode 100644
index 0000000..9447cde
--- /dev/null
+++ b/projetphp/src/Exceptions/InvalidViewException.php
@@ -0,0 +1,13 @@
+data = $data;
+ $this->htmlCode = $code;
+
+ $this->returnResponse();
+ }
+
+ public function returnResponse(): never {
+
+ header( 'Content-type: application/json' );
+ http_response_code( $this->htmlCode );
+
+ $this->data['_status'] = $this->htmlCode;
+ $json = json_encode( $this->data );
+ echo $json;
+ die();
+ }
+
+ public static function sendSuccess( $data = [] ): self {
+ $data['success'] = true;
+ return new self( $data, 200 );
+ }
+
+ public static function sendError( $data = [] ): self {
+ $data['success'] = false;
+ return new self( $data, 400 );
+ }
+
+}
\ No newline at end of file
diff --git a/projetphp/src/Http/Request.php b/projetphp/src/Http/Request.php
new file mode 100644
index 0000000..7172602
--- /dev/null
+++ b/projetphp/src/Http/Request.php
@@ -0,0 +1,53 @@
+.
+ */
+ public function __construct(
+ string $routeUrl,
+ string $routeName,
+ string $routeController,
+ string $routeAction,
+ array $routeMethods,
+ string $pageHeadTitle,
+ ){
+ $this->routeUrl = $routeUrl;
+ $this->routeName = $routeName;
+ $this->routeController = $routeController;
+ $this->routeAction = $routeAction;
+ $this->routeMethods = $routeMethods;
+ $this->pageHeadTitle = $pageHeadTitle;
+ }
+
+}
\ No newline at end of file
diff --git a/projetphp/src/Http/Router.php b/projetphp/src/Http/Router.php
new file mode 100644
index 0000000..907a5ff
--- /dev/null
+++ b/projetphp/src/Http/Router.php
@@ -0,0 +1,199 @@
+routeMethods ) ){
+ throw new InvalidRouteException( self::$clientRouteString );
+ } else {
+ self::executeRouteAction();
+ }
+
+ }
+
+ /**
+ * Permet de récupérer tous les controllers du dossier Domain.
+ * @return class-string[]
+ */
+ private static function fetchControllers(): array {
+
+ $classes = [];
+
+ $iterator = new \RecursiveIteratorIterator(
+ new \RecursiveDirectoryIterator( APP_ROOT . 'src/Domain', FilesystemIterator::SKIP_DOTS ),
+ );
+
+ foreach( $iterator as $file ){
+
+ if( $file->isFile() && $file->getExtension() === 'php' ){
+
+ $fileName = $file->getPathname();
+
+ // Transformation du chemin du fichier vers le nom complet de la classe.
+ $fileName = str_replace( APP_ROOT . 'src/', AutoLoader::PRIMARY_NAMESPACE, $fileName );
+ $fileName = str_replace( '.php', '', $fileName );
+ $fileName = str_replace( '/', '\\', $fileName );
+
+
+ /*
+ * Vérifie que l'on est bien sur un Controller.
+ * Ignore Controller car Controller n'est pas une sous-classe de Controller.
+ */
+ if( is_subclass_of( $fileName, Controller::class ) ){
+ $classes[] = $fileName;
+ }
+
+ }
+
+ }
+
+ return $classes;
+
+ }
+
+ /**
+ * Récupérer toutes les routes des controllers récupéré avant.
+ * @return Route[]
+ */
+ private static function fetchRoutes(): array {
+
+ $routes = [];
+
+ foreach( self::$controllers as $controllerClassString ){
+ $routes = array_merge( $routes, $controllerClassString::defineRoutes() );
+ }
+
+ return $routes;
+ }
+
+ /**
+ * Permet de savoir si la route que le client veut existe.
+ * @return Route|bool Retourne la route de l'utilisateur ou false si inexistante.
+ */
+ private static function clientRouteExist(): Route|bool {
+
+ $clientRouteName = trim( self::$clientRouteString, '/' );
+
+ foreach( self::$routes as $route ){
+
+ $routeName = self::getRegexRoute( $route );
+ if( preg_match( $routeName, $clientRouteName, $matches ) ){
+ array_shift( $matches ); // On enlève la chaine complète.
+ self::$clientRouteArguments = $matches;
+ return $route;
+ }
+ }
+
+ return false;
+
+ }
+
+ /**
+ * Permet de remplacer les expressions définies dans la configuration par leurs équivalents Regex.
+ *
+ * @param Route $route
+ * @return string
+ */
+ private static function getRegexRoute( Route $route ): string {
+ $routeUrl = trim( $route->routeUrl, '/' );
+ foreach ( Kernel::$configs['route_arguments'] as $key => $value ){
+ $routeUrl = str_replace( $key, $value, $routeUrl );
+ }
+ return "#^{$routeUrl}$#";
+ }
+
+ /**
+ * Va permettre d'exécuter la méthode du Controller→action() en parsant les arguments si existants.
+ * @return void
+ */
+ private static function executeRouteAction(): void {
+ $controller = self::$clientRoute->routeController;
+ $method = self::$clientRoute->routeAction;
+
+ new $controller()->$method( ...self::$clientRouteArguments);
+ }
+
+ /**
+ * Permet d'obtenir l'adresse du site vers une route spécifique.
+ *
+ * @param string $routeName Le nom de la route.
+ * @param ...$args - Les arguments de la route, si existants.
+ *
+ * @return string Renvoie l'URL demandé ou bien la racine du site si la route n'existe pas.
+ */
+ public static function getRouteURL( string $routeName, ...$args ): string {
+ foreach( self::$routes as $route ){
+ if( $routeName === $route->routeName ){
+ $i = 0;
+ $routeUrl = preg_replace_callback( '/\{([^}]+)}/', function( $match ) use ( $args, &$i ){
+ return $args[$i++] ?? "";
+ }, $route->routeUrl);
+
+ return rtrim( Kernel::$configs['general']['website_url'] . $routeUrl, '/' );
+ }
+ }
+
+ return Kernel::$configs['general']['website_url'];
+ }
+
+ public static function getAssetURL( string $assetPath ): string {
+ return Kernel::$configs['general']['website_url'] . 'assets/' . $assetPath;
+ }
+
+}
\ No newline at end of file
diff --git a/projetphp/src/Infrastructure/View.php b/projetphp/src/Infrastructure/View.php
new file mode 100644
index 0000000..88ee12f
--- /dev/null
+++ b/projetphp/src/Infrastructure/View.php
@@ -0,0 +1,220 @@
+
+ */
+ public private(set) array $integratedContent;
+
+ /**
+ * Garde la dernière instance de vue.
+ * Si il y a un squelette, ce sera l'instance du squelette.
+ *
+ * @var View
+ */
+ private static self $lastInstance;
+
+ /**
+ * Permet de construire les informations de la vue.
+ *
+ * @param string $viewName Le nom du fichier de vue.
+ * @param array $viewArgs Les arguments de la vue.
+ * @param bool $autoRender Si la méthode $this->render() est automatiquement exécuté.
+ * @param string|null $skeleton Le squelette du fichier, null correspond à aucun squelette, default correspond au
+ * squelette défini dans la configuration des vues.
+ * @param array $integratedContent Le contenu intégré dans le nouveau squelette.
+ */
+ public function __construct(
+ string $viewName,
+ array $viewArgs = [],
+ bool $autoRender = true,
+ ?string $skeleton = 'default',
+ array $integratedContent = []
+ ) {
+
+ if( !str_ends_with( $viewName, '.php' ) ) {
+ $viewName .= '.php';
+ }
+
+ $this->viewName = $viewName;
+ $this->viewArgs = $viewArgs;
+
+ $this->skeleton = $skeleton;
+ if( $this->skeleton === "default" ){
+ $this->skeleton = Kernel::$configs['views']['base_view_skeleton'];
+ }
+
+ $this->integratedContent = $integratedContent;
+
+ try {
+ if (!file_exists(self::VIEW_PATH . $this->viewName)) {
+ throw new InvalidViewException($this->viewName);
+ }
+
+ if ($autoRender) {
+ $this->render();
+ }
+ } catch (InvalidViewException $e) {
+ die( $e->getMessage() );
+ }
+
+ }
+
+ /**
+ * Permet de démarrer le rendu d'une vue.
+ * @return void
+ */
+ public function startView(): void {
+ ob_start();
+ }
+
+ /**
+ * Permet de finir le rendu d'une vue.
+ * @return void
+ */
+ public function endView(): void {
+ echo ob_get_clean();
+ }
+
+ /**
+ * Permet de faire le rendu proprement de la vue.
+ * @return void
+ */
+ public function render(): void {
+
+ self::$lastInstance = $this;
+
+ if( $this->skeleton === null ){
+
+ // Si on a pas de squelette, on inclut la vue.
+ // pour accéder aux éléments de la vue, on utilise les méthodes statiques de cette classe.
+ $this->startView();
+ require self::VIEW_PATH . $this->viewName;
+ $this->endView();
+
+ } else {
+
+ // Si on a un squelette, on charge tout le contenu de la vue enfante.
+ $contentName = $this->viewName;
+
+ // On démarre la vue du squelette.
+ $base = new View( $this->skeleton, $this->viewArgs, skeleton: null, integratedContent: [ 'content' => $contentName ] );
+
+ }
+
+
+ }
+
+ /*
+ * VIEW TOOLS
+ */
+
+ /**
+ * Permet d'injecter un contenu sauvegardé dans $this->integratedContent.
+ *
+ * @param string $integratedContentName
+ * @return void N'affiche rien si le contenu n'existe pas.
+ */
+ public static function inject( string $integratedContentName ): void {
+ if( isset( self::$lastInstance->integratedContent[ $integratedContentName ] ) )
+ require self::VIEW_PATH . self::$lastInstance->integratedContent[ $integratedContentName ];
+ }
+
+ /**
+ * Permet de récupérer un argument passé à la vue.
+ *
+ * @param string $argumentName
+ * @return mixed null si l'argument n'existe pas.
+ */
+ public static function arg( string $argumentName ): mixed {
+ if( isset( self::$lastInstance->viewArgs[ $argumentName ] ) )
+ return self::$lastInstance->viewArgs[ $argumentName ];
+ return null;
+ }
+
+ /**
+ * Permet d'intégrer un bloc à la vue.
+ *
+ * @param string $partialName
+ * @return void N'affiche rien si le bloc n'existe pas.
+ */
+ public static function partial( string $partialName ): void {
+
+ if( !str_ends_with( $partialName, '.php' ) ) {
+ $partialName .= '.php';
+ }
+
+ if( file_exists( self::VIEW_PATH . 'partials/' . $partialName ) ) {
+ require self::VIEW_PATH . 'partials/' . $partialName;
+ }
+ }
+
+ /**
+ * Permet d'obtenir le titre de la page à mettre dans
+ * @return string
+ */
+ public static function getHeadTitle(): string {
+ $siteUrl = Kernel::$configs['general']['website_name'];
+ return Router::$clientRoute->pageHeadTitle . ' - ' . $siteUrl;
+ }
+
+ /**
+ * Permet d'obtenir une route
+ *
+ * @param string $routeName Le nom de la route.
+ * @param ...$args - Les arguments de la route, si existant.
+ *
+ * @return void Affiche uniquement.
+ */
+ public static function routeUrl( string $routeName, ...$args ): void {
+ echo Router::getRouteURL( $routeName, ...$args );
+ }
+
+ /**
+ * Permet d'obtenir l'URL vers un asset (CSS,JS,Images).
+ * @param string $assetPath
+ *
+ * @return void
+ */
+ public static function assetUrl( string $assetPath ): void {
+ echo Router::getAssetURL( $assetPath );
+ }
+
+}
\ No newline at end of file
diff --git a/projetphp/src/Kernel.php b/projetphp/src/Kernel.php
new file mode 100644
index 0000000..83017c6
--- /dev/null
+++ b/projetphp/src/Kernel.php
@@ -0,0 +1,100 @@
+ [ 'cle" → valeur ] ]
+ *
+ * @var array
+ */
+ public private(set) static array $configs = [];
+
+ /**
+ * Instance actuelle de l'application.
+ * @var Kernel|null
+ */
+ private static ?self $instance = null;
+
+ /**
+ * Méthode qui permet de démarrer le site.
+ * @return self
+ */
+ public static function start(): self {
+ self::$instance = new self();
+ self::$instance->init();
+ return self::$instance;
+ }
+
+ /**
+ * Permet d'obtenir l'instance actuelle du site.
+ * @return self
+ */
+ public static function getInstance(): self {
+ return self::$instance;
+ }
+
+ /**
+ * Constructeur.
+ */
+ public function __construct() {
+ }
+
+ /**
+ * Permet de préparer le démarrage du site.
+ * Lancé automatiquement par start().
+ *
+ * @return void
+ * @see self::start()
+ */
+ public function init(): void {
+ $this->buildAutoloader();
+ $this->loadConfig();
+
+ Authentification::startSession();
+
+ try {
+ Router::routeTo();
+ } catch ( InvalidRouteException $e ){
+ die( $e->getMessage() );
+ }
+ }
+
+ /**
+ * Permet de mettre en place l'Autoloader.
+ * @return void
+ */
+ private function buildAutoloader(): void {
+ require_once 'Helpers/AutoLoader.php';
+ AutoLoader::register();
+ }
+
+ /**
+ * Permet de charger tous les fichiers de configuration du site.
+ * @return void
+ */
+ private function loadConfig(): void {
+ try {
+
+ self::$configs['general'] = ConfigFactory::loadConfigFile('general');
+ self::$configs['route_arguments'] = ConfigFactory::loadConfigFile('route_arguments');
+ self::$configs['views'] = ConfigFactory::loadConfigFile('views');
+
+ } catch( ConfigFailedLoadingException $e ){
+ die( $e->getMessage() );
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/projetphp/views/base.php b/projetphp/views/base.php
new file mode 100644
index 0000000..2a8631b
--- /dev/null
+++ b/projetphp/views/base.php
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/projetphp/views/home.php b/projetphp/views/home.php
new file mode 100644
index 0000000..3cb93ff
--- /dev/null
+++ b/projetphp/views/home.php
@@ -0,0 +1,2 @@
+Coucou
+
\ No newline at end of file
diff --git a/projetphp/views/partials/footer.php b/projetphp/views/partials/footer.php
new file mode 100644
index 0000000..8015192
--- /dev/null
+++ b/projetphp/views/partials/footer.php
@@ -0,0 +1,14 @@
+
+
+
+