diff --git a/README.md b/README.md index 27df611..9a34211 100644 --- a/README.md +++ b/README.md @@ -1 +1,57 @@ -# Les Recettes des Papis +# Les recettes des Papis + +## Installation + - Décompressez l'archive du site. + - Pointez votre domaine sur le dossier "public". + - Modifiez les fichiers de configuration dans "config". + +## Informations pratiques sur le PHP. + + - Ce site utilise le principe des routes. Afin de ne pas avoir x fichiers publiques identiques pour chaque page. + - Tout est géré par le fichier public/index.php. + - index.php va charger le Kernel (Noyau) de l'application. + - Le noyau fonctionne sur le principe d'élément unique. La méthode ``Kernel::getInstance()`` va permettre d'avoir l'unique instance de la classe Kernel. + - Une fois ``Kernel::getInstance()->init()`` déclenché, le noyau enregistre l'autoloading des fichiers, puis enregistre la configuration. + - La configuration sont des fichiers dans le dossier config/ qui vont renvoyer un tableau clé/valeur. Exemple + +```php + // Fichier config/test.php + "Val1", + 'cle_2' => "Val2", + // ... + ] ?> +``` + +- Les fichiers de configuration sont chargés via la méthode ``ConfigFactory::loadConfigFile()`` qui va vérifier si le fichier de configuration existe et le charge en conséquence. +- On enchaine ensuite sur le Router. +- Le Router est une classe utilitaire qui va permettre de faire le lien entre la route saisie ``/test/...`` de l'utilisateur et les routes enregistrés par le site. +- Le Router va d'abord commencer par récupérer la route voulue par l'utilisateur. +- Puis, le router va rechercher tous les Controllers existants. +- Un Controller est une classe qui va permettre de définir les routes et de dire, qu'est-ce qui se passe quand je prends cette route. Les routes du Controller sont définis par la methode ``Controller::defineRoutes()`` +- Pour définir les routes dans la méthode précédente, vous pouvez soit créer un objet ``Route`` en remplissant tous les champs, ou bien la méthode ``Controller::Route()`` qui va préremplir certains champs. +- Exemple de Controller +```php + class TestController extends Controller { + + public static function defineRoutes(): array { + return [ + self::Route( routeUrl: '/test', routeName: "Test", routeAction: "test" ), + new Route( routeUrl: "/test2", routeName: "Test2", routeController: "TestController", routeAction: "test2", routeMethods = [ 'GET' ] ) + ]; + } + + public function test(){ + echo "Je suis déclenché lorsque j'atteinds la route /test"; + } + + public function test2(){ + echo "Je suis déclenché lorsque j'atteinds la route /test2 !!!"; + } + } +``` +- Retournons au routeur, pour chercher les controllers, il va scanner les fichiers du dossier src/Domain avec un Iterator Récursif. (Pour se simplifier un peu la tâche.) +- Il va traiter le nom du chemin absolu pour obtenir le nom de la classe, puis va vérifier si cette classe est une sous-classe de Controller. +- Après avoir trouvé tous les Controllers, il va récupérer toutes les routes de chaque controller. +- Enfin, il va vérifier si la route utilisateur correspond à une des routes dans sa liste, si ça correspond, le Router va charger la méthode ``new {RouteController}()->{RouteAction}()`` +- Si par exemple, le router trouve la route ``/test`` voulu par l'utilisateur, il va déclencher la méthode ``new TestController()->test()``. \ No newline at end of file diff --git a/config/general.php b/config/general.php new file mode 100644 index 0000000..862b32d --- /dev/null +++ b/config/general.php @@ -0,0 +1,8 @@ + 'http://127.0.0.1:8080/', + 'website_name' => 'Les recettes des Papis', + + 'website_path' => APP_ROOT, +]; \ No newline at end of file diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..8bbcd78 --- /dev/null +++ b/public/index.php @@ -0,0 +1,13 @@ + static::class, + 'routeMethods' => [ 'GET' ], + ]; + + $args = array_merge($defaults, $args); + return new Route( ...$args ); + } + + /** + * Permet de définir les routes du controller sous le format d'une liste d'objets Route. + * Vous pouvez utiliser la method self::Route() pour préremplir des champs. + * + * @return Route[] + * @see self::Route() + */ + abstract public static function defineRoutes(): array; + +} \ No newline at end of file diff --git a/src/Domain/Pages/PagesController.php b/src/Domain/Pages/PagesController.php new file mode 100644 index 0000000..b8da0c1 --- /dev/null +++ b/src/Domain/Pages/PagesController.php @@ -0,0 +1,34 @@ +configFilePath = $configFilePath; + $this->message = "Failed to load configuration file '{$configFilePath}'."; + parent::__construct(); + } + +} \ No newline at end of file diff --git a/src/Exceptions/InvalidRouteException.php b/src/Exceptions/InvalidRouteException.php new file mode 100644 index 0000000..4b97e00 --- /dev/null +++ b/src/Exceptions/InvalidRouteException.php @@ -0,0 +1,15 @@ +clientRoute = $clientRoute; + $message = "{$clientRoute} doesn't exist"; + parent::__construct($message, 404); + } + +} \ No newline at end of file diff --git a/src/Helpers/AutoLoader.php b/src/Helpers/AutoLoader.php new file mode 100644 index 0000000..841fd6a --- /dev/null +++ b/src/Helpers/AutoLoader.php @@ -0,0 +1,38 @@ +routeUrl = $routeUrl; + $this->routeName = $routeName; + $this->routeController = $routeController; + $this->routeAction = $routeAction; + $this->routeMethods = $routeMethods; + } + +} \ No newline at end of file diff --git a/src/Http/Router.php b/src/Http/Router.php new file mode 100644 index 0000000..6dff479 --- /dev/null +++ b/src/Http/Router.php @@ -0,0 +1,158 @@ +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 { + + foreach( self::$routes as $route ){ + /* + if( preg_match( self::getRegexRoute( $route), self::$clientRouteString, $matches ) ){ + var_dump( $matches ); + } + */ + /* + if( $route->routeUrl === self::$clientRouteString ){ + return $route; + } + */ + } + + return false; + + } + + private static function getRegexRoute( Route $route ): string { + $routeUrl = $route->routeUrl; + $routeUrl = str_replace( "{int}", "([0-9]+)", $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(); + } + +} \ No newline at end of file diff --git a/src/Kernel.php b/src/Kernel.php new file mode 100644 index 0000000..163d0cb --- /dev/null +++ b/src/Kernel.php @@ -0,0 +1,93 @@ + [ 'cle" → valeur ] ] + * + * @var array + */ + public private(set) static array $configs = []; + + /** + * Instance actuelle de l'application. + * @var Kernel|null + */ + private static ?self $instance = null; + + /** + * Méthode qui permet de démarrer le site. + * @return self + */ + public static function start(): self { + self::$instance = new self(); + self::$instance->init(); + return self::$instance; + } + + /** + * Permet d'obtenir l'instance actuelle du site. + * @return self + */ + public static function getInstance(): self { + return self::$instance; + } + + /** + * Constructeur. + */ + public function __construct() { + } + + /** + * Permet de préparer le démarrage du site. + * Lancé automatiquement par start(). + * + * @return void + * @see self::start() + */ + public function init(): void { + $this->buildAutoloader(); + $this->loadConfig(); + + 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'); + } catch( ConfigFailedLoadingException $e ){ + die( $e->getMessage() ); + } + } + +} \ No newline at end of file