ajoutUtilisateurs
This commit is contained in:
58
README.md
58
README.md
@@ -1,3 +1,57 @@
|
||||
# Les Recettes des Papis
|
||||
# Les recettes des Papis
|
||||
|
||||
modif sur la partie bd jusqu'au 30/03/26 a 15h
|
||||
## 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
|
||||
<?php return [
|
||||
'cle_1' => "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()``.
|
||||
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
$db_name = "gamesdb" ; // Nom de la base de données (pré-existante)
|
||||
$db_host = "127.0.0.1" ; // Si le serveur MySQL est sur la machine locale
|
||||
$db_port = "3306" ; // Port par défaut de MySQL
|
||||
|
||||
// Informations d'authentification de votre script PHP
|
||||
$db_user = "gameuse" ; // Utilisateur par défaut de MySQL (... à changer)
|
||||
$db_pwd = "MyStrongPassword123!" ; // Mot de passe par défaut pour l'utilisateur root (.. à changer !!!)
|
||||
//GRANT ALL PRIVILEGES ON gamesdb.* TO 'gameuse'@'localhost';
|
||||
//gameuse'@'localhost'
|
||||
//MyStrongPassword123
|
||||
// Connexion à la BDD
|
||||
//j'ai fabriquer cet utilisateur spécialement pour cette exo sur le serv
|
||||
//mysql
|
||||
// Connexion à la BDD
|
||||
|
||||
// Connexion à la BDD
|
||||
try{
|
||||
// Agrégation des informations de connexion dans une chaine DSN (Data Source Name)
|
||||
$dsn = 'mysql:dbname=' . $db_name . ';host='. $db_host. ';port=' . $db_port;
|
||||
|
||||
// Connexion et récupération de l'objet connecté
|
||||
$pdo = new PDO($dsn, $db_user, $db_pwd);
|
||||
|
||||
}
|
||||
|
||||
// Récupération d'une éventuelle erreur
|
||||
catch (\Exception $ex){ ?>
|
||||
<!-- Affichage des informations liées à l'erreur-->
|
||||
<div style="color: red">
|
||||
<b>!!! ERREUR DE CONNEXION !!!</b><br>
|
||||
Code : <?= $ex->getCode() ?><br>
|
||||
Message : <?= $ex->getMessage() ?>
|
||||
|
||||
</div><?php
|
||||
// Arrêt de l'exécution du script PHP
|
||||
die("-> Exécution stoppée <-") ;
|
||||
}
|
||||
|
||||
// Poursuite de l'exécution du script ?>
|
||||
<div style="color: green">Connecté à <b><?= $dsn ?></b></div> <?php ?>
|
||||
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
|
||||
-- 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);
|
||||
@@ -1,16 +0,0 @@
|
||||
|
||||
|
||||
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 ... :
|
||||
@@ -1,45 +0,0 @@
|
||||
|
||||
|
||||
|
||||
|
||||
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)
|
||||
@@ -1,103 +0,0 @@
|
||||
<mxfile host="65bd71144e">
|
||||
<diagram id="i3f546belnF2-wjsbEOy" name="Page-1">
|
||||
<mxGraphModel dx="1489" dy="755" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0"/>
|
||||
<mxCell id="1" parent="0"/>
|
||||
<mxCell id="2" value="Recette" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=26;fillColor=none;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="300" y="232" width="170" height="182" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="3" value="(PK)idrecette" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;whiteSpace=wrap;html=1;" vertex="1" parent="2">
|
||||
<mxGeometry y="26" width="170" height="26" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="4" value="titrerecette varchar(60)" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;whiteSpace=wrap;html=1;" vertex="1" parent="2">
|
||||
<mxGeometry y="52" width="170" height="26" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="14" value="slug varchar(200) (idweb)" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;whiteSpace=wrap;html=1;" vertex="1" parent="2">
|
||||
<mxGeometry y="78" width="170" height="26" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="15" value="Description varchar(1000)&nbsp;" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;whiteSpace=wrap;html=1;" vertex="1" parent="2">
|
||||
<mxGeometry y="104" width="170" height="26" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="16" value="photo (url) varchar(200)" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;whiteSpace=wrap;html=1;" vertex="1" parent="2">
|
||||
<mxGeometry y="130" width="170" height="26" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="17" value="publicationdate DATE" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;whiteSpace=wrap;html=1;" vertex="1" parent="2">
|
||||
<mxGeometry y="156" width="170" height="26" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="6" value="Referencetag" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=26;fillColor=none;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="140" y="320" width="111" height="78" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="8" value="(FK)idrecette" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;whiteSpace=wrap;html=1;" vertex="1" parent="6">
|
||||
<mxGeometry y="26" width="111" height="26" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="9" value="(FK)idtag" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;whiteSpace=wrap;html=1;" vertex="1" parent="6">
|
||||
<mxGeometry y="52" width="111" height="26" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="10" value="Tag" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=26;fillColor=none;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="-60" y="340" width="121" height="78" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="11" value="(PK)idtag" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;whiteSpace=wrap;html=1;" vertex="1" parent="10">
|
||||
<mxGeometry y="26" width="121" height="26" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="19" value="nomtag varchar(30)" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;whiteSpace=wrap;html=1;" vertex="1" parent="10">
|
||||
<mxGeometry y="52" width="121" height="26" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="23" value="" style="endArrow=none;html=1;exitX=1;exitY=0;exitDx=0;exitDy=0;entryX=0;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="10" target="6">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="360" y="410" as="sourcePoint"/>
|
||||
<mxPoint x="410" y="360" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="24" value="" style="endArrow=none;html=1;entryX=0;entryY=0;entryDx=0;entryDy=0;exitX=1;exitY=0;exitDx=0;exitDy=0;" edge="1" parent="1" source="6" target="2">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="200" y="300" as="sourcePoint"/>
|
||||
<mxPoint x="290" y="240" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="28" value="1,n" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="50" y="334" width="60" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="31" value="1,1" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="250" y="238" width="60" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="338" value="" style="endArrow=none;html=1;exitX=0.982;exitY=1.115;exitDx=0;exitDy=0;entryX=0;entryY=0;entryDx=0;entryDy=0;exitPerimeter=0;" edge="1" parent="1" source="354" target="2">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="350" y="80" as="sourcePoint"/>
|
||||
<mxPoint x="310" y="250" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="339" value="1,1" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="280" y="202" width="60" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="341" value="" style="endArrow=none;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=-0.018;exitY=1;exitDx=0;exitDy=0;exitPerimeter=0;" edge="1" parent="1" source="354" target="342">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="-5" y="90" as="sourcePoint"/>
|
||||
<mxPoint x="60" y="130" as="targetPoint"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="342" value="Ingredient" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=26;fillColor=none;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="-40" y="190" width="121" height="78" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="343" value="(PK)idingredient" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;whiteSpace=wrap;html=1;" vertex="1" parent="342">
|
||||
<mxGeometry y="26" width="121" height="26" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="344" value="nomtag varchar(30)" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;whiteSpace=wrap;html=1;" vertex="1" parent="342">
|
||||
<mxGeometry y="52" width="121" height="26" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="345" value="1,n" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
|
||||
<mxGeometry y="160" width="60" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="351" value="Listeingredient" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=26;fillColor=none;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="140" y="70" width="111" height="78" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="353" value="(FK)idrecette" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;whiteSpace=wrap;html=1;" vertex="1" parent="351">
|
||||
<mxGeometry y="26" width="111" height="26" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="354" value="(FK)idingredient" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;whiteSpace=wrap;html=1;" vertex="1" parent="351">
|
||||
<mxGeometry y="52" width="111" height="26" as="geometry"/>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
9
config/database.php
Normal file
9
config/database.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'host' => 'localhost',
|
||||
'port' => 3306,
|
||||
'user' => 'admin',
|
||||
'pass' => 'adminpass123',
|
||||
'name' => 'siterecette'
|
||||
];
|
||||
@@ -1,57 +0,0 @@
|
||||
# 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
|
||||
<?php return [
|
||||
'cle_1' => "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()``.
|
||||
@@ -1,53 +0,0 @@
|
||||
<?php
|
||||
|
||||
class BDD{
|
||||
|
||||
private static ?PDO $pdo=null;
|
||||
public const DB_NAME = 'siterecette';
|
||||
private static string $db_name=BDD::DB_NAME;
|
||||
|
||||
|
||||
public static function getPDO(){
|
||||
|
||||
if(self::$pdo==null){
|
||||
$db_host = "127.0.0.1" ; $db_port = "3306" ;
|
||||
// identifiant
|
||||
$db_user = "admin" ; $db_pwd = "adminpass123" ;
|
||||
|
||||
// connection a la database
|
||||
try{
|
||||
$dsn = 'mysql:dbname=' . self::$db_name . ';host='. $db_host. ';port=' . $db_port;
|
||||
$pdoo = new PDO($dsn, $db_user, $db_pwd);
|
||||
}
|
||||
|
||||
//erreur?
|
||||
catch (\Exception $ex){ ?>
|
||||
Code : <?= $ex->getCode() ?><br> Message : <?= $ex->getMessage() ?>
|
||||
<?php
|
||||
die("message d'arreet connexion stopee") ;}
|
||||
|
||||
self::$pdo = $pdoo;
|
||||
}
|
||||
return self::$pdo;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function getname(){
|
||||
return self::$db_name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
?>
|
||||
|
||||
|
||||
|
||||
@@ -1,182 +0,0 @@
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Kernel;
|
||||
|
||||
if( !defined( 'APP_ROOT' ) )
|
||||
|
||||
/**
|
||||
* Définit la racine de l'application en chemin absolue.
|
||||
*/
|
||||
define( 'APP_ROOT', realpath( __DIR__ . '/../') . '/' );
|
||||
|
||||
//require_once '../src/Kernel.php';
|
||||
//Kernel::start();
|
||||
echo "bonjour";
|
||||
|
||||
require '../config/BDD.php';
|
||||
require '../src/Domain/Repository.php';
|
||||
|
||||
require_once '../src/Domain/Recettes/Recettes.php';
|
||||
require '../src/Domain/Recettes/RecettesRepository.php';
|
||||
$bd = new BDD();
|
||||
$test = new RecettesRepository($bd->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;
|
||||
@@ -1,12 +0,0 @@
|
||||
|
||||
|
||||
<?php
|
||||
|
||||
class Model{
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,33 +0,0 @@
|
||||
|
||||
<?php
|
||||
|
||||
class Recettes { // extends Model {
|
||||
|
||||
public int $num_recette;
|
||||
public string $titre_recette; //inférieur ou égal a 60
|
||||
public string $slug; //max = 200
|
||||
public string $description_recette; // max 1000
|
||||
public string $photo; // max 200, url
|
||||
public string $publication_date; //une date
|
||||
public int $temps_de_preparation; //en minute;
|
||||
//public DateTime date;
|
||||
public string $column;
|
||||
|
||||
public function __construct(int $num_recette, string $titre_recette, string $slug,
|
||||
string $description_recette, string $photo, string $publication_date, int $temps_de_preparation){
|
||||
$this->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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
?>
|
||||
@@ -1,40 +0,0 @@
|
||||
|
||||
<?php
|
||||
|
||||
class RecettesRepository extends Repository{
|
||||
|
||||
private static string $nomBDD=BDD::DB_NAME;
|
||||
private static string $tablename="Recette"; //tablename
|
||||
private static string $attributesname="(num_recette,titre_recette,slug,description_recette,photo,publication_date,temps_de_preparation)";
|
||||
private static string $idname="num_recette";
|
||||
|
||||
|
||||
public function __construct(){
|
||||
}
|
||||
|
||||
public static function getAll(): ?array{
|
||||
return parent::selectgetAll(self::$tablename);
|
||||
}
|
||||
|
||||
|
||||
public static function getByID($id): ?Recettes{
|
||||
return parent::selectgetByID($id,self::$tablename,self::$idname);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//on peut passer un array (ou objet sous forme (array)objet) en paramètre à la place de tout les autres paramètres avec (...array) au choix, pas de tableaux en paramètre normal pour éviter d'envoyer un mauvais tableaux
|
||||
//ca généralise quand même si chaque array pour différentes entitees sont scannee comme parametre car chacun ont leurs propre attributs
|
||||
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{
|
||||
(array)$attributes=[ $num_recette, $titre_recette, $slug, $description_recette, $photo, $publication_date, $temps_de_preparation];
|
||||
return parent::insertadd($attributes,self::$tablename,self::$attributesname,self::$idname,1); //le '1' car isentity, on vérifie que existe pas dejaa avec cet id
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
?>
|
||||
@@ -1,99 +0,0 @@
|
||||
|
||||
|
||||
|
||||
<?php
|
||||
|
||||
class Repository{
|
||||
|
||||
//private static string $nomBDD;
|
||||
//private static string $attributesname;
|
||||
//private static ?PDO $pdo;
|
||||
|
||||
|
||||
//public function __construct(?PDO $pdoo, string $nombdd){
|
||||
//self::$pdo=$pdoo; self::$nomBDD = $nombdd; self::$column="Recette";
|
||||
//self::$attributesname="(num_recette,titre_recette,slug,description_recette,photo,publication_date)";
|
||||
//}
|
||||
//les infos nécessaires sont passé par les classe filles
|
||||
|
||||
public static function selectgetAll($tablename): ?array{
|
||||
$sql = "SELECT * FROM " . $tablename;
|
||||
$pdo=BDD::getPDO();
|
||||
$statement = $pdo->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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
?>
|
||||
@@ -1,2 +0,0 @@
|
||||
<h1>Coucou</h1>
|
||||
<?php echo \App\Http\Router::getRouteURL( 'test', 3 ); ?>
|
||||
@@ -1,23 +0,0 @@
|
||||
<?php use App\Infrastructure\View as V; ?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title><?php echo V::getHeadTitle(); ?></title>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="stylesheet" href="<?php V::assetUrl( 'css/style.css' ); ?>" />
|
||||
</head>
|
||||
<body>
|
||||
<header id="header">x
|
||||
<div id="logo">
|
||||
<a href="index.php">
|
||||
<img src="<?php V::assetUrl( 'images/Logo.jpg' ); ?>" class="logo">
|
||||
</a>
|
||||
</div>
|
||||
<nav>
|
||||
<ul class="nav-list">
|
||||
<li><a id="google" class="nav-element" href="google.com">Google</a></li>
|
||||
<li><a id="unTest" class="nav-element" href="bing.com">Bing</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
@@ -1,20 +0,0 @@
|
||||
<?php use App\Infrastructure\View as V; ?>
|
||||
|
||||
<div class="sidebar"> une sidebar</div>
|
||||
<div class="content">
|
||||
<div class="recettes">
|
||||
<a href="recette-en-dur.php">
|
||||
<div class="recette-icone">
|
||||
<img class="recette-preview-image" src="random-recette.jpg">
|
||||
</div>
|
||||
</a>
|
||||
<div class="recette-icone"> 2 </div>
|
||||
<div class="recette-icone"> 3 </div>
|
||||
<div class="recette-icone"> 4 </div>
|
||||
<div class="recette-icone"> 5 </div>
|
||||
<div class="recette-icone"> 6 </div>
|
||||
<div class="recette-icone"> 7 </div>
|
||||
<div class="recette-icone"> 8 </div>
|
||||
<div class="recette-icone"> 9 </div>
|
||||
</div>
|
||||
</div>
|
||||
462
public/assets/css/style.css
Normal file
462
public/assets/css/style.css
Normal file
@@ -0,0 +1,462 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100..900;1,100..900&display=swap');
|
||||
/* 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%;*/
|
||||
font-family: "Roboto", sans-serif;
|
||||
}
|
||||
|
||||
|
||||
/*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;
|
||||
}
|
||||
|
||||
.logo:hover{
|
||||
box-shadow: 1px 1px 2px #0bbd90;
|
||||
border: 1px solid #0bbd90;
|
||||
}
|
||||
|
||||
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;
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.nav-list{
|
||||
li:nth-of-type(3){
|
||||
position: fixed;
|
||||
right: 25px;
|
||||
}
|
||||
}
|
||||
|
||||
#login {
|
||||
border: 1px solid black;
|
||||
border-radius: 6px;
|
||||
background-color: #ffc478;
|
||||
}
|
||||
|
||||
#login:hover {
|
||||
background-color: #0bbd90;
|
||||
}
|
||||
|
||||
/*Body et son contenu */
|
||||
body {
|
||||
background-color: blanchedalmond;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
background-color: #caecd6;
|
||||
border: 1px solid rgba(0,0,0,.125);
|
||||
border-radius: 6px;
|
||||
width: 128px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.tag-cont {
|
||||
/*display:none;*/
|
||||
}
|
||||
|
||||
.ingr-cont {
|
||||
/*display:none;*/
|
||||
}
|
||||
|
||||
.tag-selected-div {
|
||||
flex: 4;
|
||||
}
|
||||
|
||||
.tag-unselected-div {
|
||||
flex: 4;
|
||||
}
|
||||
|
||||
.sidebar-search {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.search-form-tag {
|
||||
width: 85%;
|
||||
}
|
||||
|
||||
.search-form-recette {
|
||||
width: 100%;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
border: 1px solid black;
|
||||
border-radius: 20px;
|
||||
box-shadow: 0px 0px 10px rgb(131, 131, 131);
|
||||
}
|
||||
|
||||
nav {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.tag {
|
||||
border: 1px solid black;
|
||||
border-radius: 10px;
|
||||
width: 95%;
|
||||
max-width: calc(128px*0.95);
|
||||
box-shadow: 1px 1px 1px black;
|
||||
}
|
||||
|
||||
.tag-selected {
|
||||
background-color: #ffa04d;
|
||||
}
|
||||
|
||||
.tag-selected:hover {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.tag-unselected {
|
||||
background-color: white;
|
||||
|
||||
}
|
||||
.tag-unselected:hover {
|
||||
background-color: #ffa04d;
|
||||
}
|
||||
|
||||
#hr {
|
||||
border: 1px solid #0bbd90;
|
||||
width: 93%;
|
||||
box-shadow: 1px 3px 5px #0bbd90;
|
||||
}
|
||||
|
||||
.main-body {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex: 1;
|
||||
background-clip: border-box;
|
||||
padding-right: 2%;
|
||||
padding-left: 2%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 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: scroll;
|
||||
}
|
||||
|
||||
/*Recettes :
|
||||
représente le contenue centrale de la page.
|
||||
*/
|
||||
.recettes {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-gap: 10px;
|
||||
/* grid-auto-rows: minmax(300px, auto);
|
||||
grid-auto-columns: auto;*/
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
@media screen and (max-width : 1200px) {
|
||||
.recettes {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width : 800px) {
|
||||
.recettes {
|
||||
grid-template-columns: repeat(1, 1fr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media screen and (max-width : 600px) {
|
||||
|
||||
.sidebar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
margin-left: 0px;
|
||||
text-align: center;
|
||||
padding : 0px;
|
||||
}
|
||||
|
||||
/* Classe recette icone :
|
||||
C'est la classe de chaques éléments de notre liste de recette
|
||||
*/
|
||||
.recette-icone{
|
||||
display: flex;
|
||||
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;
|
||||
max-width: 400px;
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.recette-icone:hover{
|
||||
border-color: #0bbd90;
|
||||
}
|
||||
|
||||
.recette-icone-content{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.recette-preview-image{
|
||||
max-width: calc( 5vh + 5vw );
|
||||
max-height: calc( 5vh + 5vw );
|
||||
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;
|
||||
}
|
||||
|
||||
.recette-div-info {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.recette-div-liste-info{
|
||||
padding: 30px;
|
||||
margin: 10px;
|
||||
width: 100%;
|
||||
flex:1;
|
||||
}
|
||||
|
||||
.recette-list-buttons {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
.recette-button {
|
||||
border: 1px solid black;
|
||||
border-radius: 10px;
|
||||
padding : 10px;
|
||||
box-shadow: 1px 1px 1px black;
|
||||
background-color: blanchedalmond;
|
||||
}
|
||||
|
||||
.recette-button:hover{
|
||||
background-color: rgb(243, 215, 174);
|
||||
}
|
||||
|
||||
.recette-liste-info-elem {
|
||||
text-align: left;
|
||||
padding: 4px;
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
color: #535353bd;
|
||||
border-right: 1px solid #535353bd;
|
||||
border-left: 1px solid #535353bd;
|
||||
}
|
||||
|
||||
.recette-liste-info {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.recette-liste-tag {
|
||||
display: flex;
|
||||
flex-wrap: wrap; /*trouvé à l'aide de ChatGPT car je n'arrivais pas à trouver*/
|
||||
}
|
||||
|
||||
|
||||
/*description*/
|
||||
.recette-desc {
|
||||
padding : 30px;
|
||||
}
|
||||
|
||||
/*Login form*/
|
||||
.formcont {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.formcont form {
|
||||
width: 50vmin;
|
||||
height: 40vmin;
|
||||
border: 2px solid rgb(0, 0, 0);
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5vmin;
|
||||
background:white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 5px 5px 30px #555;
|
||||
}
|
||||
|
||||
.formcont form .form-group {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 1.2vmin;
|
||||
padding-left:0px;
|
||||
}
|
||||
|
||||
.formcont form .form-group label {
|
||||
width: 95%;
|
||||
text-align: center;
|
||||
color:black;
|
||||
font-size:5vmin;
|
||||
}
|
||||
|
||||
.formcont form .form-group input {
|
||||
width: 95%;
|
||||
box-sizing: border-box;
|
||||
font-size:3vmin;
|
||||
padding:1vmin;
|
||||
|
||||
}
|
||||
|
||||
.formcont form button {
|
||||
width: 48%;
|
||||
height: 19%;
|
||||
padding:0.5vmin;
|
||||
box-sizing: border-box;
|
||||
margin: 0 auto;
|
||||
background: #ffa04d;
|
||||
color: black;
|
||||
font-size: 4vmin;
|
||||
border-radius: 7px;
|
||||
box-shadow: 2px 2px 0px #000000;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-color: #0bbd90;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
border-radius: 10px;
|
||||
box-shadow: 3px 4px 5px #8c8c8c;
|
||||
}
|
||||
|
||||
.recette-form-div-desc {
|
||||
height: 90%;
|
||||
}
|
||||
|
||||
.recette-form {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin: 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.recette-form-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#recette-form-div-desc {
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
#recette-form-description {
|
||||
height: 95%;
|
||||
}
|
||||
|
||||
/*Footer et son contenue*/
|
||||
footer{
|
||||
padding: 25px;
|
||||
background: rgb(11, 189, 144);
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 141 KiB After Width: | Height: | Size: 141 KiB |
66
public/assets/js/login.js
Normal file
66
public/assets/js/login.js
Normal file
@@ -0,0 +1,66 @@
|
||||
document.addEventListener( 'DOMContentLoaded', function(){
|
||||
const FORM = document.getElementById( 'login-form' );
|
||||
const FORM_ERROR = document.getElementById( 'login-errors' );
|
||||
if( !FORM )
|
||||
return;
|
||||
|
||||
/**
|
||||
* Permet d'afficher une erreur dans le formulaire.
|
||||
* @param message
|
||||
*/
|
||||
FORM.showError = function( message ){
|
||||
FORM_ERROR.style.display = 'block';
|
||||
FORM_ERROR.innerText = message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de retirer l'erreur du formulaire.
|
||||
*/
|
||||
FORM.removeError = function(){
|
||||
FORM_ERROR.style.display = 'none';
|
||||
FORM_ERROR.innerText = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gère l'envoi du formulaire.
|
||||
* @param e
|
||||
* @returns {boolean}
|
||||
*/
|
||||
FORM.onsubmit = function( e ){
|
||||
|
||||
e.preventDefault();
|
||||
FORM.removeError();
|
||||
|
||||
let userField = e.target.username;
|
||||
let passwordField = e.target.password;
|
||||
|
||||
if( !userField || !passwordField || userField.value === "" || passwordField.value === "" ){
|
||||
FORM.showError( "Le nom d'utilisateur ou le mot de passe ne doivent pas être vide.");
|
||||
return false;
|
||||
}
|
||||
|
||||
let formData = new FormData( FORM );
|
||||
let options = {
|
||||
method: "POST",
|
||||
contentType: "application/json",
|
||||
body: formData,
|
||||
}
|
||||
|
||||
fetch( FORM.action, options ).then( ( response ) => {
|
||||
if( response.ok ){
|
||||
response.json().then( ( responseJSON ) => {
|
||||
|
||||
if( responseJSON.success === true ){
|
||||
window.location.href = window.location.origin; // Redirection sur la page d'accueil si succès.
|
||||
} else {
|
||||
FORM.showError( responseJSON.message || "Mauvais nom d'utilisateur ou mauvais mot de passe." );
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
})
|
||||
13
public/index.php
Normal file
13
public/index.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
use App\Kernel;
|
||||
|
||||
if( !defined( 'APP_ROOT' ) )
|
||||
|
||||
/**
|
||||
* Définit la racine de l'application en chemin absolue.
|
||||
*/
|
||||
define( 'APP_ROOT', realpath( __DIR__ . '/../') . '/' );
|
||||
|
||||
require_once '../src/Kernel.php';
|
||||
Kernel::start();
|
||||
@@ -4,6 +4,9 @@ namespace App\Domain;
|
||||
|
||||
use App\Http\Route;
|
||||
|
||||
/**
|
||||
* Classe abstraite des controllers qui vont pouvoir permettre de gérer les routes et leur retour.
|
||||
*/
|
||||
abstract class Controller {
|
||||
|
||||
/**
|
||||
33
src/Domain/Ingredients/Ingredient.php
Normal file
33
src/Domain/Ingredients/Ingredient.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain\Ingredients;
|
||||
|
||||
use App\Domain\Model;
|
||||
|
||||
/**
|
||||
* Classe qui va gérer les ingrédients.
|
||||
*/
|
||||
class Ingredient extends Model {
|
||||
|
||||
/**
|
||||
* Le numéro de l'ingrédient.
|
||||
* @var int
|
||||
*/
|
||||
public int $num_ingredient;
|
||||
|
||||
/**
|
||||
* Le nom de l'ingrédient
|
||||
* @var string
|
||||
*/
|
||||
public string $nom_ingredient;
|
||||
|
||||
/**
|
||||
* Retourne le numéro de l'ingrédient.
|
||||
* @return int
|
||||
*/
|
||||
public function getID(): int
|
||||
{
|
||||
return $this->num_ingredient;
|
||||
}
|
||||
|
||||
}
|
||||
175
src/Domain/Ingredients/IngredientRepository.php
Normal file
175
src/Domain/Ingredients/IngredientRepository.php
Normal file
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain\Ingredients;
|
||||
|
||||
use App\Domain\LinkableInterface;
|
||||
use App\Domain\Recettes\Recette;
|
||||
use App\Domain\Repository;
|
||||
use App\Domain\Model;
|
||||
use App\Domain\Tags\Tag;
|
||||
use App\Kernel;
|
||||
|
||||
/**
|
||||
* Classe qui va permettre de gérer les requêtes BDD en lien avec les ingrédients.
|
||||
* Les ingrédients sont liables à d'autres entités comme les Recettes.
|
||||
*/
|
||||
class IngredientRepository extends Repository implements LinkableInterface {
|
||||
|
||||
/**
|
||||
* Permet d'avoir le nom de l'entité dont dépend ce repo.
|
||||
* @return string
|
||||
*/
|
||||
public static function getEntity(): string
|
||||
{
|
||||
return Ingredient::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* La structure de notre table dans la BDD.
|
||||
* Un champ link_recettes a été ajouté pour donner le nom de la table de lien entre nos recettes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getStructure(): array
|
||||
{
|
||||
return [
|
||||
'table' => 'Ingredient',
|
||||
'columns' => [
|
||||
'num_ingredient', 'nom_ingredient'
|
||||
],
|
||||
'link_recettes' => 'Listeingredient'
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'obtenir une liste de tous les ingrédients objet Ingreident.
|
||||
*
|
||||
* @return Ingredient[]|null
|
||||
*/
|
||||
public function getAll(): ?array {
|
||||
$sqlQuery = "SELECT * FROM {$this->tableName};";
|
||||
$results = $this->selectGetAll($sqlQuery);
|
||||
if( $results === null )
|
||||
return null;
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'obtenir un ingrédient spécifique par son ID.
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return Ingredient|null
|
||||
*/
|
||||
public function getByID( int $id ): ?Ingredient {
|
||||
$sqlQuery = "SELECT * FROM {$this->tableName} WHERE num_ingredient = {$id}";
|
||||
$results = $this->selectGetAll($sqlQuery);
|
||||
if( $results === null || count( $results ) > 1 )
|
||||
return null;
|
||||
return $results[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'obtenir, sous forme de liste, toutes les entrées qui lient des ingrédients.
|
||||
*
|
||||
* @param string $linkedTo La table qui permet de faire la liaison des ingrédients avec une autre entité.
|
||||
* @param string $linkingField Le champ qui permet de faire la liaison des ingrédients avec une autre entité.
|
||||
* @param Model $linkedEntity L'autre entité.
|
||||
*
|
||||
* @see LinkableInterface
|
||||
* @return array|null
|
||||
*/
|
||||
public function getIdLinkedTo( string $linkedTo, string $linkingField, Model $linkedEntity ): ?array {
|
||||
|
||||
$linkName = 'link_' . $linkedTo;
|
||||
if( !isset( $this->globalStructure[$linkName]))
|
||||
return null;
|
||||
|
||||
$sqlQuery = "SELECT * FROM {$this->globalStructure[$linkName]} WHERE {$linkingField} = {$linkedEntity->getId()};";
|
||||
$results = $this->selectGetAll($sqlQuery, true);
|
||||
if( $results === null )
|
||||
return null;
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'ajouter un lien entre un ingrédient et une autre entité comme Recette.
|
||||
*
|
||||
* @param string $linkedTo
|
||||
* @param string $linkingField
|
||||
* @param Model $linkedEntity
|
||||
* @param Model $ingredientEntity
|
||||
*
|
||||
* @see LinkableInterface
|
||||
* @return bool
|
||||
*/
|
||||
public function addLinkBetween( string $linkedTo, string $linkingField, Model $linkedEntity, Model $ingredientEntity ): bool {
|
||||
|
||||
$linkName = 'link_' . $linkedTo;
|
||||
if( !isset( $this->globalStructure[$linkName]))
|
||||
return false;
|
||||
|
||||
$query = "INSERT INTO {$this->globalStructure[$linkName]} ({$linkingField},num_ingredient) VALUES ({$linkedEntity->getId()}, {$ingredientEntity->getID()});";
|
||||
$statement = Kernel::$DB->pdo->prepare( $query );
|
||||
|
||||
return $statement->execute();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Retire un lien dans la BDD entre un ingrédient et une autre entité.
|
||||
*
|
||||
* @param string $linkedTo
|
||||
* @param string $linkingField
|
||||
* @param Model $linkedEntity
|
||||
* @param Model $ingredientEntity
|
||||
*
|
||||
* @see LinkableInterface
|
||||
* @return bool
|
||||
*/
|
||||
public function removeLinkBetween(string $linkedTo, string $linkingField, Model $linkedEntity, Model $ingredientEntity ): bool
|
||||
{
|
||||
$linkName = 'link_' . $linkedTo;
|
||||
if( !isset( $this->globalStructure[$linkName]))
|
||||
return false;
|
||||
|
||||
$query = "DELETE FROM {$this->globalStructure[$linkName]} WHERE {$linkingField} = {$linkedEntity->getId()} AND num_ingredient = {$ingredientEntity->getId()};";
|
||||
$statement = Kernel::$DB->pdo->prepare( $query );
|
||||
return $statement->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajouter un ingrédient dans la BDD.
|
||||
*
|
||||
* @param Model $ingredient
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function add( Model $ingredient ): bool {
|
||||
return $this->addEntity( $ingredient );
|
||||
}
|
||||
|
||||
/**
|
||||
* Met à jour un ingrédient dans la BDD.
|
||||
*
|
||||
* @param Model $ingredient
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function update( Model $ingredient ): bool {
|
||||
return $this->updateEntity( $ingredient, 'num_ingredient' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Supprime un ingrédient de la BDD.
|
||||
*
|
||||
* @param Model $ingredient
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete( Model $ingredient ): bool {
|
||||
return $this->deleteEntity( $ingredient, 'num_ingredient' );
|
||||
}
|
||||
|
||||
}
|
||||
38
src/Domain/Ingredients/UseIngredientsInterface.php
Normal file
38
src/Domain/Ingredients/UseIngredientsInterface.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain\Ingredients;
|
||||
|
||||
use App\Domain\Model;
|
||||
|
||||
/**
|
||||
* Interface utilisée par tous les repository qui sont en lien avec les ingrédients.
|
||||
*/
|
||||
interface UseIngredientsInterface {
|
||||
|
||||
/**
|
||||
* Permet de récupérer tous les ingrédients liés à ce Modèle.
|
||||
* @return array|null
|
||||
*/
|
||||
public function getAllLinkedIngredients( Model $entity ): ?array;
|
||||
|
||||
/**
|
||||
* Permet d'ajouter un ingrédient en lien avec notre autre entité.
|
||||
*
|
||||
* @param Ingredient $ingredient
|
||||
* @param Model $entity
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function addAnIngredient( Ingredient $ingredient, Model $entity ): bool;
|
||||
|
||||
/**
|
||||
* Permet de retirer un lien entre un ingrédient et une autre entité.
|
||||
*
|
||||
* @param Ingredient $ingredient
|
||||
* @param Model $entity
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function removeAnIngredient( Ingredient $ingredient, Model $entity ): bool;
|
||||
|
||||
}
|
||||
51
src/Domain/LinkableInterface.php
Normal file
51
src/Domain/LinkableInterface.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain;
|
||||
|
||||
/**
|
||||
* Interface pour dire qu'un objet peut avoir un lien avec un autre objet par une table.
|
||||
* Il s'agit d'une interface qui s'utilise sur des repositories de meta-données (Tag, Ingrédients)
|
||||
*
|
||||
* Les champs de toutes les méthodes se présentent de la même façon.
|
||||
* $linkedTo : Champ qui va désigner le nom de la table de liens que vous avez dans getStructure().
|
||||
* $linkingField : Champ dans la BDD qui va permettre de lier l'élément courant et l'étranger.
|
||||
* $linkedEntity : Une instance de l'entité étrangère que l'on veut lier.
|
||||
*/
|
||||
interface LinkableInterface {
|
||||
|
||||
/**
|
||||
* Permet de récupérer tous les liens entre notre entité implémentée et notre entité étrangère.
|
||||
*
|
||||
* @param string $linkedTo
|
||||
* @param string $linkingField
|
||||
* @param Model $linkedEntity
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function getIdLinkedTo( string $linkedTo, string $linkingField, Model $linkedEntity ): ?array;
|
||||
|
||||
/**
|
||||
* Permet d'ajouter un lien entre notre entité implémentée et notre entité étrangère.
|
||||
*
|
||||
* @param string $linkedTo
|
||||
* @param string $linkingField
|
||||
* @param Model $linkedEntity
|
||||
* @param Model $entity
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function addLinkBetween( string $linkedTo, string $linkingField, Model $linkedEntity, Model $entity ): bool;
|
||||
|
||||
/**
|
||||
* Permet de retirer un lien entre notre entité implémentée et notre entité étrangère.
|
||||
*
|
||||
* @param string $linkedTo
|
||||
* @param string $linkingField
|
||||
* @param Model $linkedEntity
|
||||
* @param Model $entity
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function removeLinkBetween( string $linkedTo, string $linkingField, Model $linkedEntity, Model $entity ): bool;
|
||||
|
||||
}
|
||||
16
src/Domain/Model.php
Normal file
16
src/Domain/Model.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain;
|
||||
|
||||
/**
|
||||
* Classe abstraite pour gérer l'implémentation des entités de données.
|
||||
*/
|
||||
abstract class Model {
|
||||
|
||||
/**
|
||||
* Getter de l'ID primaire du model spécifique.
|
||||
* @return int
|
||||
*/
|
||||
abstract public function getID(): int;
|
||||
|
||||
}
|
||||
@@ -11,11 +11,14 @@ use App\Infrastructure\View;
|
||||
*/
|
||||
class PagesController extends Controller {
|
||||
|
||||
/**
|
||||
* Définit les routes globales d'acceuil.
|
||||
* @return array|\App\Http\Route[]
|
||||
*/
|
||||
public static function defineRoutes(): array
|
||||
{
|
||||
return [
|
||||
self::Route( routeUrl: '/', routeName: 'home', routeAction: 'index', pageHeadTitle: "Home Page" ),
|
||||
self::Route( routeUrl: '/test/{int}/', routeName: 'test', routeAction: 'test' ),
|
||||
];
|
||||
|
||||
}
|
||||
@@ -28,8 +31,4 @@ class PagesController extends Controller {
|
||||
return new View( 'home', [ 'ok' => 'bla' ] );
|
||||
}
|
||||
|
||||
public function test( string $id ): void {
|
||||
echo "Coucou" . $id;
|
||||
}
|
||||
|
||||
}
|
||||
52
src/Domain/Recettes/Recette.php
Normal file
52
src/Domain/Recettes/Recette.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain\Recettes;
|
||||
|
||||
use App\Domain\Ingredients\Ingredient;
|
||||
use App\Domain\Ingredients\IngredientRepository;
|
||||
use App\Domain\Ingredients\UseIngredientsInterface;
|
||||
use App\Domain\Model;
|
||||
use App\Helpers\Markdown;
|
||||
|
||||
/**
|
||||
* Classe qui va permettre de gérer tous les objets recette.
|
||||
*/
|
||||
class Recette extends Model {
|
||||
|
||||
public int $num_recette;
|
||||
public string $titre_recette;
|
||||
public string $slug;
|
||||
public string $description_recette;
|
||||
public string $photo;
|
||||
public string $publication_date;
|
||||
public int $temps_de_preparation;
|
||||
|
||||
public function getID(): int
|
||||
{
|
||||
return $this->num_recette;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convertit la description de Markdown à HTML.
|
||||
* @return string
|
||||
*/
|
||||
public function getHTMLDescription(): string {
|
||||
return Markdown::convertToHTML( $this->description_recette );
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère une liste de tous les ingrédients liés à la recette.
|
||||
* @return Ingredient[]|null
|
||||
*/
|
||||
public function getAllLinkedIngredients(): ?array
|
||||
{
|
||||
return new RecetteRepository()->getAllLinkedIngredients( $this );
|
||||
}
|
||||
|
||||
public function getNumberOfIngredients(): int {
|
||||
|
||||
$response = $this->getAllLinkedIngredients();
|
||||
return $response !== null ? count( $response ) : 0;
|
||||
}
|
||||
|
||||
}
|
||||
162
src/Domain/Recettes/RecetteRepository.php
Normal file
162
src/Domain/Recettes/RecetteRepository.php
Normal file
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain\Recettes;
|
||||
|
||||
use App\Domain\Ingredients\Ingredient;
|
||||
use App\Domain\Ingredients\IngredientRepository;
|
||||
use App\Domain\Ingredients\UseIngredientsInterface;
|
||||
use App\Domain\Model;
|
||||
use App\Domain\Repository;
|
||||
use App\Domain\Tags\Tag;
|
||||
use App\Domain\Tags\TagRepository;
|
||||
use App\Domain\Tags\UseTagsInterface;
|
||||
|
||||
/**
|
||||
* Classe qui permet de faire le lien entre la BDD et le site pour les recettes.
|
||||
* Les recettes sont en lien avec les ingrédients.
|
||||
*/
|
||||
class RecetteRepository extends Repository implements UseIngredientsInterface, UseTagsInterface {
|
||||
|
||||
public static function getEntity(): string
|
||||
{
|
||||
return Recette::class;
|
||||
}
|
||||
|
||||
public static function getStructure(): array
|
||||
{
|
||||
return [
|
||||
'table' => 'Recette',
|
||||
'columns' => [
|
||||
'num_recette', 'titre_recette', 'slug', 'description_recette', 'photo', 'publication_date', 'temps_de_preparation'
|
||||
]
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'obtenir une liste de toutes les recettes objet Recette.
|
||||
*
|
||||
* @return Recette[]|null
|
||||
*/
|
||||
public function getAll(): ?array {
|
||||
$sqlQuery = "SELECT * FROM {$this->tableName};";
|
||||
$results = $this->selectGetAll($sqlQuery);
|
||||
if( $results === null )
|
||||
return null;
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'obtenir toutes les recettes paginées.
|
||||
* Mise par défaut dans l'ordre croissant du titre et avec une pagination de 15 éléments.
|
||||
*
|
||||
* @param int $page
|
||||
* @param int $pagination
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function getAllRecettesBrowse( int $page = 1, int $pagination = 15 ){
|
||||
|
||||
if( $page <= 0 )
|
||||
$page = 1;
|
||||
|
||||
$offset = ( $page - 1 ) * $pagination;
|
||||
|
||||
$sqlQuery = "SELECT * FROM {$this->tableName} ORDER BY titre_recette ASC LIMIT {$pagination} OFFSET {$offset};";
|
||||
$results = $this->selectGetAll($sqlQuery);
|
||||
if( $results === null )
|
||||
return null;
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'avoir une recette par un ID.
|
||||
*
|
||||
* @param int $id
|
||||
* @return Recette|null
|
||||
*/
|
||||
public function getByID( int $id ): ?Recette {
|
||||
$sqlQuery = "SELECT * FROM {$this->tableName} WHERE num_recette = {$id}";
|
||||
$results = $this->selectGetAll($sqlQuery);
|
||||
if( $results === null || count( $results ) > 1 )
|
||||
return null;
|
||||
return $results[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'avoir une recette par un slug.
|
||||
*
|
||||
* @param string $slug
|
||||
* @return Recette|null
|
||||
*/
|
||||
public function getBySlug( string $slug ): ?Recette {
|
||||
$sqlQuery = "SELECT * FROM {$this->tableName} WHERE slug = {$slug}";
|
||||
$results = $this->selectGetAll($sqlQuery);
|
||||
if( $results === null || count( $results ) > 1 )
|
||||
return null;
|
||||
return $results[0];
|
||||
}
|
||||
|
||||
public function add( Model $recette ): bool {
|
||||
return $this->addEntity( $recette );
|
||||
}
|
||||
|
||||
public function update( Model $recette ): bool {
|
||||
return $this->updateEntity( $recette, 'num_recette' );
|
||||
}
|
||||
|
||||
public function delete( Model $recette ): bool {
|
||||
return $this->deleteEntity( $recette, 'num_recette' );
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function getAllLinkedIngredients(Model $entity): ?array
|
||||
{
|
||||
$ingredientRepo = new IngredientRepository();
|
||||
$response = $ingredientRepo->getIdLinkedTo( 'recettes', 'num_recette', $entity );
|
||||
if( $response === null )
|
||||
return null;
|
||||
|
||||
return array_map( function($arr) use($ingredientRepo) {
|
||||
return $ingredientRepo->getByID( $arr['num_ingredient'] );
|
||||
}, $response );
|
||||
}
|
||||
|
||||
public function addAnIngredient(Ingredient $ingredient, Model $entity): bool
|
||||
{
|
||||
$ingredientRepo = new IngredientRepository();
|
||||
return $ingredientRepo->addLinkBetween( 'recettes', 'num_recette', $entity, $ingredient );
|
||||
}
|
||||
|
||||
public function removeAnIngredient(Ingredient $ingredient, Model $entity): bool
|
||||
{
|
||||
$ingredientRepo = new IngredientRepository();
|
||||
return $ingredientRepo->removeLinkBetween( 'recettes', 'num_recette', $entity, $ingredient );
|
||||
}
|
||||
|
||||
public function getAllLinkedTags(Model $entity): ?array
|
||||
{
|
||||
$tagRepo = new TagRepository();
|
||||
$response = $tagRepo->getIdLinkedTo( 'recettes', 'num_recette', $entity );
|
||||
if( $response === null )
|
||||
return null;
|
||||
|
||||
return array_map( function($arr) use($tagRepo) {
|
||||
return $tagRepo->getByID( $arr['num_tag'] );
|
||||
}, $response );
|
||||
}
|
||||
|
||||
public function addATag(Tag $tag, Model $entity): bool
|
||||
{
|
||||
$tagRepo = new TagRepository();
|
||||
return $tagRepo->addLinkBetween( 'recettes', 'num_recette', $entity, $tag );
|
||||
}
|
||||
|
||||
public function removeATag(Tag $tag, Model $entity): bool
|
||||
{
|
||||
$tagRepo = new TagRepository();
|
||||
return $tagRepo->removeLinkBetween( 'recettes', 'num_recette', $entity, $tag );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,7 +3,10 @@
|
||||
namespace App\Domain\Recettes;
|
||||
|
||||
use App\Domain\Controller;
|
||||
use App\Domain\Ingredients\IngredientRepository;
|
||||
use App\Domain\Tags\TagRepository;
|
||||
use App\Http\JSONResponse;
|
||||
use App\Http\Request;
|
||||
use App\Infrastructure\View;
|
||||
|
||||
class RecettesController extends Controller {
|
||||
@@ -18,7 +21,16 @@ class RecettesController extends Controller {
|
||||
}
|
||||
|
||||
public function index(): View {
|
||||
return new View( 'recettes/index', [] );
|
||||
|
||||
$page = Request::get( 'page' );
|
||||
if( $page == null )
|
||||
$page = 1;
|
||||
|
||||
return new View( 'recettes/index', [
|
||||
'tagsList' => new TagRepository()->getAll(),
|
||||
'ingredientsList' => new IngredientRepository()->getAll(),
|
||||
'recettesList' => new RecetteRepository()->getAllRecettesBrowse( $page ),
|
||||
] );
|
||||
}
|
||||
|
||||
}
|
||||
170
src/Domain/Repository.php
Normal file
170
src/Domain/Repository.php
Normal file
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain;
|
||||
|
||||
use App\Domain\Recettes\Recette;
|
||||
use App\Kernel;
|
||||
use PDO;
|
||||
|
||||
/**
|
||||
* Classe abstraite avec des méthodes pour pouvoir gérer les liens entre le site et la base de données.
|
||||
*/
|
||||
abstract class Repository {
|
||||
|
||||
/**
|
||||
* Instancie des éléments de cette classe par rapport au repository.
|
||||
* @return class-string
|
||||
*/
|
||||
abstract public static function getEntity(): string;
|
||||
|
||||
/**
|
||||
* Doit retourner une liste du type :
|
||||
* ['table' => '', 'columns' => [ ...Liste des colonnes dans la BDD ] ].
|
||||
* @return array
|
||||
*/
|
||||
abstract public static function getStructure(): array;
|
||||
|
||||
/**
|
||||
* Contient le nom de la table principale du repo.
|
||||
* @var string|mixed
|
||||
*/
|
||||
final public string $tableName;
|
||||
|
||||
/**
|
||||
* Contient le nom des colonnes de la table du repo.
|
||||
* @var array|mixed
|
||||
*/
|
||||
final public array $tableColumns;
|
||||
|
||||
/**
|
||||
* Contient les mêmes données que getStructure().
|
||||
* @var array
|
||||
*/
|
||||
public private(set) array $globalStructure;
|
||||
|
||||
/**
|
||||
* Constructeur.
|
||||
* Reprend les informations de getStructure et les met dans des attributs.
|
||||
*/
|
||||
public function __construct(){
|
||||
$structure = static::getStructure();
|
||||
|
||||
$this->tableName = $structure['table'];
|
||||
$this->tableColumns = $structure['columns'];
|
||||
$this->globalStructure = $structure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'avoir tous les éléments correspondant à la requête passée en paramètre.
|
||||
*
|
||||
* @param string $sqlQuery
|
||||
* @param bool $asArray Permet de savoir si on veut que le retour soit une array ou bien un tableau de Model.
|
||||
* @return array|null
|
||||
*/
|
||||
public function selectGetAll( string $sqlQuery, bool $asArray = false ): ?array {
|
||||
$statement = Kernel::$DB->pdo->prepare( $sqlQuery );
|
||||
if( !$statement->execute() )
|
||||
return null;
|
||||
|
||||
if( $asArray )
|
||||
$results = $statement->fetchAll( PDO::FETCH_ASSOC );
|
||||
else
|
||||
$results = $statement->fetchAll( PDO::FETCH_CLASS, static::getEntity() );
|
||||
if( empty( $results ) )
|
||||
return null;
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'ajouter une entité à la base de données.
|
||||
*
|
||||
* @param Model $entity
|
||||
* @return bool
|
||||
*/
|
||||
public function addEntity( Model $entity ): bool {
|
||||
|
||||
$query = "INSERT INTO {$this->tableName} (";
|
||||
$values = "(";
|
||||
foreach( $this->tableColumns as $column ) {
|
||||
$query .= "`{$column}`,";
|
||||
$values .= ":{$column},";
|
||||
}
|
||||
$query = substr( $query, 0, -1 ) . ")";
|
||||
$values = substr( $values, 0, -1 ) . ")";
|
||||
$query .= " VALUES " . $values . ";";
|
||||
|
||||
$statement = Kernel::$DB->pdo->prepare( $query );
|
||||
foreach( $this->tableColumns as $column ) {
|
||||
$statement->bindValue(":{$column}", $entity->{$column} );
|
||||
}
|
||||
|
||||
return $statement->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de mettre à jour les informations de l'entité dans la base de données.
|
||||
*
|
||||
* @param Model $entity
|
||||
* @param string $identifier
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function updateEntity( Model $entity, string $identifier ): bool {
|
||||
$query = "UPDATE {$this->tableName} SET ";
|
||||
foreach( $this->tableColumns as $column ) {
|
||||
$query .= "`{$column}` = :{$column},";
|
||||
}
|
||||
$query = substr( $query, 0, -1 ) . " WHERE {$identifier} = :{$identifier};";
|
||||
|
||||
$statement = Kernel::$DB->pdo->prepare( $query );
|
||||
foreach( $this->tableColumns as $column ) {
|
||||
$statement->bindValue(":{$column}", $entity->{$column} );
|
||||
}
|
||||
$statement->bindValue( ":{$identifier}", $entity->{$identifier} );
|
||||
return $statement->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de supprimer une entrée d'entité dans la base de données.
|
||||
*
|
||||
* @param Model $entity
|
||||
* @param string $identifier
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteEntity( Model $entity, string $identifier ): bool {
|
||||
$query = "DELETE FROM {$this->tableName} WHERE {$identifier} = :{$identifier};";
|
||||
$statement = Kernel::$DB->pdo->prepare( $query );
|
||||
$statement->bindValue( ":{$identifier}", $entity->{$identifier} );
|
||||
return $statement->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fonction raccourcie pour préparer les champs nécessaires pour addEntity.
|
||||
*
|
||||
* @param Model $entity
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function add( Model $entity ): bool;
|
||||
|
||||
/**
|
||||
* Fonction raccourcie pour préparer les champs nécessaires pour updateEntity
|
||||
*
|
||||
* @param Model $entity
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function update( Model $entity ): bool;
|
||||
|
||||
/**
|
||||
* Fonction raccourcie pour préparer les champs nécessaires pour deleteEntity
|
||||
*
|
||||
* @param Model $entity
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function delete( Model $entity ): bool;
|
||||
|
||||
|
||||
}
|
||||
33
src/Domain/Tags/Tag.php
Normal file
33
src/Domain/Tags/Tag.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain\Tags;
|
||||
|
||||
use App\Domain\Model;
|
||||
|
||||
/**
|
||||
* Classe qui va gérer les tags.
|
||||
*/
|
||||
class Tag extends Model {
|
||||
|
||||
/**
|
||||
* Le numéro du tag.
|
||||
* @var int
|
||||
*/
|
||||
public int $num_tag;
|
||||
|
||||
/**
|
||||
* Le nom du tag
|
||||
* @var string
|
||||
*/
|
||||
public string $nom_tag;
|
||||
|
||||
/**
|
||||
* Retourne le numéro du tag.
|
||||
* @return int
|
||||
*/
|
||||
public function getID(): int
|
||||
{
|
||||
return $this->num_tag;
|
||||
}
|
||||
|
||||
}
|
||||
174
src/Domain/Tags/TagRepository.php
Normal file
174
src/Domain/Tags/TagRepository.php
Normal file
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain\Tags;
|
||||
|
||||
use App\Domain\LinkableInterface;
|
||||
use App\Domain\Recettes\Recette;
|
||||
use App\Domain\Repository;
|
||||
use App\Domain\Model;
|
||||
use App\Kernel;
|
||||
|
||||
/**
|
||||
* Classe qui va permettre de gérer les requêtes BDD en lien avec les tags.
|
||||
* Les tags sont liables à d'autres entités comme les Recettes.
|
||||
*/
|
||||
class TagRepository extends Repository implements LinkableInterface {
|
||||
|
||||
/**
|
||||
* Permet d'avoir le nom de l'entité dont dépend ce repo.
|
||||
* @return string
|
||||
*/
|
||||
public static function getEntity(): string
|
||||
{
|
||||
return Tag::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* La structure de notre table dans la BDD.
|
||||
* Un champ link_recettes a été ajouté pour donner le nom de la table de lien entre nos recettes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getStructure(): array
|
||||
{
|
||||
return [
|
||||
'table' => 'Tag',
|
||||
'columns' => [
|
||||
'num_tag', 'nom_tag'
|
||||
],
|
||||
'link_recettes' => 'Referencetag'
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'obtenir une liste de tous les tags objet Tag.
|
||||
*
|
||||
* @return Tag[]|null
|
||||
*/
|
||||
public function getAll(): ?array {
|
||||
$sqlQuery = "SELECT * FROM {$this->tableName};";
|
||||
$results = $this->selectGetAll($sqlQuery);
|
||||
if( $results === null )
|
||||
return null;
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'obtenir un tag spécifique par son ID.
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return Tag|null
|
||||
*/
|
||||
public function getByID( int $id ): ?Tag {
|
||||
$sqlQuery = "SELECT * FROM {$this->tableName} WHERE num_tag = {$id}";
|
||||
$results = $this->selectGetAll($sqlQuery);
|
||||
if( $results === null || count( $results ) > 1 )
|
||||
return null;
|
||||
return $results[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'obtenir, sous forme de liste, toutes les entrées qui lient des tags.
|
||||
*
|
||||
* @param string $linkedTo La table qui permet de faire la liaison des tags avec une autre entité.
|
||||
* @param string $linkingField Le champ qui permet de faire la liaison des tags avec une autre entité.
|
||||
* @param Model $linkedEntity L'autre entité.
|
||||
*
|
||||
* @see LinkableInterface
|
||||
* @return array|null
|
||||
*/
|
||||
public function getIdLinkedTo( string $linkedTo, string $linkingField, Model $linkedEntity ): ?array {
|
||||
|
||||
$linkName = 'link_' . $linkedTo;
|
||||
if( !isset( $this->globalStructure[$linkName]))
|
||||
return null;
|
||||
|
||||
$sqlQuery = "SELECT * FROM {$this->globalStructure[$linkName]} WHERE {$linkingField} = {$linkedEntity->getId()};";
|
||||
$results = $this->selectGetAll($sqlQuery, true);
|
||||
if( $results === null )
|
||||
return null;
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'ajouter un lien entre un tag et une autre entité comme Recette.
|
||||
*
|
||||
* @param string $linkedTo
|
||||
* @param string $linkingField
|
||||
* @param Model $linkedEntity
|
||||
* @param Model $tagEntity
|
||||
*
|
||||
* @see LinkableInterface
|
||||
* @return bool
|
||||
*/
|
||||
public function addLinkBetween( string $linkedTo, string $linkingField, Model $linkedEntity, Model $tagEntity ): bool {
|
||||
|
||||
$linkName = 'link_' . $linkedTo;
|
||||
if( !isset( $this->globalStructure[$linkName]))
|
||||
return false;
|
||||
|
||||
$query = "INSERT INTO {$this->globalStructure[$linkName]} ({$linkingField},num_tag) VALUES ({$linkedEntity->getId()}, {$tagEntity->getID()});";
|
||||
$statement = Kernel::$DB->pdo->prepare( $query );
|
||||
|
||||
return $statement->execute();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Retire un lien dans la BDD entre un tag et une autre entité.
|
||||
*
|
||||
* @param string $linkedTo
|
||||
* @param string $linkingField
|
||||
* @param Model $linkedEntity
|
||||
* @param Model $tagEntity
|
||||
*
|
||||
* @see LinkableInterface
|
||||
* @return bool
|
||||
*/
|
||||
public function removeLinkBetween(string $linkedTo, string $linkingField, Model $linkedEntity, Model $tagEntity ): bool
|
||||
{
|
||||
$linkName = 'link_' . $linkedTo;
|
||||
if( !isset( $this->globalStructure[$linkName]))
|
||||
return false;
|
||||
|
||||
$query = "DELETE FROM {$this->globalStructure[$linkName]} WHERE {$linkingField} = {$linkedEntity->getId()} AND num_tag = {$tagEntity->getId()};";
|
||||
$statement = Kernel::$DB->pdo->prepare( $query );
|
||||
return $statement->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajouter un tag dans la BDD.
|
||||
*
|
||||
* @param Model $ingredient
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function add( Model $tag ): bool {
|
||||
return $this->addEntity( $tag );
|
||||
}
|
||||
|
||||
/**
|
||||
* Met à jour un tag dans la BDD.
|
||||
*
|
||||
* @param Model $tag
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function update( Model $tag ): bool {
|
||||
return $this->updateEntity( $tag, 'num_tag' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Supprime un tag de la BDD.
|
||||
*
|
||||
* @param Model $tag
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete( Model $tag ): bool {
|
||||
return $this->deleteEntity( $tag, 'num_tag' );
|
||||
}
|
||||
|
||||
}
|
||||
38
src/Domain/Tags/UseTagsInterface.php
Normal file
38
src/Domain/Tags/UseTagsInterface.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain\Tags;
|
||||
|
||||
use App\Domain\Model;
|
||||
|
||||
/**
|
||||
* Interface utilisée par tous les repository qui sont en lien avec les tags.
|
||||
*/
|
||||
interface UseTagsInterface {
|
||||
|
||||
/**
|
||||
* Permet de récupérer tous les tags liés à ce Modèle.
|
||||
* @return array|null
|
||||
*/
|
||||
public function getAllLinkedTags( Model $entity ): ?array;
|
||||
|
||||
/**
|
||||
* Permet d'ajouter un tag en lien avec notre autre entité.
|
||||
*
|
||||
* @param Tag $tag
|
||||
* @param Model $entity
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function addATag( Tag $tag, Model $entity ): bool;
|
||||
|
||||
/**
|
||||
* Permet de retirer un lien entre un tag et une autre entité.
|
||||
*
|
||||
* @param Tag $tag
|
||||
* @param Model $entity
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function removeATag( Tag $tag, Model $entity ): bool;
|
||||
|
||||
}
|
||||
@@ -6,6 +6,7 @@ use App\Domain\Controller;
|
||||
use App\Helpers\Authentification;
|
||||
use App\Http\JSONResponse;
|
||||
use App\Http\Request;
|
||||
use App\Infrastructure\View;
|
||||
|
||||
class AuthentificationController extends Controller {
|
||||
|
||||
@@ -15,19 +16,29 @@ class AuthentificationController extends Controller {
|
||||
|
||||
// Public routes.
|
||||
self::Route( routeUrl: '/login', routeName: 'login', routeAction: 'loginForm', pageHeadTitle: 'Connexion' ),
|
||||
self::Route( routeUrl: '/logout', routeName: 'logout', routeAction: 'logoutPage', pageHeadTitle: 'Déconnexion' ),
|
||||
|
||||
// API Routes.
|
||||
self::Route( routeUrl: '/api/auth', routeName: 'api->auth', routeAction: 'auth', routeMethods: ['POST'] ),
|
||||
self::Route( routeUrl: '/api/auth/logout', routeName: 'api->auth->logout', routeAction: 'logout', routeMethods: ['POST'] ),
|
||||
// self::Route( routeUrl: '/api/auth/logout', routeName: 'api->auth->logout', routeAction: 'logout', routeMethods: ['POST'] ),
|
||||
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
public function login(): View {
|
||||
public function loginForm(): View {
|
||||
return new View( 'login' );
|
||||
}
|
||||
|
||||
public function logoutPage(){
|
||||
if( !Authentification::isLoggedIn() ) {
|
||||
Request::redirectTo( 'home' );
|
||||
}
|
||||
|
||||
Authentification::destroySession();
|
||||
Request::redirectTo( 'home' );
|
||||
}
|
||||
|
||||
public function auth(): JSONResponse {
|
||||
|
||||
Request::setCORS();
|
||||
@@ -39,14 +50,14 @@ class AuthentificationController extends Controller {
|
||||
|
||||
$userId = 1;
|
||||
Authentification::loginUser( $userId );
|
||||
JSONResponse::sendSuccess( [ 'user_id' => $userId ] );
|
||||
return JSONResponse::sendSuccess( [ 'user_id' => $userId ] );
|
||||
|
||||
}
|
||||
|
||||
public function logout(): JSONResponse {
|
||||
|
||||
if( !Authentification::isLoggedIn() ) {
|
||||
return JSONResponse::sendError( [ 'message' => 'Alrady disconnected' ] );
|
||||
return JSONResponse::sendError( [ 'message' => 'Already disconnected' ] );
|
||||
}
|
||||
|
||||
Authentification::destroySession();
|
||||
23
src/Domain/Utilisateurs/Utilisateurs.php
Normal file
23
src/Domain/Utilisateurs/Utilisateurs.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain\Utilisateurs;
|
||||
|
||||
use App\Domain\Model;
|
||||
//use App\Helpers\Markdown;
|
||||
|
||||
/**
|
||||
* Classe qui va permettre de gérer tous les objets recette.
|
||||
*/
|
||||
class Utilisateurs extends Model {
|
||||
|
||||
public int $num_user;
|
||||
public string $username;
|
||||
public string $userpassword;
|
||||
|
||||
|
||||
public function getID(): int
|
||||
{
|
||||
return $this->num_user;
|
||||
}
|
||||
|
||||
}
|
||||
75
src/Domain/Utilisateurs/UtilisateursRepository.php
Normal file
75
src/Domain/Utilisateurs/UtilisateursRepository.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain\Utilisateurs;
|
||||
|
||||
use App\Domain\Model;
|
||||
use App\Domain\Repository;
|
||||
|
||||
|
||||
/**
|
||||
* Classe qui permet de faire le lien entre la BDD et le site pour les recettes.
|
||||
* Les recettes sont en lien avec les ingrédients.
|
||||
*/
|
||||
class UtilisateursRepository extends Repository {
|
||||
|
||||
public static function getEntity(): string
|
||||
{
|
||||
return Utilisateurs::class;
|
||||
}
|
||||
|
||||
public static function getStructure(): array
|
||||
{
|
||||
return [
|
||||
'table' => 'User',
|
||||
'columns' => [
|
||||
'num_user', 'username', 'userpassword'
|
||||
]
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'obtenir une liste de toutes les recettes objet Recette.
|
||||
*
|
||||
* @return Recette[]|null
|
||||
*/
|
||||
public function getAll(): ?array {
|
||||
$sqlQuery = "SELECT * FROM {$this->tableName};";
|
||||
$results = $this->selectGetAll($sqlQuery);
|
||||
if( $results === null )
|
||||
return null;
|
||||
return $results;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Permet d'avoir une recette par un ID.
|
||||
*
|
||||
* @param int $id
|
||||
* @return Recette|null
|
||||
*/
|
||||
public function getByID( int $id ): ?Utilisateurs {
|
||||
$sqlQuery = "SELECT * FROM {$this->tableName} WHERE num_user = {$id}";
|
||||
$results = $this->selectGetAll($sqlQuery);
|
||||
if( $results === null || count( $results ) > 1 )
|
||||
return null;
|
||||
return $results[0];
|
||||
}
|
||||
|
||||
|
||||
public function add( Model $utilisateurs ): bool {
|
||||
return $this->addEntity( $utilisateurs );
|
||||
}
|
||||
|
||||
public function update( Model $utilisateurs ): bool {
|
||||
return $this->updateEntity( $utilisateurs, 'num_user' );
|
||||
}
|
||||
|
||||
public function delete( Model $utilisateurs ): bool {
|
||||
return $this->deleteEntity( $utilisateurs, 'num_user' );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
29
src/Helpers/Markdown.php
Normal file
29
src/Helpers/Markdown.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Helpers;
|
||||
|
||||
class Markdown {
|
||||
|
||||
public static function getMarkdownEntities(): array {
|
||||
return [
|
||||
|
||||
// Gras & Italique
|
||||
'/\*\*(.*?)\*\*/' => '<b>$1</b>',
|
||||
'/\*(.*?)\*/' => '<i>$1</i>',
|
||||
|
||||
// Titres
|
||||
'/^## (.*?)$/m' => '<h3>$1</h3>',
|
||||
'/^# (.*?)$/m' => '<h2>$1</h2>',
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
public static function convertToHTML( string $markdown ): string {
|
||||
$safeMD = htmlspecialchars( $markdown, ENT_QUOTES );
|
||||
foreach( Markdown::getMarkdownEntities() as $key => $value ) {
|
||||
$safeMD = preg_replace( $key, $value, $safeMD );
|
||||
}
|
||||
|
||||
return nl2br( $safeMD );
|
||||
}
|
||||
}
|
||||
@@ -50,4 +50,20 @@ class Request {
|
||||
return self::sanitize( $_POST[$name] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de rediriger un utilisateur.
|
||||
* /!\ Arrête tout traitement sur la page.
|
||||
*
|
||||
* @param string $routeName
|
||||
* @param ...$args
|
||||
*
|
||||
* @return never
|
||||
*/
|
||||
public static function redirectTo( string $routeName, ...$args ): never {
|
||||
|
||||
$routeUrl = Router::getRouteURL( $routeName, ...$args );
|
||||
header("Location: {$routeUrl}");
|
||||
die();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,19 +15,19 @@ final class Router {
|
||||
* @var string
|
||||
*/
|
||||
public private(set) static string $clientRouteString;
|
||||
|
||||
// private(set)
|
||||
/**
|
||||
* Informations de la route du client.
|
||||
* @var Route
|
||||
*/
|
||||
public private(set) static Route $clientRoute;
|
||||
|
||||
public static Route $clientRoute;
|
||||
// private(set)
|
||||
/**
|
||||
* Informations sur les arguments passés à la route.
|
||||
* @var array
|
||||
*/
|
||||
public private(set) static array $clientRouteArguments;
|
||||
|
||||
public static array $clientRouteArguments;
|
||||
// private(set)
|
||||
/**
|
||||
* Liste des controllers sorti du cache ou récupéré via fetchControllers.
|
||||
* @var array
|
||||
@@ -48,7 +48,7 @@ final class Router {
|
||||
*/
|
||||
public static function routeTo(): void {
|
||||
|
||||
self::$clientRouteString = $_SERVER['REQUEST_URI'];
|
||||
self::$clientRouteString = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
|
||||
|
||||
self::$controllers = self::fetchControllers();
|
||||
self::$routes = self::fetchRoutes();
|
||||
@@ -166,7 +166,10 @@ final class Router {
|
||||
$controller = self::$clientRoute->routeController;
|
||||
$method = self::$clientRoute->routeAction;
|
||||
|
||||
new $controller()->$method( ...self::$clientRouteArguments);
|
||||
(new $controller())->$method( ...self::$clientRouteArguments);
|
||||
//correction controler()->method to controler().method
|
||||
// new $controller()->$method( ...self::$clientRouteArguments);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,7 +188,7 @@ final class Router {
|
||||
return $args[$i++] ?? "";
|
||||
}, $route->routeUrl);
|
||||
|
||||
return rtrim( Kernel::$configs['general']['website_url'] . $routeUrl, '/' );
|
||||
return rtrim( rtrim( Kernel::$configs['general']['website_url'], '/' ) . $routeUrl, '/' );
|
||||
}
|
||||
}
|
||||
|
||||
45
src/Infrastructure/Database.php
Normal file
45
src/Infrastructure/Database.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Infrastructure;
|
||||
|
||||
/**
|
||||
* Permet de se connecter à la base de données et de faire le pont
|
||||
* entre la classe PDO et nos actions.
|
||||
*/
|
||||
final class Database {
|
||||
|
||||
/**
|
||||
* Contient les informations de connexion à notre BDD.
|
||||
* @var array
|
||||
*/
|
||||
private array $databaseInfos;
|
||||
|
||||
/**
|
||||
* Instance PDO.
|
||||
* @var \PDO
|
||||
*/
|
||||
public private(set) \PDO $pdo;
|
||||
|
||||
/**
|
||||
* Constructeur, lance la connexion.
|
||||
* @param array $loginInfos ['name','host','port','user','pass']
|
||||
*/
|
||||
public function __construct( array $loginInfos ){
|
||||
$this->databaseInfos = $loginInfos;
|
||||
$this->tryLogin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'essayer un login à la base de données.
|
||||
* @return void - never si la connexion échoue.
|
||||
*/
|
||||
private function tryLogin(): void {
|
||||
try {
|
||||
$dsn = 'mysql:dbname=' . $this->databaseInfos['name'] . ';host=' . $this->databaseInfos['host'] . ';port=' . $this->databaseInfos['port'];
|
||||
$this->pdo = new \PDO( $dsn, $this->databaseInfos['user'], $this->databaseInfos['pass'] );
|
||||
} catch ( \PDOException $e ) {
|
||||
die( $e->getMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,6 +7,7 @@ use App\Helpers\Authentification;
|
||||
use App\Helpers\AutoLoader;
|
||||
use App\Helpers\ConfigFactory;
|
||||
use App\Http\Router;
|
||||
use App\Infrastructure\Database;
|
||||
|
||||
/**
|
||||
* Classe primaire du site.
|
||||
@@ -22,6 +23,14 @@ final class Kernel {
|
||||
*/
|
||||
public private(set) static array $configs = [];
|
||||
|
||||
/**
|
||||
* Instance à la base de données.
|
||||
* Pour utiliser la classe PDO : $DB->PDO.
|
||||
*
|
||||
* @var Database|null
|
||||
*/
|
||||
public private(set) static ?Database $DB = null;
|
||||
|
||||
/**
|
||||
* Instance actuelle de l'application.
|
||||
* @var Kernel|null
|
||||
@@ -62,6 +71,7 @@ final class Kernel {
|
||||
public function init(): void {
|
||||
$this->buildAutoloader();
|
||||
$this->loadConfig();
|
||||
$this->loadDatabase();
|
||||
|
||||
Authentification::startSession();
|
||||
|
||||
@@ -89,6 +99,7 @@ final class Kernel {
|
||||
try {
|
||||
|
||||
self::$configs['general'] = ConfigFactory::loadConfigFile('general');
|
||||
self::$configs['database'] = ConfigFactory::loadConfigFile('database');
|
||||
self::$configs['route_arguments'] = ConfigFactory::loadConfigFile('route_arguments');
|
||||
self::$configs['views'] = ConfigFactory::loadConfigFile('views');
|
||||
|
||||
@@ -97,4 +108,12 @@ final class Kernel {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de se connecter à la base de données principale.
|
||||
* @return void
|
||||
*/
|
||||
private function loadDatabase(): void {
|
||||
self::$DB = new Database( self::$configs['database'] );
|
||||
}
|
||||
|
||||
}
|
||||
32
views/home.php
Normal file
32
views/home.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<h1>Coucou</h1>
|
||||
<?php $str = "Markdown **text**\n# SOLONG\n*text*."; $md = \App\Helpers\Markdown::convertToHTML( $str ); echo "<p>$md</p>"; ?>
|
||||
<?php use App\Infrastructure\View as V; use App\Http\Router; ?>
|
||||
|
||||
|
||||
<?php
|
||||
|
||||
|
||||
|
||||
|
||||
$recette = new \App\Domain\Recettes\RecetteRepository()->getByID( 2 );
|
||||
$modelingredient = new \App\Domain\Ingredients\Ingredient();
|
||||
$modelingredient->num_ingredient=0;
|
||||
$modelingredient->nom_ingredient='nomdingredientaupif';
|
||||
var_dump($modelingredient);
|
||||
//$ingredient = new \App\Domain\Ingredients\IngredientRepository()->add($modelingredient);
|
||||
//pas de add si numing existe déjà use autoincrement
|
||||
$ingredient = new \App\Domain\Ingredients\IngredientRepository()->getByID( 1 );
|
||||
var_dump( $recette );
|
||||
var_dump( $ingredient );
|
||||
// new \App\Domain\Recettes\RecetteRepository()->removeAnIngredient( $ingredient, $recette );
|
||||
var_dump( $recette->getAllLinkedIngredients() );
|
||||
echo "\n\n";
|
||||
$modelUtilisateurs = new \App\Domain\Utilisateurs\Utilisateurs();
|
||||
$modelUtilisateurs->num_user=0;
|
||||
$modelUtilisateurs->username="usnmaemaee";
|
||||
$modelUtilisateurs->userpassword="pawssorddd";
|
||||
$user = new \App\Domain\Utilisateurs\UtilisateursRepository()->add($modelUtilisateurs);
|
||||
$user = new \App\Domain\Utilisateurs\UtilisateursRepository()->getByID( 2 );
|
||||
var_dump($user);
|
||||
|
||||
?>
|
||||
23
views/login.php
Normal file
23
views/login.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php use App\Infrastructure\View as V; use App\Http\Router; ?>
|
||||
|
||||
<div class=formcont>
|
||||
<form id='login-form' action='<?php echo Router::getRouteURL( 'api->auth' ); ?>' method='post'>
|
||||
|
||||
<div class='form-group'>
|
||||
<label for='logmsg'>Se Connecter</label>
|
||||
</div>
|
||||
<div id="login-errors" class="form-error" style="display:none;color:red;">
|
||||
</div>
|
||||
<div class='form-group'>
|
||||
<input type='text' class='form-control' name='username' id='username' value='' placeholder="Pseudo">
|
||||
</div>
|
||||
|
||||
<div class='form-group'>
|
||||
<input type='text' class='form-control' name='password' id='password' value='' placeholder="Mot de Passe">
|
||||
</div>
|
||||
|
||||
<button type='submit' class='btn btn-primary'>Confirmer</button>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
<script src="<?php echo Router::getAssetURL( 'js/login.js' ); ?>" defer></script>
|
||||
30
views/partials/header.php
Normal file
30
views/partials/header.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php use App\Infrastructure\View as V; ?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title><?php echo V::getHeadTitle(); ?></title>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="stylesheet" href="<?php V::assetUrl( 'css/style.css' ); ?>" />
|
||||
</head>
|
||||
<body>
|
||||
<header id="header">
|
||||
<div id="logo">
|
||||
<a href="index.php">
|
||||
<img src="<?php V::assetUrl( 'images/Logo.jpg'); ?>" class="logo">
|
||||
</a>
|
||||
</div>
|
||||
<nav>
|
||||
<ul class="nav-list">
|
||||
<li><a id="google" class="nav-element" href="<?php V::routeUrl( 'home'); ?>">Acceuil</a></li>
|
||||
<li><a id="unTest" class="nav-element" href="<?php V::routeUrl( 'recettes->index'); ?>">Liste des recettes</a></li>
|
||||
<?php if( \App\Helpers\Authentification::isLoggedIn() ): ?>
|
||||
<li><a id="login" class= "nav-element" href="<?php V::routeUrl( 'logout'); ?>">Logout</a></li>
|
||||
<li><a id="addBouton" class="nav-element" href="<?php V::routeUrl( 'recettes->create'); ?>">Ajouter une Recette</a></li>
|
||||
<?php else: ?>
|
||||
<li><a id="login" class= "nav-element" href="<?php V::routeUrl( 'login'); ?>">Login</a></li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
<input type="text" class="search-form search-form-recette" placeholder="Rechercher une recette ...">
|
||||
</nav>
|
||||
</header>
|
||||
39
views/partials/tag-sidebar.php
Normal file
39
views/partials/tag-sidebar.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php use App\Infrastructure\View as V; ?>
|
||||
|
||||
<div class="sidebar">
|
||||
<div class="tag-cont">
|
||||
<h4>Tag</h4>
|
||||
<div class="tag-selected-div">
|
||||
<ul>
|
||||
</ul>
|
||||
</div>
|
||||
<form class="sidebar-search" action="none">
|
||||
<input type="text" class="search-form search-form-tag" name="search-tag" placeholder="Rechercher..." >
|
||||
</form>
|
||||
<div class="tag-unselected-div">
|
||||
<ul>
|
||||
<?php foreach( V::arg( 'tagsList') as $tag ): ?>
|
||||
<li class="tag tag-unselected" onclick="test()"><?php echo $tag->nom_tag; ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<hr id="hr">
|
||||
<div class="ingr-cont">
|
||||
<h4>Ingrédient</h4>
|
||||
<div class="tag-selected-div">
|
||||
<ul>
|
||||
</ul>
|
||||
</div>
|
||||
<form class="sidebar-search" action="none">
|
||||
<input type="text" class="search-form search-form-tag" name="search-ingr" placeholder="Rechercher..." >
|
||||
</form>
|
||||
<div class="tag-unselected-div">
|
||||
<ul>
|
||||
<?php foreach( V::arg( 'ingredientsList') as $tag ): ?>
|
||||
<li class="tag tag-unselected" onclick="test()"><?php echo $tag->nom_ingredient; ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
19
views/recettes/index.php
Normal file
19
views/recettes/index.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php use App\Infrastructure\View as V; ?>
|
||||
|
||||
<?php V::partial( 'tag-sidebar' ); ?>
|
||||
<div class="content">
|
||||
<div class="recettes">
|
||||
<?php if( V::arg( 'recettesList' ) != null ) foreach( V::arg( 'recettesList' ) as $recette ): ?>
|
||||
<a class="recette-icone" href="<?php V::routeUrl( 'recettes->show', $recette->slug ); ?>">
|
||||
<img class="recette-preview-image" src="random-recette.jpg">
|
||||
<div class="recette-icone-content">
|
||||
<h3><?php echo $recette->titre_recette; ?></h3>
|
||||
<ul>
|
||||
<li>Temps de préparation : <?php echo $recette->temps_de_preparation; ?></li>
|
||||
<li>Nombre d'ingrédients : <?php echo $recette->getNumberOfIngredients(); ?></li>
|
||||
</ul>
|
||||
</div>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user