BenBack #1

Merged
Benjamin merged 2 commits from BenBack into master 2026-03-20 13:00:11 +00:00
11 changed files with 267 additions and 18 deletions
Showing only changes of commit 43eb936532 - Show all commits

View File

@@ -0,0 +1,6 @@
<?php
return [
'{int}' => '([0-9]+)',
'{chars}' => '([A-Za-z]+)',
'{string}' => '([0-9A-Za-z]+)',
];

4
config/views.php Normal file
View File

@@ -0,0 +1,4 @@
<?php
return [
'base_view_skeleton' => 'base'
];

View File

@@ -3,6 +3,7 @@
namespace App\Domain\Pages;
use App\Domain\Controller;
use App\Infrastructure\View;
/**
* Controller pour les pages sans lien avec un contenu spécifique.
@@ -14,7 +15,7 @@ class PagesController extends Controller {
{
return [
self::Route( routeUrl: '/', routeName: 'Homepage', routeAction: 'index' ),
self::ROute( routeUrl: '/test/{int}', routeName: 'test', routeAction: 'test' ),
self::Route( routeUrl: '/test/{string}/baba', routeName: 'test', routeAction: 'test' ),
];
}
@@ -23,11 +24,11 @@ class PagesController extends Controller {
* Route de la page d'accueil.
* @return void
*/
public function index(): void {
echo "Coucou";
public function index(): View {
return new View( 'home', [ 'ok' => 'bla' ] );
}
public function test( int $id ): void {
public function test( string $id ): void {
echo "Coucou" . $id;
}

View 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 );
}
}

View File

@@ -5,6 +5,7 @@ namespace App\Http;
use App\Domain\Controller;
use App\Exceptions\InvalidRouteException;
use App\Helpers\AutoLoader;
use App\Kernel;
use FilesystemIterator;
final class Router {
@@ -21,6 +22,12 @@ final class Router {
*/
public private(set) static Route $clientRoute;
/**
* Informations sur les arguments passés à la route.
* @var array
*/
public private(set) static array $clientRouteArguments;
/**
* Liste des controllers sorti du cache ou récupéré via fetchControllers.
* @var array
@@ -34,7 +41,7 @@ final class Router {
private static array $routes;
/**
* Fonction principale qui va router le contenu vers la bonne méthode du bon Controlleur.
* 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é.
@@ -121,17 +128,14 @@ final class Router {
*/
private static function clientRouteExist(): Route|bool {
$clientRouteName = trim( self::$clientRouteString, '/' );
foreach( self::$routes as $route ){
/*
if( preg_match( self::getRegexRoute( $route), self::$clientRouteString, $matches ) ){
var_dump( $matches );
}
*/
/*
if( $route->routeUrl === self::$clientRouteString ){
$routeName = self::getRegexRoute( $route );
if( preg_match( $routeName, $clientRouteName, $matches ) ){
array_shift( $matches );
self::$clientRouteArguments = $matches;
return $route;
}
*/
}
return false;
@@ -139,20 +143,22 @@ final class Router {
}
private static function getRegexRoute( Route $route ): string {
$routeUrl = $route->routeUrl;
$routeUrl = str_replace( "{int}", "([0-9]+)", $routeUrl );
return $routeUrl;
$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.
* Va permettre d'exécuter la méthode du Controlleraction() en parsant les arguments si existants.
* @return void
*/
private static function executeRouteAction(): void {
$controller = self::$clientRoute->routeController;
$method = self::$clientRoute->routeAction;
new $controller()->$method();
new $controller()->$method( ...self::$clientRouteArguments);
}
}

194
src/Infrastructure/View.php Normal file
View File

@@ -0,0 +1,194 @@
<?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.
$content = file_get_contents( self::VIEW_PATH . $this->viewName );
// On démarre la vue du squelette.
$base = new View( $this->skeleton, $this->viewArgs, skeleton: null, integratedContent: [ 'content' => $content ] );
}
}
/*
* 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 ] ) )
echo 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;
}
}
public static function getHeadTitle(): string {
$siteUrl = Kernel::$configs['general']['website_name'];
return Router::$clientRoute->routeName . ' - ' . $siteUrl;
}
}

View File

@@ -84,7 +84,11 @@ final class Kernel {
*/
private function loadConfig(): void {
try {
self::$configs['general'] = ConfigFactory::loadConfigFile('general');
self::$configs['route_arguments'] = ConfigFactory::loadConfigFile('route_arguments');
self::$configs['views'] = ConfigFactory::loadConfigFile('views');
} catch( ConfigFailedLoadingException $e ){
die( $e->getMessage() );
}

7
views/base.php Normal file
View File

@@ -0,0 +1,7 @@
<?php use App\Infrastructure\View as V; ?>
<?php V::partial( 'header' ); ?>
<?php V::inject( 'content'); ?>
<?php V::partial( 'footer' ); ?>

1
views/home.php Normal file
View File

@@ -0,0 +1 @@
<h1>Coucou</h1>

View File

@@ -0,0 +1,4 @@
<?php use App\Infrastructure\View as V; ?>
</body>
</html>

View File

@@ -0,0 +1,9 @@
<?php use App\Infrastructure\View as V; ?>
<!DOCTYPE html>
<html>
<head>
<title><?php echo V::getHeadTitle(); ?></title>
<meta charset="UTF-8" />
</head>
<body>