ajoutUtilisateurs
This commit is contained in:
41
src/Domain/Controller.php
Normal file
41
src/Domain/Controller.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
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 {
|
||||
|
||||
/**
|
||||
* Va permettre de créer une route en préremplissant certains arguments.
|
||||
* Pour les paramètres, veuillez voir le constructeur d'une Route.
|
||||
*
|
||||
* @param mixed ...$args
|
||||
* @return Route
|
||||
*
|
||||
* @see Route::__construct()
|
||||
*/
|
||||
public static function Route( ...$args ): Route {
|
||||
$defaults = [
|
||||
'routeController' => static::class,
|
||||
'routeMethods' => [ 'GET' ],
|
||||
'pageHeadTitle' => 'Page',
|
||||
];
|
||||
|
||||
$args = array_merge($defaults, $args);
|
||||
return new Route( ...$args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de définir les routes du controller sous le format d'une liste d'objets Route.
|
||||
* Vous pouvez utiliser la method self::Route() pour préremplir des champs.
|
||||
*
|
||||
* @return Route[]
|
||||
* @see self::Route()
|
||||
*/
|
||||
abstract public static function defineRoutes(): array;
|
||||
|
||||
}
|
||||
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;
|
||||
|
||||
}
|
||||
34
src/Domain/Pages/PagesController.php
Normal file
34
src/Domain/Pages/PagesController.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain\Pages;
|
||||
|
||||
use App\Domain\Controller;
|
||||
use App\Infrastructure\View;
|
||||
|
||||
/**
|
||||
* Controller pour les pages sans lien avec un contenu spécifique.
|
||||
* Exemple : Page d'accueil.
|
||||
*/
|
||||
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" ),
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Route de la page d'accueil.
|
||||
* @return void
|
||||
*/
|
||||
public function index(): View {
|
||||
return new View( 'home', [ 'ok' => 'bla' ] );
|
||||
}
|
||||
|
||||
}
|
||||
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 );
|
||||
}
|
||||
|
||||
}
|
||||
16
src/Domain/Recettes/RecettesAPIController.php
Normal file
16
src/Domain/Recettes/RecettesAPIController.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain\Recettes;
|
||||
|
||||
use App\Domain\Controller;
|
||||
|
||||
class RecettesAPIController extends Controller {
|
||||
|
||||
public static function defineRoutes(): array
|
||||
{
|
||||
return [
|
||||
self::Route( routeUrl: '/api/recettes/list', routeName: 'api->recettes->list', routeAction: 'list', routeMethods: ['POST'] ),
|
||||
];
|
||||
|
||||
}
|
||||
}
|
||||
36
src/Domain/Recettes/RecettesController.php
Normal file
36
src/Domain/Recettes/RecettesController.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
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 {
|
||||
|
||||
public static function defineRoutes(): array
|
||||
{
|
||||
return [
|
||||
self::Route( routeUrl: '/recettes', routeName: 'recettes->index', routeAction: 'index', pageHeadTitle: 'Liste des recettes' ),
|
||||
self::Route( routeUrl: '/recettes/{string}', routeName: 'recettes->show', routeAction: 'show', pageHeadTitle: 'Recette' ),
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
public function index(): View {
|
||||
|
||||
$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 ),
|
||||
] );
|
||||
}
|
||||
|
||||
}
|
||||
17
src/Domain/Recettes/RecettesManagementController.php
Normal file
17
src/Domain/Recettes/RecettesManagementController.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain\Recettes;
|
||||
|
||||
use App\Domain\Controller;
|
||||
|
||||
class RecettesManagementController extends Controller {
|
||||
|
||||
public static function defineRoutes(): array
|
||||
{
|
||||
return [
|
||||
self::Route( routeUrl: '/recettes/create', routeName: 'recettes->create', routeAction: 'create' ),
|
||||
self::Route( routeUrl: '/recettes/edit/{int}', routeName: 'recettes->edit', routeAction: 'edit' ),
|
||||
];
|
||||
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
}
|
||||
68
src/Domain/Utilisateurs/AuthentificationController.php
Normal file
68
src/Domain/Utilisateurs/AuthentificationController.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domain\Utilisateurs;
|
||||
|
||||
use App\Domain\Controller;
|
||||
use App\Helpers\Authentification;
|
||||
use App\Http\JSONResponse;
|
||||
use App\Http\Request;
|
||||
use App\Infrastructure\View;
|
||||
|
||||
class AuthentificationController extends Controller {
|
||||
|
||||
public static function defineRoutes(): array {
|
||||
|
||||
return [
|
||||
|
||||
// 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'] ),
|
||||
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
$username = Request::get( 'username' );
|
||||
$password = Request::get( 'password' );
|
||||
|
||||
// TODO : Récupération de l'utilisateur et verify_password.
|
||||
|
||||
$userId = 1;
|
||||
Authentification::loginUser( $userId );
|
||||
return JSONResponse::sendSuccess( [ 'user_id' => $userId ] );
|
||||
|
||||
}
|
||||
|
||||
public function logout(): JSONResponse {
|
||||
|
||||
if( !Authentification::isLoggedIn() ) {
|
||||
return JSONResponse::sendError( [ 'message' => 'Already disconnected' ] );
|
||||
}
|
||||
|
||||
Authentification::destroySession();
|
||||
return JSONResponse::sendSuccess( [ 'message' => 'Logged out' ] );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
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' );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
28
src/Exceptions/ConfigFailedLoadingException.php
Normal file
28
src/Exceptions/ConfigFailedLoadingException.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
/**
|
||||
* Exception qui se déclenche lorsqu'un fichier de configuration n'a pas pu être chargé.
|
||||
*
|
||||
* - Peut se déclencher si un fichier de configuration non voulu.
|
||||
*/
|
||||
class ConfigFailedLoadingException extends \Exception {
|
||||
|
||||
/**
|
||||
* Chemin vers le fichier de configuration manquant.
|
||||
* @var string
|
||||
*/
|
||||
public private(set) string $configFilePath;
|
||||
|
||||
/**
|
||||
* Constructeur.
|
||||
* @param string $configFilePath Le fichier de configuration manquant.
|
||||
*/
|
||||
public function __construct( string $configFilePath ) {
|
||||
$this->configFilePath = $configFilePath;
|
||||
$this->message = "Failed to load configuration file '{$configFilePath}'.";
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
}
|
||||
15
src/Exceptions/InvalidRouteException.php
Normal file
15
src/Exceptions/InvalidRouteException.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exceptions;
|
||||
class InvalidRouteException extends \Exception {
|
||||
|
||||
private string $clientRoute;
|
||||
|
||||
public function __construct(string $clientRoute)
|
||||
{
|
||||
$this->clientRoute = $clientRoute;
|
||||
$message = "{$clientRoute} doesn't exist";
|
||||
parent::__construct($message, 404);
|
||||
}
|
||||
|
||||
}
|
||||
13
src/Exceptions/InvalidViewException.php
Normal file
13
src/Exceptions/InvalidViewException.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exceptions;
|
||||
use Throwable;
|
||||
|
||||
class InvalidViewException extends \Exception {
|
||||
|
||||
public function __construct( string $viewName )
|
||||
{
|
||||
parent::__construct( "View {$viewName} does not exist.", 500 );
|
||||
}
|
||||
|
||||
}
|
||||
49
src/Helpers/Authentification.php
Normal file
49
src/Helpers/Authentification.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace App\Helpers;
|
||||
|
||||
class Authentification {
|
||||
|
||||
/**
|
||||
* Permet de démarrer la variable Session.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function startSession(): void {
|
||||
session_start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de supprimer la session.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function destroySession(): void {
|
||||
session_destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de connecter un utilisateur.
|
||||
*
|
||||
* @param int $userId
|
||||
* @return void
|
||||
*/
|
||||
public static function loginUser( int $userId ){
|
||||
$_SESSION['user'] = $userId;
|
||||
}
|
||||
|
||||
// TODO : Complete when user.
|
||||
public static function getCurrentUser() {
|
||||
return $_SESSION['user'] ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de savoir si un utilisateur est connecté ou pas.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isLoggedIn(): bool {
|
||||
return self::getCurrentUser() !== false;
|
||||
}
|
||||
|
||||
}
|
||||
38
src/Helpers/AutoLoader.php
Normal file
38
src/Helpers/AutoLoader.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
namespace App\Helpers;
|
||||
|
||||
/**
|
||||
* Classe utilitaire contenant des méthodes pour charger automatiquement les classes.
|
||||
*/
|
||||
class AutoLoader {
|
||||
|
||||
/**
|
||||
* Namespace principal de l'application.
|
||||
*/
|
||||
public const string PRIMARY_NAMESPACE = 'App\\';
|
||||
|
||||
/**
|
||||
* Permet d'enregistrer la méthode _autoload_ en tant que méthode pour charger des classes.
|
||||
* @return void
|
||||
*/
|
||||
public static function register(): void {
|
||||
spl_autoload_register( [ self::class, '_autoload_' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de charger une classe.
|
||||
*
|
||||
* @param string $className
|
||||
* @return void
|
||||
*/
|
||||
public static function _autoload_( string $className ): void {
|
||||
if( !str_starts_with( $className, self::PRIMARY_NAMESPACE ) ) // Ne s'occupe que des classes à charger de cette application.
|
||||
return;
|
||||
|
||||
$className = str_replace( self::PRIMARY_NAMESPACE, '', $className );
|
||||
$className = str_replace( '\\', '/', $className );
|
||||
|
||||
require APP_ROOT . 'src/' . $className . '.php';
|
||||
}
|
||||
|
||||
}
|
||||
42
src/Helpers/ConfigFactory.php
Normal file
42
src/Helpers/ConfigFactory.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Helpers;
|
||||
|
||||
use App\Exceptions\ConfigFailedLoadingException;
|
||||
|
||||
/**
|
||||
* Classe outillage qui permet de charger les fichiers de configuration.
|
||||
*/
|
||||
class ConfigFactory {
|
||||
|
||||
/**
|
||||
* Chemin relatif à partir de APP_ROOT du dossier contenant les fichiers de configuration.
|
||||
*
|
||||
* @see APP_ROOT
|
||||
*/
|
||||
const string CONFIG_RELATIVE_FOLDER = "config/";
|
||||
|
||||
/**
|
||||
* Permet de charger un fichier de configuration.
|
||||
*
|
||||
* @param string $fileName Le nom du fichier de configuration, avec ou sans l'extension .php.
|
||||
* @return array
|
||||
*
|
||||
* @throws ConfigFailedLoadingException
|
||||
*/
|
||||
public static function loadConfigFile( string $fileName ): array {
|
||||
if( !str_ends_with( $fileName, ".php" ) ) {
|
||||
$fileName .= ".php";
|
||||
}
|
||||
|
||||
$filePath = APP_ROOT . self::CONFIG_RELATIVE_FOLDER . $fileName;
|
||||
|
||||
if( !file_exists( $filePath ) ){
|
||||
throw new ConfigFailedLoadingException( "Config file '$fileName' does not exist" );
|
||||
}
|
||||
|
||||
$configArray = require $filePath;
|
||||
return $configArray;
|
||||
}
|
||||
|
||||
}
|
||||
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 );
|
||||
}
|
||||
}
|
||||
27
src/Helpers/SanitizeTrait.php
Normal file
27
src/Helpers/SanitizeTrait.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Helpers;
|
||||
|
||||
/**
|
||||
* Trait qui permet de désinfecter une variable.
|
||||
*/
|
||||
trait SanitizeTrait {
|
||||
|
||||
/**
|
||||
* Permet de désinfecter une variable
|
||||
*
|
||||
* @param mixed $data
|
||||
* @return mixed
|
||||
*/
|
||||
public static function sanitize( mixed $data ): mixed {
|
||||
|
||||
if( is_string( $data ) ) {
|
||||
return htmlspecialchars( $data, ENT_QUOTES );
|
||||
} else if( is_integer( $data ) ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
return $data;
|
||||
|
||||
}
|
||||
}
|
||||
51
src/Http/JSONResponse.php
Normal file
51
src/Http/JSONResponse.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http;
|
||||
|
||||
/**
|
||||
* Permet de renvoyer une réponse de route au format JSON.
|
||||
*/
|
||||
class JSONResponse {
|
||||
|
||||
/**
|
||||
* Les données ajoutés au fichier JSON.
|
||||
* @var array|mixed
|
||||
*/
|
||||
public private(set) array $data;
|
||||
|
||||
/**
|
||||
* Le code HTML de la réponse.
|
||||
* @var int|mixed
|
||||
*/
|
||||
public private(set) int $htmlCode;
|
||||
|
||||
public function __construct( $data = [], $code = 200 ){
|
||||
|
||||
$this->data = $data;
|
||||
$this->htmlCode = $code;
|
||||
|
||||
$this->returnResponse();
|
||||
}
|
||||
|
||||
public function returnResponse(): never {
|
||||
|
||||
header( 'Content-type: application/json' );
|
||||
http_response_code( $this->htmlCode );
|
||||
|
||||
$this->data['_status'] = $this->htmlCode;
|
||||
$json = json_encode( $this->data );
|
||||
echo $json;
|
||||
die();
|
||||
}
|
||||
|
||||
public static function sendSuccess( $data = [] ): self {
|
||||
$data['success'] = true;
|
||||
return new self( $data, 200 );
|
||||
}
|
||||
|
||||
public static function sendError( $data = [] ): self {
|
||||
$data['success'] = false;
|
||||
return new self( $data, 400 );
|
||||
}
|
||||
|
||||
}
|
||||
69
src/Http/Request.php
Normal file
69
src/Http/Request.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http;
|
||||
use App\Helpers\SanitizeTrait;
|
||||
use App\Kernel;
|
||||
|
||||
/**
|
||||
* Classe utilitaire ayant plusieurs méthodes pour gérer la requête actuelle.
|
||||
*/
|
||||
class Request {
|
||||
|
||||
use SanitizeTrait;
|
||||
|
||||
/**
|
||||
* Bloquer les CORS venant d'autres sites.
|
||||
* @return void
|
||||
*/
|
||||
public static function setCORS(): void {
|
||||
$siteUrl = Kernel::$configs['general']['website_url'];
|
||||
header("Access-Control-Allow-Origin: {$siteUrl}");
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'obtenir une variable GET et nettoyé.
|
||||
*
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get( string $name ): mixed {
|
||||
|
||||
if( !isset( $_GET[$name] ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return self::sanitize( $_GET[$name] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'obtenir une variable POST et nettoyé.
|
||||
*
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*/
|
||||
public static function post( string $name ): mixed {
|
||||
|
||||
if( !isset( $_POST[$name] ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
42
src/Http/Route.php
Normal file
42
src/Http/Route.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http;
|
||||
|
||||
/**
|
||||
* Permet de définir une route précise.
|
||||
*/
|
||||
final class Route {
|
||||
|
||||
|
||||
public private(set) string $routeUrl;
|
||||
public private(set) string $routeName;
|
||||
public private(set) string $routeController;
|
||||
public private(set) string $routeAction;
|
||||
public private(set) array $routeMethods;
|
||||
public private(set) string $pageHeadTitle;
|
||||
|
||||
/**
|
||||
* @param string $routeUrl Le chemin vers la route.
|
||||
* @param string $routeName Le nom de la route.
|
||||
* @param string $routeController Le controller qui va interpréter cette route.
|
||||
* @param string $routeAction L'action du controller qui va interpréter cette route.
|
||||
* @param array $routeMethods Une liste de methodes GET, POST que la page accepte.
|
||||
* @param string $pageHeadTitle Le nom de la page qui sera affiché dans <title></title>.
|
||||
*/
|
||||
public function __construct(
|
||||
string $routeUrl,
|
||||
string $routeName,
|
||||
string $routeController,
|
||||
string $routeAction,
|
||||
array $routeMethods,
|
||||
string $pageHeadTitle,
|
||||
){
|
||||
$this->routeUrl = $routeUrl;
|
||||
$this->routeName = $routeName;
|
||||
$this->routeController = $routeController;
|
||||
$this->routeAction = $routeAction;
|
||||
$this->routeMethods = $routeMethods;
|
||||
$this->pageHeadTitle = $pageHeadTitle;
|
||||
}
|
||||
|
||||
}
|
||||
202
src/Http/Router.php
Normal file
202
src/Http/Router.php
Normal file
@@ -0,0 +1,202 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http;
|
||||
|
||||
use App\Domain\Controller;
|
||||
use App\Exceptions\InvalidRouteException;
|
||||
use App\Helpers\AutoLoader;
|
||||
use App\Kernel;
|
||||
use FilesystemIterator;
|
||||
|
||||
final class Router {
|
||||
|
||||
/**
|
||||
* Route voulue par le client.
|
||||
* @var string
|
||||
*/
|
||||
public private(set) static string $clientRouteString;
|
||||
// private(set)
|
||||
/**
|
||||
* Informations de la route du client.
|
||||
* @var Route
|
||||
*/
|
||||
public static Route $clientRoute;
|
||||
// private(set)
|
||||
/**
|
||||
* Informations sur les arguments passés à la route.
|
||||
* @var array
|
||||
*/
|
||||
public static array $clientRouteArguments;
|
||||
// private(set)
|
||||
/**
|
||||
* Liste des controllers sorti du cache ou récupéré via fetchControllers.
|
||||
* @var array
|
||||
*/
|
||||
private static array $controllers;
|
||||
|
||||
/**
|
||||
* Liste des routes tirées des controllers. Rempli par la méthode fetchRoutes.
|
||||
* @var Route[]
|
||||
*/
|
||||
private static array $routes;
|
||||
|
||||
/**
|
||||
* Fonction principale qui va router le contenu vers la bonne méthode du bon Controller.
|
||||
* @return void
|
||||
*
|
||||
* @throws InvalidRouteException Si la route voulue n'existe pas ou n'est pas bien formaté.
|
||||
*/
|
||||
public static function routeTo(): void {
|
||||
|
||||
self::$clientRouteString = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
|
||||
|
||||
self::$controllers = self::fetchControllers();
|
||||
self::$routes = self::fetchRoutes();
|
||||
|
||||
$clientRoute = self::clientRouteExist();
|
||||
if( !$clientRoute ){
|
||||
throw new InvalidRouteException( self::$clientRouteString );
|
||||
}
|
||||
self::$clientRoute = $clientRoute;
|
||||
|
||||
if( !in_array( $_SERVER['REQUEST_METHOD'], self::$clientRoute->routeMethods ) ){
|
||||
throw new InvalidRouteException( self::$clientRouteString );
|
||||
} else {
|
||||
self::executeRouteAction();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de récupérer tous les controllers du dossier Domain.
|
||||
* @return class-string[]
|
||||
*/
|
||||
private static function fetchControllers(): array {
|
||||
|
||||
$classes = [];
|
||||
|
||||
$iterator = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator( APP_ROOT . 'src/Domain', FilesystemIterator::SKIP_DOTS ),
|
||||
);
|
||||
|
||||
foreach( $iterator as $file ){
|
||||
|
||||
if( $file->isFile() && $file->getExtension() === 'php' ){
|
||||
|
||||
$fileName = $file->getPathname();
|
||||
|
||||
// Transformation du chemin du fichier vers le nom complet de la classe.
|
||||
$fileName = str_replace( APP_ROOT . 'src/', AutoLoader::PRIMARY_NAMESPACE, $fileName );
|
||||
$fileName = str_replace( '.php', '', $fileName );
|
||||
$fileName = str_replace( '/', '\\', $fileName );
|
||||
|
||||
|
||||
/*
|
||||
* Vérifie que l'on est bien sur un Controller.
|
||||
* Ignore Controller car Controller n'est pas une sous-classe de Controller.
|
||||
*/
|
||||
if( is_subclass_of( $fileName, Controller::class ) ){
|
||||
$classes[] = $fileName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $classes;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupérer toutes les routes des controllers récupéré avant.
|
||||
* @return Route[]
|
||||
*/
|
||||
private static function fetchRoutes(): array {
|
||||
|
||||
$routes = [];
|
||||
|
||||
foreach( self::$controllers as $controllerClassString ){
|
||||
$routes = array_merge( $routes, $controllerClassString::defineRoutes() );
|
||||
}
|
||||
|
||||
return $routes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de savoir si la route que le client veut existe.
|
||||
* @return Route|bool Retourne la route de l'utilisateur ou false si inexistante.
|
||||
*/
|
||||
private static function clientRouteExist(): Route|bool {
|
||||
|
||||
$clientRouteName = trim( self::$clientRouteString, '/' );
|
||||
|
||||
foreach( self::$routes as $route ){
|
||||
|
||||
$routeName = self::getRegexRoute( $route );
|
||||
if( preg_match( $routeName, $clientRouteName, $matches ) ){
|
||||
array_shift( $matches ); // On enlève la chaine complète.
|
||||
self::$clientRouteArguments = $matches;
|
||||
return $route;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de remplacer les expressions définies dans la configuration par leurs équivalents Regex.
|
||||
*
|
||||
* @param Route $route
|
||||
* @return string
|
||||
*/
|
||||
private static function getRegexRoute( Route $route ): string {
|
||||
$routeUrl = trim( $route->routeUrl, '/' );
|
||||
foreach ( Kernel::$configs['route_arguments'] as $key => $value ){
|
||||
$routeUrl = str_replace( $key, $value, $routeUrl );
|
||||
}
|
||||
return "#^{$routeUrl}$#";
|
||||
}
|
||||
|
||||
/**
|
||||
* Va permettre d'exécuter la méthode du Controller→action() en parsant les arguments si existants.
|
||||
* @return void
|
||||
*/
|
||||
private static function executeRouteAction(): void {
|
||||
$controller = self::$clientRoute->routeController;
|
||||
$method = self::$clientRoute->routeAction;
|
||||
|
||||
(new $controller())->$method( ...self::$clientRouteArguments);
|
||||
//correction controler()->method to controler().method
|
||||
// new $controller()->$method( ...self::$clientRouteArguments);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'obtenir l'adresse du site vers une route spécifique.
|
||||
*
|
||||
* @param string $routeName Le nom de la route.
|
||||
* @param ...$args - Les arguments de la route, si existants.
|
||||
*
|
||||
* @return string Renvoie l'URL demandé ou bien la racine du site si la route n'existe pas.
|
||||
*/
|
||||
public static function getRouteURL( string $routeName, ...$args ): string {
|
||||
foreach( self::$routes as $route ){
|
||||
if( $routeName === $route->routeName ){
|
||||
$i = 0;
|
||||
$routeUrl = preg_replace_callback( '/\{([^}]+)}/', function( $match ) use ( $args, &$i ){
|
||||
return $args[$i++] ?? "";
|
||||
}, $route->routeUrl);
|
||||
|
||||
return rtrim( rtrim( Kernel::$configs['general']['website_url'], '/' ) . $routeUrl, '/' );
|
||||
}
|
||||
}
|
||||
|
||||
return Kernel::$configs['general']['website_url'];
|
||||
}
|
||||
|
||||
public static function getAssetURL( string $assetPath ): string {
|
||||
return Kernel::$configs['general']['website_url'] . 'assets/' . $assetPath;
|
||||
}
|
||||
|
||||
}
|
||||
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() );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
220
src/Infrastructure/View.php
Normal file
220
src/Infrastructure/View.php
Normal file
@@ -0,0 +1,220 @@
|
||||
<?php
|
||||
|
||||
namespace App\Infrastructure;
|
||||
|
||||
use App\Exceptions\InvalidViewException;
|
||||
use App\Http\Router;
|
||||
use App\Kernel;
|
||||
|
||||
/**
|
||||
* Permet de rendre une vue / contenu de la page.
|
||||
* /!\ : Une seule vue peut-être appellé par page, hormis celle en plus pour le squelette.
|
||||
*/
|
||||
final class View {
|
||||
|
||||
/**
|
||||
* Répertoire où se trouvent les vues.
|
||||
*/
|
||||
const string VIEW_PATH = APP_ROOT . 'views/';
|
||||
|
||||
/**
|
||||
* Le nom du fichier de vue.
|
||||
* @var string
|
||||
*/
|
||||
public private(set) string $viewName;
|
||||
|
||||
/**
|
||||
* Les arguments passés à la vue.
|
||||
* @var array
|
||||
*/
|
||||
public private(set) array $viewArgs;
|
||||
|
||||
/**
|
||||
* La base de la vue. (Pour ne pas répéter header/footer à chaque fois).
|
||||
* null correspond à pas de squelette.
|
||||
*
|
||||
* @var string|mixed|null
|
||||
*/
|
||||
public private(set) ?string $skeleton;
|
||||
|
||||
/**
|
||||
* Utilisé par les squelettes, permet d'injecter des contenus comme le contenu de son enfant.
|
||||
* @var array<string,string>
|
||||
*/
|
||||
public private(set) array $integratedContent;
|
||||
|
||||
/**
|
||||
* Garde la dernière instance de vue.
|
||||
* Si il y a un squelette, ce sera l'instance du squelette.
|
||||
*
|
||||
* @var View
|
||||
*/
|
||||
private static self $lastInstance;
|
||||
|
||||
/**
|
||||
* Permet de construire les informations de la vue.
|
||||
*
|
||||
* @param string $viewName Le nom du fichier de vue.
|
||||
* @param array $viewArgs Les arguments de la vue.
|
||||
* @param bool $autoRender Si la méthode $this->render() est automatiquement exécuté.
|
||||
* @param string|null $skeleton Le squelette du fichier, null correspond à aucun squelette, default correspond au
|
||||
* squelette défini dans la configuration des vues.
|
||||
* @param array<string,string> $integratedContent Le contenu intégré dans le nouveau squelette.
|
||||
*/
|
||||
public function __construct(
|
||||
string $viewName,
|
||||
array $viewArgs = [],
|
||||
bool $autoRender = true,
|
||||
?string $skeleton = 'default',
|
||||
array $integratedContent = []
|
||||
) {
|
||||
|
||||
if( !str_ends_with( $viewName, '.php' ) ) {
|
||||
$viewName .= '.php';
|
||||
}
|
||||
|
||||
$this->viewName = $viewName;
|
||||
$this->viewArgs = $viewArgs;
|
||||
|
||||
$this->skeleton = $skeleton;
|
||||
if( $this->skeleton === "default" ){
|
||||
$this->skeleton = Kernel::$configs['views']['base_view_skeleton'];
|
||||
}
|
||||
|
||||
$this->integratedContent = $integratedContent;
|
||||
|
||||
try {
|
||||
if (!file_exists(self::VIEW_PATH . $this->viewName)) {
|
||||
throw new InvalidViewException($this->viewName);
|
||||
}
|
||||
|
||||
if ($autoRender) {
|
||||
$this->render();
|
||||
}
|
||||
} catch (InvalidViewException $e) {
|
||||
die( $e->getMessage() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de démarrer le rendu d'une vue.
|
||||
* @return void
|
||||
*/
|
||||
public function startView(): void {
|
||||
ob_start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de finir le rendu d'une vue.
|
||||
* @return void
|
||||
*/
|
||||
public function endView(): void {
|
||||
echo ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de faire le rendu proprement de la vue.
|
||||
* @return void
|
||||
*/
|
||||
public function render(): void {
|
||||
|
||||
self::$lastInstance = $this;
|
||||
|
||||
if( $this->skeleton === null ){
|
||||
|
||||
// Si on a pas de squelette, on inclut la vue.
|
||||
// pour accéder aux éléments de la vue, on utilise les méthodes statiques de cette classe.
|
||||
$this->startView();
|
||||
require self::VIEW_PATH . $this->viewName;
|
||||
$this->endView();
|
||||
|
||||
} else {
|
||||
|
||||
// Si on a un squelette, on charge tout le contenu de la vue enfante.
|
||||
$contentName = $this->viewName;
|
||||
|
||||
// On démarre la vue du squelette.
|
||||
$base = new View( $this->skeleton, $this->viewArgs, skeleton: null, integratedContent: [ 'content' => $contentName ] );
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* VIEW TOOLS
|
||||
*/
|
||||
|
||||
/**
|
||||
* Permet d'injecter un contenu sauvegardé dans $this->integratedContent.
|
||||
*
|
||||
* @param string $integratedContentName
|
||||
* @return void N'affiche rien si le contenu n'existe pas.
|
||||
*/
|
||||
public static function inject( string $integratedContentName ): void {
|
||||
if( isset( self::$lastInstance->integratedContent[ $integratedContentName ] ) )
|
||||
require self::VIEW_PATH . self::$lastInstance->integratedContent[ $integratedContentName ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de récupérer un argument passé à la vue.
|
||||
*
|
||||
* @param string $argumentName
|
||||
* @return mixed null si l'argument n'existe pas.
|
||||
*/
|
||||
public static function arg( string $argumentName ): mixed {
|
||||
if( isset( self::$lastInstance->viewArgs[ $argumentName ] ) )
|
||||
return self::$lastInstance->viewArgs[ $argumentName ];
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'intégrer un bloc à la vue.
|
||||
*
|
||||
* @param string $partialName
|
||||
* @return void N'affiche rien si le bloc n'existe pas.
|
||||
*/
|
||||
public static function partial( string $partialName ): void {
|
||||
|
||||
if( !str_ends_with( $partialName, '.php' ) ) {
|
||||
$partialName .= '.php';
|
||||
}
|
||||
|
||||
if( file_exists( self::VIEW_PATH . 'partials/' . $partialName ) ) {
|
||||
require self::VIEW_PATH . 'partials/' . $partialName;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'obtenir le titre de la page à mettre dans <title></title>
|
||||
* @return string
|
||||
*/
|
||||
public static function getHeadTitle(): string {
|
||||
$siteUrl = Kernel::$configs['general']['website_name'];
|
||||
return Router::$clientRoute->pageHeadTitle . ' - ' . $siteUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'obtenir une route
|
||||
*
|
||||
* @param string $routeName Le nom de la route.
|
||||
* @param ...$args - Les arguments de la route, si existant.
|
||||
*
|
||||
* @return void Affiche uniquement.
|
||||
*/
|
||||
public static function routeUrl( string $routeName, ...$args ): void {
|
||||
echo Router::getRouteURL( $routeName, ...$args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'obtenir l'URL vers un asset (CSS,JS,Images).
|
||||
* @param string $assetPath
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function assetUrl( string $assetPath ): void {
|
||||
echo Router::getAssetURL( $assetPath );
|
||||
}
|
||||
|
||||
}
|
||||
119
src/Kernel.php
Normal file
119
src/Kernel.php
Normal file
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
use App\Exceptions\ConfigFailedLoadingException;
|
||||
use App\Exceptions\InvalidRouteException;
|
||||
use App\Helpers\Authentification;
|
||||
use App\Helpers\AutoLoader;
|
||||
use App\Helpers\ConfigFactory;
|
||||
use App\Http\Router;
|
||||
use App\Infrastructure\Database;
|
||||
|
||||
/**
|
||||
* Classe primaire du site.
|
||||
* Permet de lancer l'application.
|
||||
*/
|
||||
final class Kernel {
|
||||
|
||||
/**
|
||||
* Liste des fichiers de configuration sous le format suivant :
|
||||
* [ 'nom_de_la_config' -> [ 'cle" → valeur ] ]
|
||||
*
|
||||
* @var array<string,array>
|
||||
*/
|
||||
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
|
||||
*/
|
||||
private static ?self $instance = null;
|
||||
|
||||
/**
|
||||
* Méthode qui permet de démarrer le site.
|
||||
* @return self
|
||||
*/
|
||||
public static function start(): self {
|
||||
self::$instance = new self();
|
||||
self::$instance->init();
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'obtenir l'instance actuelle du site.
|
||||
* @return self
|
||||
*/
|
||||
public static function getInstance(): self {
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructeur.
|
||||
*/
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de préparer le démarrage du site.
|
||||
* Lancé automatiquement par start().
|
||||
*
|
||||
* @return void
|
||||
* @see self::start()
|
||||
*/
|
||||
public function init(): void {
|
||||
$this->buildAutoloader();
|
||||
$this->loadConfig();
|
||||
$this->loadDatabase();
|
||||
|
||||
Authentification::startSession();
|
||||
|
||||
try {
|
||||
Router::routeTo();
|
||||
} catch ( InvalidRouteException $e ){
|
||||
die( $e->getMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de mettre en place l'Autoloader.
|
||||
* @return void
|
||||
*/
|
||||
private function buildAutoloader(): void {
|
||||
require_once 'Helpers/AutoLoader.php';
|
||||
AutoLoader::register();
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de charger tous les fichiers de configuration du site.
|
||||
* @return void
|
||||
*/
|
||||
private function loadConfig(): void {
|
||||
try {
|
||||
|
||||
self::$configs['general'] = ConfigFactory::loadConfigFile('general');
|
||||
self::$configs['database'] = ConfigFactory::loadConfigFile('database');
|
||||
self::$configs['route_arguments'] = ConfigFactory::loadConfigFile('route_arguments');
|
||||
self::$configs['views'] = ConfigFactory::loadConfigFile('views');
|
||||
|
||||
} catch( ConfigFailedLoadingException $e ){
|
||||
die( $e->getMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de se connecter à la base de données principale.
|
||||
* @return void
|
||||
*/
|
||||
private function loadDatabase(): void {
|
||||
self::$DB = new Database( self::$configs['database'] );
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user