ugly : this branch will be delete
continuous-integration/drone/push Build is passing Details

issue_021_Auth
David D'ALMEIDA 1 year ago
parent 7c79d2656a
commit c780be4799

@ -4,11 +4,16 @@
"psr-4": { "psr-4": {
"Hearttrack\\": "src/", "Hearttrack\\": "src/",
"App\\": "src/app", "App\\": "src/app",
"Enums\\": "src/app/enums",
"Data\\": "src/data", "Data\\": "src/data",
"Model\\": "src/data/model", "Model\\": "src/data/model",
"Repository\\": "src/data/model/repository", "Repository\\": "src/data/model/repository",
"Manager\\": "src/data/model/manager", "Manager\\": "src/data/model/manager",
"Network\\": "src/data/core/network", "Network\\": "src/data/core/network",
"Database\\": "src/data/core/database",
"Database\\Gateway\\": "src/data/core/database/gateway",
"Database\\Mapper\\": "src/data/core/database/mapper",
"Database\\Entity\\": "src/data/core/database/entity",
"Console\\": "src/console", "Console\\": "src/console",
"Stub\\": [ "Stub\\": [
"src/data/stub", "src/data/stub",

@ -1,30 +1,22 @@
<?php <?php
require_once __DIR__ . '/../vendor/autoload.php'; require_once __DIR__ . '/../vendor/autoload.php';
require_once __DIR__ . '/../config/config.php'; require_once __DIR__ . '/../config/config.php';
// turn the if in obj mode use App\AppCreator;
// if (APP_ENV === 'console') { use App\Router\Middleware\LoggingMiddleware;
// require_once __DIR__ . '/../src/console/Console.php'; use App\Router\Request\RequestFactory;
// } use Controllers\ArgumentControllerResolver;
// elseif (APP_ENV === 'development') { use Controllers\IArgumentResolver;
// on pourait aussi gérer le port sois ici comme dans express sois comme dans un fichier de config json... $appFactory = new AppCreator();
$appFactory = new AppCreator(); $appFactory->registerService(IArgumentResolver::class,ArgumentControllerResolver::class);
// builder.Services.AddScoped<AuthMiddlewareFliter>(); // $appFactory->registerService('twig',);
$app = $appFactory->registerService('','');
$appFactory.errorProvider(class:: or port)
// connexion string // // Connexion à la base de données
// $databaseContext = DatabaseContext::getInstance();
$appFactory->AddControllers();
$app = $appFactory->create();
$app->use(new LoggingMiddleware());
// $app->addHttpClient(HttpClient::class);
// je veux pas faire sa pour load les controller avec les anotation
$app->mapControllers();
// var connectionString = builder.Configuration.GetConnectionString("LolDatabase"); $app->run(RequestFactory::createFromGlobals());
// builder.Services.AddDbContext<LolDbContext>(options =>
// options.UseSqlite(connectionString), ServiceLifetime.Singleton);
$app->use(new LoggingMiddleware());
$app = $appFactory->create();
$app.addHttpClient(HttpClient::class)
// je veux pas faire sa pour load les controller avec les anotation
$app->RegisterControllers();
$app->
$app->run();
}

@ -1,4 +1,13 @@
<? <?
namespace App;
use Controllers\BaseController;
use App\Router\Request\HttpRequest;
use App\Router\Middleware\IHttpMiddleware;
use App\Router\Route;
use App\Router\Router;
use App\Router\Session;
// should make the session start // should make the session start
class App { class App {
@ -7,7 +16,10 @@ class App {
private IHttpMiddleware $middlewarePipeline; private IHttpMiddleware $middlewarePipeline;
private DiContainer $container; private Container $container;
private Router $router;
private array $controllers = [];
public function __construct($appName, $version, $diContainer) { public function __construct($appName, $version, $diContainer) {
$this->appName = $appName; $this->appName = $appName;
@ -35,7 +47,8 @@ class App {
return $this->version; return $this->version;
} }
public function run() { public function run(HttpRequest $request) {
Session::getInstance();
echo "Running {$this->appName} version {$this->version}\n"; echo "Running {$this->appName} version {$this->version}\n";
} }
@ -80,6 +93,39 @@ class App {
// return $middlewareClasses; // return $middlewareClasses;
// } // }
public function mapControllers(): void
{
$classes = $this->container->getAllRegisteredClassNames();
foreach ($classes as $class) {
if ($this->isController($class)) {
$this->mapControllerRoutes($class);
}
}
}
private function mapControllerRoutes(string $controllerClass): void
{
$reflectionClass = new \ReflectionClass($controllerClass);
$attributes = $reflectionClass->getAttributes(Route::class);
$prefix = '';
if(!empty($attributes)){
$prefix = $attributes[0]->newInstance()->getPath();
}
foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
foreach ($method->getAttributes(Route::class) as $attribute) {
$route = $attribute->newInstance();
$this->router->add($route->method,$prefix . $route->path, [$controllerClass, $method->getName()]);
}
}
}
private function isController(string $class): bool
{
$reflectionClass = new \ReflectionClass($class);
return $reflectionClass->isSubclassOf(BaseController::class);
}
} }
?> ?>

@ -1,12 +1,63 @@
<?php <?php
namespace App;
use Controllers\BaseController;
class AppCreator
{
private Container $container;
class AppCreator { private array $services = [];
public function __construct() {
public function __construct()
{
$this->container = new Container;
} }
public function registerService(string $serviceId, callable|string $service): self
{
$this->container->set($serviceId, $service);
$this->services[] = $serviceId;
return $this;
}
public function create()
{
if (APP_ENV === 'console') {
require_once __DIR__ . '/../src/console/Console.php';
return;
} elseif (APP_ENV === 'development') {
$app = new App("HeartTrack", 1, $this->container);
return $app;
}
}
function AddControllers($namespacePrefix = 'Controllers', $pathToControllers = __DIR__ . 'controller'): self
{
$controllerFiles = glob($pathToControllers . '/*.php');
foreach ($controllerFiles as $file) {
// Get class name from file name
$class = basename($file, '.php');
$fullClassName = $namespacePrefix . '\\' . $class;
if (!class_exists($fullClassName)) {
continue;
}
// Use reflection to check if class extends BaseController
$reflectionClass = new \ReflectionClass($fullClassName);
if ($reflectionClass->isSubclassOf(BaseController::class)) {
// Register in DI container
$this->container->set($fullClassName, function () use ($fullClassName) {
return new $fullClassName();
});
}
}
return $this;
}
} }

@ -0,0 +1,100 @@
<?php
namespace App;
use Shared\Exception\ContainerException;
use Shared\Exception\NotFoundException;
use Psr\Container\ContainerInterface;
class Container implements ContainerInterface
{
private array $entries = [];
public function get(string $id)
{
if ($this->has($id)) {
$entry = $this->entries[$id];
if (is_callable($entry)) {
return $entry($this);
}
$id = $entry;
}
return $this->resolve($id);
}
public function has(string $id): bool
{
return isset($this->entries[$id]);
}
public function set(string $id, callable|string $concrete): void
{
$this->entries[$id] = $concrete;
}
public function resolve(string $id)
{
// 1. Inspect the class that we are trying to get from the container
try {
$reflectionClass = new \ReflectionClass($id);
} catch(\ReflectionException $e) {
throw new NotFoundException($e->getMessage(), $e->getCode(), $e);
}
if (! $reflectionClass->isInstantiable()) {
throw new ContainerException('Class "' . $id . '" is not instantiable');
}
// 2. Inspect the constructor of the class
$constructor = $reflectionClass->getConstructor();
if (! $constructor) {
return new $id;
}
// 3. Inspect the constructor parameters (dependencies)
$parameters = $constructor->getParameters();
if (! $parameters) {
return new $id;
}
// 4. If the constructor parameter is a class then try to resolve that class using the container
$dependencies = array_map(
function (\ReflectionParameter $param) use ($id) {
$name = $param->getName();
$type = $param->getType();
if (! $type) {
throw new ContainerException(
'Failed to resolve class "' . $id . '" because param "' . $name . '" is missing a type hint'
);
}
if ($type instanceof \ReflectionUnionType) {
throw new ContainerException(
'Failed to resolve class "' . $id . '" because of union type for param "' . $name . '"'
);
}
if ($type instanceof \ReflectionNamedType && ! $type->isBuiltin()) {
return $this->get($type->getName());
}
throw new ContainerException(
'Failed to resolve class "' . $id . '" because invalid param "' . $name . '"'
);
},
$parameters
);
return $reflectionClass->newInstanceArgs($dependencies);
}
public function getAllRegisteredClassNames(): array
{
return array_keys($this->entries);
}
}

@ -34,7 +34,7 @@ class MyHttpClient {
$context = stream_context_create($options); $context = stream_context_create($options);
$response = file_get_contents($url, false, $context); $response = file_get_contents($url, false, $context);
// You can add error handling here if needed // error handling
return $response; return $response;
} }

@ -0,0 +1,78 @@
<?php
// getArguments() is also able to inject any Request attribute;
// if the argument has the same name as the corresponding attribute:
// the matching is done on the argument name or a type hint, the arguments order does not matter
namespace Controllers;
use App\Router\Request\IRequest;
/**
* Responsible for resolving the arguments passed to a controller action.
*/
class ArgumentControllerResolver implements IArgumentresolver{
/**
* Resolves and returns the arguments for a given controller callable.
*
* @param IRequest $request The HTTP request object.
* @param callable $controller The controller callable.
* @return array An array of resolved arguments.
* @throws \ReflectionException If the controller method does not exist.
* @throws \InvalidArgumentException If an argument cannot be resolved.
*/
public function getArguments(IRequest $request, callable $controller): array
{
try {
$reflectionMethod = new \ReflectionMethod($controller);
} catch (\ReflectionException $e) {
throw new \InvalidArgumentException("Controller method error: " . $e->getMessage());
}
$args = [];
foreach ($reflectionMethod->getParameters() as $param) {
if (IRequest::class === $param->getType()->getName() || is_subclass_of($param->getType()->getName(), IRequest::class)) {
$args[] = $request;
continue;
}
$name = $param->getName();
$value = $this->getFromRequest($name, $request);
if ($value === null && $param->isDefaultValueAvailable()) {
$value = $param->getDefaultValue();
} elseif ($value === null) {
throw new \InvalidArgumentException("Missing argument: $name");
}
$args[] = $value;
}
return $args;
}
/**
* Extracts a value from the request based on a key.
*
* @param string $key The key to look for in the request.
* @param IRequest $req The request object.
* @return mixed The value from the request or null if not found.
*/
public function getFromRequest(string $key, IRequest $req): mixed
{
$body = $req->getBody();
if (array_key_exists($key, $body)) {
return $body[$key];
}
$queryParams = $req->getQueryParameters();
if (array_key_exists($key, $queryParams)) {
return $queryParams[$key];
}
$requestParams = $req->getRequestParameters();
if (array_key_exists($key, $requestParams)) {
return $requestParams[$key];
}
return null;
}
}

@ -3,10 +3,12 @@ namespace App\Controllers;
class AthleteController extends BaseController class AthleteController extends BaseController
{ {
protected $authService;
public function __construct() public function __construct()
{ {
// Initialize UserController specific configurations or dependencies // Initialize UserController specific configurations or dependencies
} }
public function index() public function index()
{ {

@ -0,0 +1,86 @@
<?php
namespace Controleur;
use App\Attributes\Route;
use App\Container;
use App\Router\Request\IRequest;
use App\Router\Responce\Response;
use Shared\Validation;
// use App\Enums\HttpMethod;
class CoachControleur extends BaseController
{
private $DataManager;
public function __construct(Container $container)
{
global $twig;
session_start();
$this->DataManager = $container->get('DBDATAMANAGER');
}
#[Route(path: '/', name: 'test', methods:['GET'])] // 8
public function index(): Response{
return new Response( $this->Reinit());
}
#[Route(path: '/addAthl', name: 'test', methods:['Post'])] // 8
public function addAthlthe(IRequest $req,string $userName){
if(Validation::val_string($userName)){
$resp = $this->$DataManager->coachManager->addAthlthe($userName);
if($resp){
return new Response($container->get('twig')->render('listAthlet.html.twig',$this->$DataManager->coachManager->getCurrentUser()->listAthlete));
}
}
}
public function Reinit()
{
global $twig;
$dVue = [
'nom' => '',
'age' => 0,
'email'=> '',
];
return $twig->render('vuephp1.html.twig', [
'dVue' => $dVue
]);
}
#[Route(path: '/hello', methods:['GET'], name: 'hello')]
public function hello(): Response{
return new Response('Hello');
}
#[Route(path: '/hi', methods:['GET'],name: 'hi')]
public function hi(string $name,IRequest $req): Response{
return new Response($name.$req->getMethod());
}
public function ValidationFormulaire(array $dVueEreur)
{
global $twig; // nécessaire pour utiliser variables globales
//si exception, ca remonte !!!
$nom = $_POST['txtNom']; // txtNom = nom du champ texte dans le formulaire
$age = $_POST['txtAge'];
$email = $_POST['email'];
\config\Validation::val_form($nom, $age,$email, $dVueEreur);
$model = new \modeles\Simplemodel();
$data = $model->get_data();
$dVue = [
'nom' => $nom,
'email' => $email,
'age' => $age,
'data' => $data,
];
echo $twig->render('vuephp1.html.twig', ['dVue' => $dVue, 'dVueEreur' => $dVueEreur]);
}
}//fin class

@ -1,44 +1,149 @@
<?php <?php
use App\Container;
use App\Router\Request\IRequest;
use App\Router\Router;
use Controllers\IArgumentResolver;
use Shared\Exception\NotImplementedException;
// App etre sur que la persone a le droit defaire // App etre sur que la persone a le droit defaire
class FrontController { class FrontController {
private $router; private $router;
public function __construct(Router $router) { private $container;
public function __construct(Router $router, Container $container) {
$this->router = $router; $this->router = $router;
$this->container = $container;
} }
public function dispatch(IRequest $request) { public function dispatch(IRequest $request) {
$match = $this->router->match($request); try {
$match = $this->router->match($request);
if ($match) {
$controllerName = $match['controller']; if (!is_null($match)) {
$actionName = $match['action']; $controller = $this->getController($match['target']);
$request->addToBody($match['params']);
// Utilisez l'injection de dépendances pour créer le contrôleur
$controller = $this->createController($controllerName);
if (!is_callable($controller)){
if ($controller) { // body to key values maybe is better
// Appeler l'action correspondante // $request = array_reduce($params, function ($request, $key) use ($params) {
$controller->$actionName(); // return $request->withAttribute($key, $params[$key]);
// }, $request);
// if (is_callable($action)) {
// return $action();
// }
// if (is_array($action)) {
// [$className, $method] = $action;
// if (class_exists($className) && method_exists($className, $method)) {
// $class = new $className();
// return call_user_func_array([$class, $method], []);
// }
// }
throw new NotImplementedException('Handle when route targer is not a callable not handle');
}
$argumentResolver = $this->container->get(IArgumentResolver::class);
$arguments = $argumentResolver->getArguments($request, $controller);
$response = call_user_func_array($controller, $arguments);
// should handle responce proprely like if its a HTML, STING, JSON,....
return $response;
} else { } else {
// Gérer l'erreur, le contrôleur n'existe pas return $this->handleError(404, "Page not found");
$this->handleError();
} }
} else { } catch (NotFoundHttpException $e) {
// Gérer l'erreur, aucune route correspondante return $this->handleError(404, $e->getMessage());
$this->handleError(); } catch (\Exception $e) {
return $this->handleError(500, "Internal Server Error: " . $e->getMessage());
} }
} }
private function createController($controllerName) { // public function dispatch(IRequest $request) {
// // si sa match sa me retourn une route
// $match = $this->router->match($request);
// // si j'ai bien récupe une route
// if (!is_null($match)) {
// // $controllerName = $match['controller'];
// // $callable = $match['target'];
// // $request->addAttributes($match['params']);
// // Utilisez l'injection de dépendances pour avoir le contrôleur - en gros par rapport à la chaine de carractère la on demmande est ce que on peut avoir une instantce d'un objet(la callable)
// // je résous les param qui sont dans la request pa rapport à l'appel de fonction(le callable)
// $params = $match->getParams();
// $request = array_reduce($params, function ($request, $key) use ($params) {
// return $request->withAttribute($key, $params[$key]);
// }, $request);
// // on va vérifié si dans la request j'ai les finfo nécéssaire pour le callable(controller)
// $arguments = $this->argumentResolver->getArguments($request, $controller);
// $this->dispatcher->dispatch(new ArgumentEvent($request, $controller, $arguments), 'kernel.arguments');
// $response = call_user_func_array($controller, $arguments);
// // if (is_callable($route->getCallable())){
// // call_user_func_array($controller, $request);
// // }
// // can i a dd a logic to have defined route like new Route('', function()) => so without class
// // so il i can check
// // public function resolve(string $requestUri, string $requestMethod): mixed
// // {
// // $path = explode('?', $requestUri)[0];
// // $action = $this->routes[$requestMethod][$path] ?? null;
// // if (is_callable($action)) {
// // return $action();
// // }
// // if (is_array($action)) {
// // [$className, $method] = $action;
// // if (class_exists($className) && method_exists($className, $method)) {
// // $class = new $className();
// // return call_user_func_array([$class, $method], []);
// // }
// // }
// // throw new RouteNotFoundException();
// // }
// if ($controller && is_callable(array($controller, $route->getParams()))) {
// // Appeler l'action correspondante
// // $controller->$actionName();
// // should call DI container or Arguments Resolver ($arguments = $this->argumentResolver->getArguments($request, $controller);)
// // $response = call_user_func_array($controller, $arguments);
// // to get correct argument
// // ORR like graphicsArt set it un Request
// // So je mets dans la request en tant que attribu ce que à besoin ma function et du coup dans le controller je fait un $request->getAttribute('name')
// // a peu près comme je fais en js const { email, password } = req.body;
// // ou j'utilise un Argument resolver qui va le le faire
// call_user_func_array($controller, $request);
// } else {
// // Gérer l'erreur, le contrôleur n'existe pas
// $this->handleError();
// }
// } else {
// // Gérer l'erreur, aucune route correspondante
// $this->handleError();
// }
// }
private function getController($controllerName) {
// Utilisez un conteneur d'injection de dépendances pour créer le contrôleur // Utilisez un conteneur d'injection de dépendances pour créer le contrôleur
return DependencyContainer::create($controllerName); return $this->container->get($controllerName);
} }
private function handleError() {// composant twig
header("HTTP/1.0 404 Not Found"); private function handleError($statusCode, $message) {// composant twig
echo "Page not found"; // http_response_code($statusCode);
$response = new Response($statusCode, $message);
echo $message;
// status,..., body
// return new Responce(404,[notfond],erreur.twig)
} }
} }
?> ?>

@ -0,0 +1,26 @@
<?php
// // controller arguments are guessed by using this Interface getArguments()
// // introspects the controller signature to determine which arguments to pass to it by using the native PHP reflection.
// namespace Controllers;
// interface IArgumentResolver {
// public function getArguments(Object Source, callable);
// }
namespace Controllers;
use App\Router\Request\IRequest;
/**
* Interface for classes that resolve arguments for controller methods.
*/
interface IArgumentResolver
{
/**
* Resolves the arguments for a controller method based on the given request.
*
* @param IRequest $request The request object.
* @param callable $controller The controller callable.
* @return array An array of arguments resolved for the controller method.
*/
public function getArguments(IRequest $request, callable $controller): array;
}

@ -0,0 +1,28 @@
<?php
declare(strict_types = 1);
namespace App\Enums;
enum HttpMethod: string {
case Get = 'GET';
case Post = 'POST';
case Put = 'PUT';
case Head = 'HEAD';
case Patch = "PATCH";
case Delete = 'Delete';
public static function values()
{
return [
self::Get,
self::Post,
self::Put,
self::Delete,
self::Head,
self::Patch,
// Add more HTTP methods as needed
];
}
}

@ -1,22 +1,51 @@
<?php <?php
namespace App\Router;
// // map users details page using controller#action string
// $router->map( 'GET', '/users/[i:id]/', 'UserController#showDetails' );
// // map contact form handler using function name string
// $router->map( 'POST', '/contact/', 'handleContactForm' );
class Route class Route
{ {
private string $name;
private string $name; private string $path;
private array $parrams; private string $method; // callable|array
private $callable;
private $callable; public function __construct(string $path, callable $callable, array $params = null,string $name = null)
{
$this->path = $path;
$this->callable = $callable;
$this->name = $name;
}
public function __construct(array $params, callable $callable, string $name = null)
{
$this->path = $params;
$this->callable = $callable;
$this->name = $name;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(?string $name): void
{
$this->name = $name;
}
public function getCallable()
{
return $this->callable;
}
public function getPath(): string
{
return $this->path;
}
public function setCallable(callable $callable)
{
$this->callable = $callable;
}
} }

@ -27,49 +27,58 @@ Envoi de la réponse : Il envoie finalement la réponse HTTP au client en utilis
<?php <?php
namespace App\Router;
use App\Router\Request\IRequest;
use App\Enums\HttpMethod;
// Just a url matcher // Just a url matcher
class Router { class Router {
private string $path; private string $path;
// routes collection // routes collection
private AltoRouter $routes; private \AltoRouter $routes;
// public static $verbs = ['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'];
public function __construct(string $path = "/PHP/project/index.php") { public function __construct(string $path = "/PHP/project/index.php") {
$this->path = $path; $this->path = $path;
$this->routes = new AltoRouter($this->$path); $this->routes = new \AltoRouter($this->$path);
}
// add a new Route to Collection
public function add(string $method,Route $route) {
if (!in_array($method, HttpMethod::values(), true)){
throw new \InvalidArgumentException("Method not suported");
}
$this->routes->map($method, $route->getPath(), $route->getCallable(), $route->getName());
} }
public function add(Route $route, $name) {} // extrait les paramètres d'URL de l'URL demandée
// extrait également les paramètres d'URL de l'URL demandée
public function extractParams(string $path) {} public function extractParams(string $path) {}
public function get(string $path, callable $callable, $name) { public function get(string $path, callable $callable, $name) {
$this->router->map('GET', $path, $callable, $name); $this->routes->map('GET', $path, $callable, $name);
} }
public function post(string $path, callable $callable, $name) { public function post(string $path, callable $callable, $name) {
$this->router->map('POST', $path, $callable, $name); $this->routes->map('POST', $path, $callable, $name);
} }
public function put(string $path, callable $callable, $name) { public function put(string $path, callable $callable, $name) {
$this->router->map('PUT', $path, $callable, $name); $this->routes->map('PUT', $path, $callable, $name);
} }
public function match (IRequest $request): ?Route { /// check if the request can be process
public function match (IRequest $request): ?array {
$result = $this->routes->match($request->getRequestUri(), $request->getMethod()); $result = $this->routes->match($request->getRequestUri(), $request->getMethod());
if ($result) { if ($result) {
return new Route($result['params'],$result['target'],$result['name']) ; // not Route
// retunr $result
return $result;
} }
return null; return null;
} }
public function
} }

@ -0,0 +1,121 @@
<?php
/*
Use the static method getInstance to get the object.
*/
namespace App\Router;
class Session
{
const SESSION_STARTED = TRUE;
const SESSION_NOT_STARTED = FALSE;
// The state of the session
private $sessionState = self::SESSION_NOT_STARTED;
// THE only instance of the class
private static $instance;
private function __construct() {}
/**
* Returns THE instance of 'Session'.
* The session is automatically initialized if it wasn't.
*
* @return object
**/
public static function getInstance()
{
if ( !isset(self::$instance))
{
self::$instance = new self;
}
self::$instance->startSession();
return self::$instance;
}
/**
* (Re)starts the session.
*
* @return bool TRUE if the session has been initialized, else FALSE.
**/
private function startSession()
{
if ( $this->sessionState == self::SESSION_NOT_STARTED )
{
$this->sessionState = session_start();
}
return $this->sessionState;
}
/**
* Stores datas in the session.
* Example: $instance->foo = 'bar';
*
* @param name Name of the datas.
* @param value Your datas.
* @return void
**/
public function __set( $name , $value )
{
$_SESSION[$name] = $value;
}
/**
* Gets datas from the session.
* Example: echo $instance->foo;
*
* @param name Name of the datas to get.
* @return mixed Datas stored in session.
**/
public function __get( string $name )
{
if ( isset($_SESSION[$name]))
{
return $_SESSION[$name];
}
}
public function __isset( $name )
{
return isset($_SESSION[$name]);
}
public function __unset( $name )
{
unset( $_SESSION[$name] );
}
/**
* Destroys the current session.
*
* @return bool TRUE is session has been deleted, else FALSE.
**/
public function destroy()
{
if ( $this->sessionState == self::SESSION_STARTED )
{
$this->sessionState = !session_destroy();
unset( $_SESSION );
return !$this->sessionState;
}
return FALSE;
}
}

@ -0,0 +1,18 @@
<?php
declare(strict_types = 1);
namespace App\Attributes;
use App\Enums\HttpMethod;
#[\Attribute(Attribute::TARGET_METHOD|Attribute::IS_REPEATABLE)]
class Get extends Route
{
public function __construct(
private string|array $path,
private ?string $name = null)
{
parent::__construct($path,$name,HttpMethod::Post);
}
}

@ -0,0 +1,33 @@
<?php
namespace App\Attributes;
use App\Enums\HttpMethod;
#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_CLASS)]
class Route
{
public function __construct(
private string|array $path = null,
private ?string $name = null,
private array|HttpMethod $methods = HttpMethod::Get,
)
{
}
public function getPath(): array| string{
return $this->path;
}
public function getName(): ?string{
return $this->name;
}
public function getMethods(): array | HttpMethod
{
return $this->methods;
}
}

@ -1,4 +1,7 @@
<?php <?php
namespace App\Router\Middleware;
use App\Router\Request\IRequest;
use Shared\Validation\Validator;
class RequestValidationMiddleware extends Middleware { class RequestValidationMiddleware extends Middleware {
private $validator; private $validator;
@ -27,10 +30,10 @@ class RequestValidationMiddleware extends Middleware {
} }
$validationRules = [ // $validationRules = [
'email' => [ // 'email' => [
['callback' => Validator::required(), 'message' => 'Email is required.'], // ['callback' => Validator::required(), 'message' => 'Email is required.'],
['callback' => Validator::email(), 'message' => 'Email must be a valid email address.'] // ['callback' => Validator::email(), 'message' => 'Email must be a valid email address.']
], // ],
// Add more rules as needed // // Add more rules as needed
]; // ];

@ -1,4 +1,8 @@
<?php <?php
namespace App\Router\Middleware;
use App\Router\Request\IRequest;
interface IHttpMiddleware { interface IHttpMiddleware {
public function handle(IRequest $request, callable $next); public function handle(IRequest $request, callable $next);

@ -1,4 +1,8 @@
<?php <?php
namespace App\Router\Middleware;
use App\Router\Request\IRequest;
class LoggingMiddleware extends Middleware { class LoggingMiddleware extends Middleware {
public function handle(IRequest $request, callable $next) { public function handle(IRequest $request, callable $next) {
// Logique de journalisation // Logique de journalisation

@ -3,6 +3,10 @@
// Dans l'app, les requêtes HTTP traversent une série de couches de traitement appelées "middleware". // Dans l'app, les requêtes HTTP traversent une série de couches de traitement appelées "middleware".
// Chaque middleware peut accepter ou refuser la requête. Une fois qu'une requête // Chaque middleware peut accepter ou refuser la requête. Une fois qu'une requête
// passe avec succès à travers tous les middleware, elle est finalement traitée par l'application elle-même. // passe avec succès à travers tous les middleware, elle est finalement traitée par l'application elle-même.
namespace App\Router\Middleware;
use App\Router\Request\IRequest;
abstract class Middleware implements IHttpMiddleware { abstract class Middleware implements IHttpMiddleware {
protected $next; protected $next;

@ -1,4 +1,5 @@
<?php <?php
namespace App\Router\Request;
interface ContentStrategy { interface ContentStrategy {
public function getContent(): array; public function getContent(): array;

@ -1,4 +1,6 @@
<?php <?php
namespace App\Router\Request;
// should maybe change this // should maybe change this
class ContentStrategyFactory { class ContentStrategyFactory {
private static $strategyMap = [ private static $strategyMap = [

@ -1,4 +1,5 @@
<?php <?php
namespace App\Router\Request;
class FormContentStrategy implements ContentStrategy { class FormContentStrategy implements ContentStrategy {

@ -1,4 +1,5 @@
<?php <?php
namespace App\Router\Request;
class HttpRequest implements IRequest { class HttpRequest implements IRequest {
private $queryParameters; private $queryParameters;
@ -7,17 +8,21 @@ class HttpRequest implements IRequest {
private $requestUri; private $requestUri;
private $headers; private $headers;
private array $body;
public function __construct( public function __construct(
array $query, array $query,
array $server, array $server,
array $headers, array $headers,
ContentStrategy $contentStrategy ContentStrategy $contentStrategy,
array $body
) { ) {
$this->queryParameters = $query; $this->queryParameters = $query;
$this->requestUri = $server['REQUEST_URI'] ?? ''; $this->requestUri = $server['REQUEST_URI'] ?? '';
$this->method = strtoupper($server['REQUEST_METHOD'] ?? 'GET'); $this->method = strtoupper($server['REQUEST_METHOD'] ?? 'GET');
$this->headers = $headers; $this->headers = $headers;
$this->requestParameters = $contentStrategy->getContent(); $this->requestParameters = $contentStrategy->getContent();
$this->body = $body;
} }
public function getQueryParameters(): array { public function getQueryParameters(): array {
@ -39,5 +44,12 @@ class HttpRequest implements IRequest {
public function getHeaders(): array { public function getHeaders(): array {
return $this->headers; return $this->headers;
} }
public function getBody(): array{
return $this->body;
}
public function addToBody(string|array $attributes){
$this->body[] = $attributes;
}
} }

@ -1,9 +1,14 @@
<?php <?php
namespace App\Router\Request;
interface IRequest interface IRequest
{ {
public function getRequestUri(); public function getRequestUri();
public function getBody();
public function addToBody(string|array $attributes);
public function getHeaders(); public function getHeaders();
public function getMethod(); public function getMethod();
public function getQueryParameters(): array; public function getQueryParameters(): array;

@ -1,4 +1,6 @@
<?php <?php
namespace App\Router\Request;
class JsonContentStrategy implements ContentStrategy { class JsonContentStrategy implements ContentStrategy {
public function getContent(): array { public function getContent(): array {
$rawContent = file_get_contents('php://input'); $rawContent = file_get_contents('php://input');

@ -1,4 +1,6 @@
<?php <?php
namespace App\Router\Request;
class RequestFactory { class RequestFactory {
public static function createFromGlobals(): IRequest { public static function createFromGlobals(): IRequest {

@ -1,21 +1,13 @@
<?php <?php
declare(strict_types=1);
namespace Silex\Security;
use Silex\Gateway\UserGateway;
use Silex\Model\User;
class Security class Security
{ {
const tokenSession = 'tokenSession'; const tokenSession = 'tokenSession';
private array $session; private array $session;
private UserGateway $userGateway; private UserRepository $userGateway;
private ?User $user = null; private ?User $user = null;
public function __construct(UserGateway $userGateway, array &$session) public function __construct(UserRepository $userGateway, array &$session)
{ {
$this->userGateway = $userGateway; $this->userGateway = $userGateway;
$this->session = &$session; $this->session = &$session;

@ -0,0 +1,14 @@
<?php
class Connection extends PDO {
private $stmt;
public function __construct(string $dsn) {
// $dsn = "pgsql:host=$this->host;port=$this->port;dbname=$this->database;user=$this->username;password=$this->password";
parent::__construct($dsn);
echo "Successfully connected to the database";
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
}
?>

@ -0,0 +1,50 @@
<?php
class DatabaseQueryExecutor {
private $connection;
// should be this IDatabaseConnection
public function __construct(Connection $dbConnection) {
$this->connection = $dbConnection;
}
public function executeQuery(string $query, array $parameters = []): bool {
$stmt = $this->connection->prepare($query);
foreach ($parameters as $name => $value) {
$stmt->bindValue($name, $value[0], $value[1]);
}
return $stmt->execute();
}
public function executeTransaction(callable $transaction): bool {
try {
$this->connection->beginTransaction();
$transaction($this);
$this->connection->commit();
return true;
} catch (PDOException $e) {
$this->connection->rollBack();
throw new Exception('Database transaction failed: ' . $e->getMessage());
}
}
public function fetchAll(string $query, array $parameters = []): array {
$stmt = $this->connection->prepare($query);
foreach ($parameters as $name => $value) {
$stmt->bindValue($name, $value[0], $value[1]);
}
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
public function fetchOne(string $query, array $parameters = []): ?array {
$stmt = $this->connection->prepare($query);
foreach ($parameters as $name => $value) {
$stmt->bindValue($name, $value[0], $value[1]);
}
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
return $result ?: null;
}
}
?>

@ -0,0 +1,35 @@
<?php
namespace Database;
abstract class DbContext {
protected $databaseConnection;
public function __construct() {
$this->onConfiguring();
$this->onModelCreating();
}
protected abstract function onConfiguring();
protected abstract function onModelCreating();
protected function isConfigured() {
return $this->databaseConnection !== null;
}
// getInstantce
protected function seedDatabase($sqlFilePath) {
if (!$this->isConfigured()) {
if (file_exists($sqlFilePath)) {
try {
$sql = file_get_contents($sqlFilePath);
$this->databaseConnection->exec($sql);
echo "Database seeded successfully.";
} catch (\PDOException $e) {
echo "Error seeding database: " . $e->getMessage();
}
} else {
echo "SQL file not found: $sqlFilePath";
}
}
}
}

@ -0,0 +1,11 @@
<?php
namespace Database;
use Manager\DataManager;
class DbManager extends DataManager{
public HeartDbContext $context;
public function __construct(){
$this->userMgr = new UserRepository($this);
}
}

@ -0,0 +1,49 @@
<?php
namespace Database;
use Database\Gateway\UserGateway;
class HeartDbContext extends DbContext {
public $userGateWay;
private $seed = true;
// ... autres gateways pour chaque entité
public function __construct() {
// Initialisation de chaque gateway avec la connexion à la base de données
$databaseConnection = DatabaseConnection::getInstance("");
$this->userGateWay = new UserGateway($databaseConnection);
}
public function onConfiguring() {
if (!$this->isConfigured()) {
echo "!IsConfigured...\n";
try {
$options = $this->getConnectionOptions();
$this->databaseConnection = DatabaseConnection::getInstance($options['dsn'], $options['username'], $options['password']);
echo 'Successfully connected to the database';
} catch (PDOException $e) {
echo 'Error connecting to the database: ' . $e->getMessage();
}
}
}
protected function getConnectionOptions(): array {
// 'dbname' => 'mydb',
// 'user' => 'user',
// 'password' => 'secret',
// 'host' => 'localhost',
// 'driver' => 'pdo_mysql',
return [
'dsn' => 'mysql:host=localhost;dbname=your_database',
'username' => 'your_username',
'password' => 'your_password'
];
}
public function onModelCreating() {
if (!$this->isConfigured() && $this->seed) {
$this->seedDatabase(__DIR__ . '/../../../config/heart.sql');
}
}
}

@ -0,0 +1,4 @@
<?
interface IDatabaseConnection {
public function connect();
}

@ -0,0 +1,76 @@
<?php
namespace Database\Mapper;
use Database\Entity;
use Model\User;
class UserMapper {
/**
* Convert a User entity to a UserDTO.
*
* @param User $user
* @return UserEntity
*/
public static function toEntity(User $user): UserEntity {
return new UserEntity(
$user->getId(),
$user->getNom(),
$user->getPrenom(),
$user->getEmail(),
$user->getSexe(),
$user->getTaille(),
$user->getPoids(),
$user->getDateNaissance(),
$user->getRole()
);
}
/**
* Convert a UserEntity to a User entity.
*
* @param UserEntity $entity
* @return User
*/
public static function toModel(UserEntity $entity): User {
$user = new User(
$entity->id,
$entity->nom,
$entity->prenom,
$entity->email,
// Handle password appropriately
'defaultPassword', // This is a placeholder. Handle with care.
$entity->sexe,
$entity->taille,
$entity->poids,
$entity->dateNaissance,
$entity->role
);
return $user;
}
/**
* Map SQL result to UserEntity object.
*
* @param array $row
* @return UserEntity
*/
public static function fromSql(array $row): UserEntity {
$dateNaissance = new \DateTime($row['date_naissance']); // Adjust the key as per your database column name
$role = new Role(/* parameters based on your Role class constructor */);
return new UserEntity(
$row['id'],
$row['nom'],
$row['prenom'],
$row['email'],
$row['mot_de_passe'], // Make sure this is handled securely
$row['sexe'],
$row['taille'],
$row['poids'],
$dateNaissance,
$role
);
}
}

@ -0,0 +1,15 @@
<?php
namespace Database\Entity;
class AthleteEntity {
public function __construct(
public ?int $id = null,
public ?string $nom = null,
public ?string $prenom = null,
public ?string $email = null,
public ?string $sexe = null,
public ?float $taille = null,
public ?float $poids = null,
public ?\DateTime $dateNaissance = null,
private ?int $coach_id = null
) {}
}

@ -0,0 +1,60 @@
<?php
namespace Database\Gateway;
use Model\User;
use Repository\IUserRepository;
use DataMapper\UserMapper;
// changer car je suis censé provide une API simplifié genre un QuerryBuilder plus to que sa m'est bon on s'en fou
class UserGateway {
private DatabaseQueryExecutor $queryExecutor;
public function __construct(DatabaseQueryExecutor $queryExecutor) {
$this->queryExecutor = $queryExecutor;
}
public function getItemById(int $id): ?UserEntity {
$result = $this->queryExecutor->fetchOne("SELECT * FROM users WHERE id = :id", ['id' => [$id, PDO::PARAM_INT]]);
return $result ? UserMapper::fromSql($result) : null;
}
public function getItemByEmail(string $email): ?UserEntity {
$result = $this->queryExecutor->fetchOne("SELECT * FROM users WHERE email = :email", ['email' => [$email, PDO::PARAM_STR]]);
return $result ? $this->mapper->mapToUser($result) : null;
}
public function GetNbItems(): int {
$result = $this->queryExecutor->fetchOne("SELECT COUNT(*) as count FROM users");
return $result ? (int)$result['count'] : 0;
}
public function GetItems(int $index, int $count, ?string $orderingPropertyName = null, bool $descending = false): array {
$order = $descending ? 'DESC' : 'ASC';
$query = "SELECT * FROM users " . ($orderingPropertyName ? "ORDER BY $orderingPropertyName $order " : "") . "LIMIT :index, :count";
$parameters = ['index' => [$index, PDO::PARAM_INT], 'count' => [$count, PDO::PARAM_INT]];
$results = $this->queryExecutor->fetchAll($query, $parameters);
return array_map([$this->mapper, 'mapToUser'], $results);
}
public function GetItemsByName(string $substring, int $index, int $count, ?string $orderingPropertyName = null, bool $descending = false): array {
$order = $descending ? 'DESC' : 'ASC';
$query = "SELECT * FROM users WHERE CONCAT(first_name, ' ', last_name) LIKE :substring " . ($orderingPropertyName ? "ORDER BY $orderingPropertyName $order " : "") . "LIMIT :index, :count";
$parameters = ['substring' => ["%$substring%", PDO::PARAM_STR], 'index' => [$index, PDO::PARAM_INT], 'count' => [$count, PDO::PARAM_INT]];
$results = $this->queryExecutor->fetchAll($query, $parameters);
return array_map([$this->mapper, 'mapToUser'], $results);
}
public function UpdateItem(UserEntity $oldUser, UserEntity $newUser): void {
// Logique pour mettre à jour un utilisateur
// Utiliser $this->queryExecutor->executeQuery pour exécuter la requête de mise à jour
}
public function AddItem(UserEntity $user): void {
// Logique pour ajouter un nouvel utilisateur
// Utiliser $this->queryExecutor->executeQuery pour exécuter la requête d'insertion
}
public function DeleteItem(UserEntity $user): bool {
$success = $this->queryExecutor->executeQuery("DELETE FROM users WHERE id = :id", ['id' => [$user->getId(), PDO::PARAM_INT]]);
return $success;
}
}

@ -0,0 +1,66 @@
<?php
namespace Database;
use Model\User;
use Repository\IUserRepository;
use Database\DbContext;
class UserRepository implements IUserRepository {
private readonly DbManager $parent;
public function __construct(DbManager $dbContext) {
$this->parent = $dbContext;
}
public function getItemById(int $id): ?User {
throw new NotImplementedException();
}
public function GetItemByName(string $substring, int $index, int $count, ?string $orderingPropertyName = null, bool $descending = false){
throw new NotImplementedException();
}
public function getItemByEmail(string $email): ?User {
throw new NotImplementedException();
}
public function getNbItems(): int {
throw new NotImplementedException();
}
public function getItems(int $index, int $count, ?string $orderingPropertyName = null, bool $descending = false): array {
throw new NotImplementedException();
}
public function getItemsByName(string $substring, int $index, int $count, ?string $orderingPropertyName = null, bool $descending = false): array {
throw new NotImplementedException();
}
public function addItem(User $user): ?User {
// Add a new user to the database
$userEntity = $this->parent->context->userGateWay->addUser($user->toEntity());
$this->parent->dbContext->userGateWay->saveChanges();
return $userEntity->ToModel();
}
public function updateItem(User $oldUser, User $newUser): void {
throw new NotImplementedException();
}
public function deleteItem(User $user): bool {
// should use name and other things to equals
$usertoDelete = $this->parent->context->userGateWay->GetItemsByName($user->getNom());
// Where(c => c.Name == item.Name).First();
if ($usertoDelete != null)
{
$deleted = $this->dbContext->userGateWay->Remove($usertoDelete);
$this->parent->dbContext->saveChanges();
return true;
}
return false;
}
}
?>

@ -0,0 +1,8 @@
<?php
namespace Shared\Exception;
final class ContainerException extends \Exception
{
public $message = "Container runs wrong";
}

@ -0,0 +1,8 @@
<?php
namespace Shared\Exception;
final class NotFoundException extends \Exception
{
public $message = "Not found";
}
Loading…
Cancel
Save