Compare commits
8 Commits
master
...
issue_021_
Author | SHA1 | Date |
---|---|---|
|
c780be4799 | 1 year ago |
|
7c79d2656a | 1 year ago |
|
0e5e671423 | 1 year ago |
|
153418181e | 1 year ago |
|
585ef229f6 | 2 years ago |
|
b9239f490b | 2 years ago |
|
f217787afe | 2 years ago |
|
7709209b96 | 2 years ago |
After Width: | Height: | Size: 81 KiB |
@ -1,9 +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';
|
||||||
if (APP_ENV === 'console') {
|
use App\AppCreator;
|
||||||
require_once __DIR__ . '/../src/console/Console.php';
|
use App\Router\Middleware\LoggingMiddleware;
|
||||||
}
|
use App\Router\Request\RequestFactory;
|
||||||
elseif (APP_ENV === 'development') {
|
use Controllers\ArgumentControllerResolver;
|
||||||
require_once __DIR__ . 'index.html';
|
use Controllers\IArgumentResolver;
|
||||||
}
|
$appFactory = new AppCreator();
|
||||||
|
$appFactory->registerService(IArgumentResolver::class,ArgumentControllerResolver::class);
|
||||||
|
// $appFactory->registerService('twig',);
|
||||||
|
|
||||||
|
// // 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();
|
||||||
|
|
||||||
|
$app->run(RequestFactory::createFromGlobals());
|
||||||
|
@ -0,0 +1,131 @@
|
|||||||
|
<?
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
class App {
|
||||||
|
private $appName;
|
||||||
|
private $version;
|
||||||
|
|
||||||
|
private IHttpMiddleware $middlewarePipeline;
|
||||||
|
|
||||||
|
private Container $container;
|
||||||
|
|
||||||
|
private Router $router;
|
||||||
|
private array $controllers = [];
|
||||||
|
|
||||||
|
public function __construct($appName, $version, $diContainer) {
|
||||||
|
$this->appName = $appName;
|
||||||
|
$this->version = $version;
|
||||||
|
$this->$diContainer = $diContainer;
|
||||||
|
}
|
||||||
|
public function use(IHttpMiddleware $middleware) {
|
||||||
|
if ($this->middlewarePipeline === null) {
|
||||||
|
$this->middlewarePipeline = $middleware;
|
||||||
|
} else {
|
||||||
|
// Chain the new middleware to the end of the existing pipeline
|
||||||
|
$currentMiddleware = $this->middlewarePipeline;
|
||||||
|
while ($currentMiddleware->getNext() !== null) {
|
||||||
|
$currentMiddleware = $currentMiddleware->getNext();
|
||||||
|
}
|
||||||
|
$currentMiddleware->setNext($middleware);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAppName() {
|
||||||
|
return $this->appName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getVersion() {
|
||||||
|
return $this->version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function run(HttpRequest $request) {
|
||||||
|
Session::getInstance();
|
||||||
|
echo "Running {$this->appName} version {$this->version}\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// public function run(HttpRequest $request) {
|
||||||
|
// if ($this->middlewarePipeline === null) {
|
||||||
|
// // No middleware defined, return the request as-is
|
||||||
|
// return $request;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Exécutez le middleware en utilisant le pipeline
|
||||||
|
// return $this->middlewarePipeline->handle($request, function($request) {
|
||||||
|
// // Logique de gestion principale de la requête ici
|
||||||
|
// echo "Main Request Handling Logic.\n";
|
||||||
|
// return $request;
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// should not be hese responsibibilty add in DI
|
||||||
|
public function autoAddMiddlewares() {
|
||||||
|
$middlewareClasses = $this->findMiddlewareClasses();
|
||||||
|
|
||||||
|
foreach ($middlewareClasses as $middlewareClass) {
|
||||||
|
$this->use(new $middlewareClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Méthode pour rechercher automatiquement les classes de middleware en utilisant la réflexion
|
||||||
|
// private function findMiddlewareClasses() {
|
||||||
|
// $middlewareClasses = [];
|
||||||
|
|
||||||
|
// // Utilisez la réflexion pour obtenir toutes les classes disponibles
|
||||||
|
// $classes = get_declared_classes();
|
||||||
|
|
||||||
|
// foreach ($classes as $class) {
|
||||||
|
// $reflectionClass = new ReflectionClass($class);
|
||||||
|
// if ($reflectionClass->implementsInterface(MiddlewareInterface::class)) {
|
||||||
|
// // La classe implémente MiddlewareInterface, ajoutez-la à la liste
|
||||||
|
// $middlewareClasses[] = $class;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
namespace App;
|
||||||
|
use Controllers\BaseController;
|
||||||
|
class AppCreator
|
||||||
|
{
|
||||||
|
private Container $container;
|
||||||
|
|
||||||
|
private array $services = [];
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,108 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Container
|
||||||
|
*/
|
||||||
|
class Container
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $instances = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $abstract
|
||||||
|
* @param null $concrete
|
||||||
|
*/
|
||||||
|
public function set($abstract, $concrete = NULL)
|
||||||
|
{
|
||||||
|
if ($concrete === NULL) {
|
||||||
|
$concrete = $abstract;
|
||||||
|
}
|
||||||
|
$this->instances[$abstract] = $concrete;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $abstract
|
||||||
|
* @param array $parameters
|
||||||
|
*
|
||||||
|
* @return mixed|null|object
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function get($abstract, $parameters = [])
|
||||||
|
{
|
||||||
|
// if we don't have it, just register it
|
||||||
|
if (!isset($this->instances[$abstract])) {
|
||||||
|
$this->set($abstract);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->resolve($this->instances[$abstract], $parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resolve single
|
||||||
|
*
|
||||||
|
* @param $concrete
|
||||||
|
* @param $parameters
|
||||||
|
*
|
||||||
|
* @return mixed|object
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function resolve($concrete, $parameters)
|
||||||
|
{
|
||||||
|
if ($concrete instanceof Closure) {
|
||||||
|
return $concrete($this, $parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
$reflector = new ReflectionClass($concrete);
|
||||||
|
// check if class is instantiable
|
||||||
|
if (!$reflector->isInstantiable()) {
|
||||||
|
throw new Exception("Class {$concrete} is not instantiable");
|
||||||
|
}
|
||||||
|
|
||||||
|
// get class constructor
|
||||||
|
$constructor = $reflector->getConstructor();
|
||||||
|
if (is_null($constructor)) {
|
||||||
|
// get new instance from class
|
||||||
|
return $reflector->newInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
// get constructor params
|
||||||
|
$parameters = $constructor->getParameters();
|
||||||
|
$dependencies = $this->getDependencies($parameters);
|
||||||
|
|
||||||
|
// get new instance with dependencies resolved
|
||||||
|
return $reflector->newInstanceArgs($dependencies);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get all dependencies resolved
|
||||||
|
*
|
||||||
|
* @param $parameters
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function getDependencies($parameters)
|
||||||
|
{
|
||||||
|
$dependencies = [];
|
||||||
|
foreach ($parameters as $parameter) {
|
||||||
|
// get the type hinted class
|
||||||
|
$dependency = $parameter->getClass();
|
||||||
|
if ($dependency === NULL) {
|
||||||
|
// check if default value for a parameter is available
|
||||||
|
if ($parameter->isDefaultValueAvailable()) {
|
||||||
|
// get default value of parameter
|
||||||
|
$dependencies[] = $parameter->getDefaultValue();
|
||||||
|
} else {
|
||||||
|
throw new Exception("Can not resolve class dependency {$parameter->name}");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// get dependency resolved
|
||||||
|
$dependencies[] = $this->get($dependency->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $dependencies;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
<?
|
||||||
|
class MyHttpClient {
|
||||||
|
private $baseUrl;
|
||||||
|
private $headers;
|
||||||
|
|
||||||
|
public function __construct($baseUrl) {
|
||||||
|
$this->baseUrl = $baseUrl;
|
||||||
|
$this->headers = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setHeader($name, $value) {
|
||||||
|
$this->headers[$name] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get($endpoint) {
|
||||||
|
$url = $this->baseUrl . '/' . $endpoint;
|
||||||
|
return $this->sendRequest('GET', $url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function post($endpoint, $data) {
|
||||||
|
$url = $this->baseUrl . '/' . $endpoint;
|
||||||
|
return $this->sendRequest('POST', $url, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function sendRequest($method, $url, $data = null) {
|
||||||
|
$options = [
|
||||||
|
'http' => [
|
||||||
|
'method' => $method,
|
||||||
|
'header' => $this->buildHeaders(),
|
||||||
|
'content' => $data ? http_build_query($data) : null,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
$context = stream_context_create($options);
|
||||||
|
$response = file_get_contents($url, false, $context);
|
||||||
|
|
||||||
|
// error handling
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildHeaders() {
|
||||||
|
$headers = [];
|
||||||
|
foreach ($this->headers as $name => $value) {
|
||||||
|
$headers[] = "$name: $value";
|
||||||
|
}
|
||||||
|
return implode("\r\n", $headers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Usage
|
||||||
|
$httpClient = new MyHttpClient('https://api.example.com');
|
||||||
|
|
||||||
|
// Add headers (e.g., authentication token)
|
||||||
|
$httpClient->setHeader('Authorization', 'Bearer your-auth-token-here');
|
||||||
|
|
||||||
|
// Example GET request
|
||||||
|
$getResponse = $httpClient->get('some-endpoint');
|
||||||
|
echo "GET Response: $getResponse\n";
|
||||||
|
|
||||||
|
// Example POST request
|
||||||
|
$postData = ['key' => 'value'];
|
||||||
|
$postResponse = $httpClient->post('another-endpoint', $postData);
|
||||||
|
echo "POST Response: $postResponse\n";
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Controllers;
|
||||||
|
|
||||||
|
class AthleteController extends BaseController
|
||||||
|
{
|
||||||
|
protected $authService;
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
// Initialize UserController specific configurations or dependencies
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
// Handle the user listing logic here
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show($id)
|
||||||
|
{
|
||||||
|
// Handle displaying a specific user by ID
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
// Handle user creation logic here
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store()
|
||||||
|
{
|
||||||
|
// Handle storing a new user in the database
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit($id)
|
||||||
|
{
|
||||||
|
// Handle user editing logic here
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update($id)
|
||||||
|
{
|
||||||
|
// Handle updating a user in the database
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy($id)
|
||||||
|
{
|
||||||
|
// Handle user deletion logic here
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,141 @@
|
|||||||
|
<?php
|
||||||
|
namespace Controllers;
|
||||||
|
use Responce\{RedirectResponse, Response};
|
||||||
|
/**
|
||||||
|
* BaseController is a abstract class that embede all based function of a controller in this app
|
||||||
|
* Responsabilité du contrôleur :
|
||||||
|
* - Gérer les demandes HTTP et coordonner l'exécution de l'action appropriée.
|
||||||
|
* - Exposer des méthodes/actions qui sont spécifiques à l'interface utilisateur.
|
||||||
|
* !!! Aucune logique métier ici !!!
|
||||||
|
* Contôle l'intégrité des données et valid les action ( les deux doivent être vérifier)
|
||||||
|
* Ses responsabilités sont de garantir que les données de la demande sont valides et de choisir la vue à retourner.
|
||||||
|
* Un Controller à la responsibilité de lire les information d'un Request(obj) et créer une {Response}.
|
||||||
|
* Un controller à toujour un default et un Null case
|
||||||
|
*/
|
||||||
|
abstract class BaseController{
|
||||||
|
|
||||||
|
private DI $container;
|
||||||
|
|
||||||
|
public function __construct(DI $di){
|
||||||
|
$this->container = $di;
|
||||||
|
}
|
||||||
|
|
||||||
|
// private ILogger<T> $logger;
|
||||||
|
protected function redirect(string $url, int $status = 302): RedirectResponse
|
||||||
|
{
|
||||||
|
return new RedirectResponse($url, $status);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function redirectToRoute(string $route, array $parameters = [], int $status = 302): RedirectResponse
|
||||||
|
{
|
||||||
|
return $this->redirect($this->generateUrl($route, $parameters), $status);
|
||||||
|
}
|
||||||
|
protected function renderView(string $view, array $parameters = []): string
|
||||||
|
{
|
||||||
|
return $this->doRenderView($view, null, $parameters, __FUNCTION__);
|
||||||
|
}
|
||||||
|
protected function render(string $view, array $parameters = [], Response $response = null): Response
|
||||||
|
{
|
||||||
|
return $this->doRender($view, null, $parameters, $response, __FUNCTION__);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Renders a view.
|
||||||
|
*
|
||||||
|
* If an invalid form is found in the list of parameters, a 422 status code is returned.
|
||||||
|
* Forms found in parameters are auto-cast to form views.
|
||||||
|
*/
|
||||||
|
protected function render(string $view, array $parameters = [], Response $response = null): Response
|
||||||
|
{
|
||||||
|
$content = $this->renderView($view, $parameters);
|
||||||
|
$response ??= new Response();
|
||||||
|
|
||||||
|
if (200 === $response->getStatusCode()) {
|
||||||
|
foreach ($parameters as $v) {
|
||||||
|
if ($v instanceof FormInterface && $v->isSubmitted() && !$v->isValid()) {
|
||||||
|
$response->setStatusCode(422);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$response->setContent($content);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
private function doRenderView(string $view, ?string $block, array $parameters, string $method): string
|
||||||
|
{
|
||||||
|
if (!$this->container->has('twig')) {
|
||||||
|
throw new \LogicException(sprintf('You cannot use the "%s" method if the Twig Bundle is not available. Try running "composer require symfony/twig-bundle".', $method));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($parameters as $k => $v) {
|
||||||
|
if ($v instanceof FormInterface) {
|
||||||
|
$parameters[$k] = $v->createView();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $block) {
|
||||||
|
return $this->container->get('twig')->load($view)->renderBlock($block, $parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function doRender(string $view, ?string $block, array $parameters, ?Response $response, string $method): Response
|
||||||
|
{
|
||||||
|
$content = $this->doRenderView($view, $block, $parameters, $method);
|
||||||
|
$response ??= new Response();
|
||||||
|
|
||||||
|
if (200 === $response->getStatusCode()) {
|
||||||
|
foreach ($parameters as $v) {
|
||||||
|
if ($v instanceof FormInterface && $v->isSubmitted() && !$v->isValid()) {
|
||||||
|
$response->setStatusCode(422);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$response->setContent($content);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and returns a Form instance from the type of the form.
|
||||||
|
*/
|
||||||
|
protected function createForm(string $type, mixed $data = null, array $options = []): FormInterface
|
||||||
|
{
|
||||||
|
return $this->container->get('form.factory')->create($type, $data, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and returns a form builder instance.
|
||||||
|
*/
|
||||||
|
protected function createFormBuilder(mixed $data = null, array $options = []): FormBuilderInterface
|
||||||
|
{
|
||||||
|
return $this->container->get('form.factory')->createBuilder(FormType::class, $data, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public function index();
|
||||||
|
|
||||||
|
public function __call($method, $parameters)
|
||||||
|
{
|
||||||
|
throw new BadMethodCallException(sprintf(
|
||||||
|
'Method %s::%s does not exist.', static::class, $method
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute an action on the controller.
|
||||||
|
*
|
||||||
|
* @param string $method
|
||||||
|
* @param array $parameters
|
||||||
|
*/
|
||||||
|
public function callAction($method, $parameters): Response
|
||||||
|
{
|
||||||
|
return $this->{$method}(...array_values($parameters));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
?>
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,168 @@
|
|||||||
|
<?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
|
||||||
|
class FrontController {
|
||||||
|
private $router;
|
||||||
|
|
||||||
|
private $container;
|
||||||
|
|
||||||
|
public function __construct(Router $router, Container $container) {
|
||||||
|
$this->router = $router;
|
||||||
|
$this->container = $container;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dispatch(IRequest $request) {
|
||||||
|
try {
|
||||||
|
$match = $this->router->match($request);
|
||||||
|
|
||||||
|
if (!is_null($match)) {
|
||||||
|
$controller = $this->getController($match['target']);
|
||||||
|
$request->addToBody($match['params']);
|
||||||
|
|
||||||
|
|
||||||
|
if (!is_callable($controller)){
|
||||||
|
// body to key values maybe is better
|
||||||
|
// $request = array_reduce($params, function ($request, $key) use ($params) {
|
||||||
|
// 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 {
|
||||||
|
return $this->handleError(404, "Page not found");
|
||||||
|
}
|
||||||
|
} catch (NotFoundHttpException $e) {
|
||||||
|
return $this->handleError(404, $e->getMessage());
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return $this->handleError(500, "Internal Server Error: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
return $this->container->get($controllerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function handleError($statusCode, $message) {// composant twig
|
||||||
|
// http_response_code($statusCode);
|
||||||
|
$response = new Response($statusCode, $message);
|
||||||
|
echo $message;
|
||||||
|
// status,..., body
|
||||||
|
// return new Responce(404,[notfond],erreur.twig)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
<!--
|
||||||
|
Point d'entrée unique : Le front controller est le point d'entrée unique de toutes les requêtes HTTP entrantes dans une application Symfony. Toutes les requêtes sont dirigées vers ce contrôleur, qui est généralement un fichier PHP, tel que public/index.php.
|
||||||
|
|
||||||
|
Initialisation : Le front controller initialise l'application en chargeant les dépendances, en configurant l'environnement, en définissant les paramètres globaux, et en préparant l'infrastructure de base nécessaire pour gérer les requêtes HTTP.
|
||||||
|
|
||||||
|
Gestion de la requête : Une fois qu'une requête HTTP arrive, le front controller crée un objet Request à partir de cette requête entrante. Il s'occupe également de la gestion de la session, de la gestion des cookies, et de l'analyse des en-têtes HTTP.
|
||||||
|
|
||||||
|
Routage vers le contrôleur : Le front controller interagit avec le router pour déterminer quel contrôleur doit être utilisé pour traiter la requête. Il envoie la requête au router pour faire correspondre l'URL demandée à une route et obtenir des informations sur le contrôleur et l'action associés.
|
||||||
|
|
||||||
|
Résolution du contrôleur : Une fois que le router a identifié le contrôleur et l'action à appeler, le front controller résout le contrôleur en créant une instance de l'objet contrôleur approprié. Il extrait également l'action à appeler.
|
||||||
|
|
||||||
|
Exécution de l'action : Le front controller appelle l'action du contrôleur avec les paramètres nécessaires, généralement en passant l'objet Request. L'action effectue le traitement spécifique à la page, tel que la récupération de données, la manipulation des données, etc.
|
||||||
|
|
||||||
|
Génération de la réponse : Après avoir exécuté l'action, le contrôleur génère une réponse HTTP sous la forme d'un objet Response. Cette réponse peut contenir des données à afficher dans le navigateur du client.
|
||||||
|
|
||||||
|
Envoi de la réponse : Le front controller envoie finalement la réponse HTTP générée par le contrôleur au client, qui l'affiche dans le navigateur -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- c'est App -->
|
@ -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
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
|||||||
|
<?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
|
||||||
|
{
|
||||||
|
private string $name;
|
||||||
|
|
||||||
|
private string $path;
|
||||||
|
|
||||||
|
private string $method; // callable|array
|
||||||
|
|
||||||
|
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 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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
<!-- Correspondance des URLs : Le rôle principal du router est de faire correspondre les URLs entrantes aux contrôleurs et aux actions qui doivent les gérer.
|
||||||
|
Il examine l'URL demandée par le client (par exemple, "/contact") et détermine quelle route correspondante peut être utilisée.
|
||||||
|
|
||||||
|
Ces règles peuvent être définies à l'aide d'annotations dans les contrôleurs.
|
||||||
|
|
||||||
|
Gestion des paramètres d'URL : Le router extrait également les paramètres d'URL de l'URL demandée. Par exemple, si l'URL est "/articles/123", le router extraira l'identifiant "123" en tant que paramètre pour être transmis au contrôleur.
|
||||||
|
|
||||||
|
Gestion des noms de route : Le router attribue des noms aux routes définies, ce qui permet aux développeurs de générer des URLs à partir de noms de route dans leurs vues ou leurs contrôleurs. Cela simplifie la génération d'URLs dans l'application.
|
||||||
|
|
||||||
|
Gestion des erreurs de routage : En cas de route non trouvée (par exemple, lorsque l'URL demandée ne correspond à aucune route définie), le router peut générer une réponse HTTP appropriée, généralement une réponse "404 Not Found".
|
||||||
|
|
||||||
|
Configuration du contexte de routage : Le router tient compte du contexte de la requête actuelle, ce qui signifie qu'il peut adapter la recherche de routes en fonction des paramètres de la requête, tels que la langue, la méthode HTTP, etc. -->
|
||||||
|
<!--
|
||||||
|
match: Méthode pour faire correspondre une URL à une route et renvoyer les informations de route.
|
||||||
|
generate: Méthode pour générer une URL à partir du nom de la route et des paramètres.
|
||||||
|
getContext: Récupère le contexte de la requête.
|
||||||
|
setContext: Définit le contexte de la requête.
|
||||||
|
getRouteCollection: Récupère la collection de routes.
|
||||||
|
getMatcher: Récupère l'objet UrlMatcher utilisé pour la correspondance des URLs -->
|
||||||
|
|
||||||
|
<!-- Création de l'objet Request : Le contrôleur frontal crée un objet Request à partir de la requête HTTP entrante en utilisant la classe Symfony\Component\HttpFoundation\Request.
|
||||||
|
Configuration du router : Il configure et utilise le router (objet Router) pour faire correspondre l'URL à une route.
|
||||||
|
Résolution du contrôleur : Le contrôleur frontal résout le contrôleur en utilisant le contrôleur résolveur (généralement une instance de Symfony\Component\HttpKernel\Controller\ControllerResolver).
|
||||||
|
Exécution de l'action : Il appelle l'action du contrôleur en fonction de la route correspondante et exécute l'action spécifique à la page.
|
||||||
|
Création de la réponse : Le contrôleur frontal crée un objet Response pour contenir la réponse HTTP générée par l'action du contrôleur.
|
||||||
|
Envoi de la réponse : Il envoie finalement la réponse HTTP au client en utilisant la méthode send de l'objet Response -->
|
||||||
|
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Router;
|
||||||
|
use App\Router\Request\IRequest;
|
||||||
|
use App\Enums\HttpMethod;
|
||||||
|
// Just a url matcher
|
||||||
|
|
||||||
|
class Router {
|
||||||
|
|
||||||
|
private string $path;
|
||||||
|
|
||||||
|
// routes collection
|
||||||
|
private \AltoRouter $routes;
|
||||||
|
|
||||||
|
public function __construct(string $path = "/PHP/project/index.php") {
|
||||||
|
$this->path = $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());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// extrait les paramètres d'URL de l'URL demandée
|
||||||
|
|
||||||
|
public function extractParams(string $path) {}
|
||||||
|
|
||||||
|
public function get(string $path, callable $callable, $name) {
|
||||||
|
$this->routes->map('GET', $path, $callable, $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function post(string $path, callable $callable, $name) {
|
||||||
|
$this->routes->map('POST', $path, $callable, $name);
|
||||||
|
}
|
||||||
|
public function put(string $path, callable $callable, $name) {
|
||||||
|
$this->routes->map('PUT', $path, $callable, $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// check if the request can be process
|
||||||
|
public function match (IRequest $request): ?array {
|
||||||
|
$result = $this->routes->match($request->getRequestUri(), $request->getMethod());
|
||||||
|
if ($result) {
|
||||||
|
// not Route
|
||||||
|
// retunr $result
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
?>
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class HttpException extends \RuntimeException
|
||||||
|
{
|
||||||
|
private int $statusCode;
|
||||||
|
private array $headers;
|
||||||
|
|
||||||
|
public function __construct(int $statusCode, string $message = '', \Throwable $previous = null, array $headers = [], int $code = 0)
|
||||||
|
{
|
||||||
|
$this->statusCode = $statusCode;
|
||||||
|
$this->headers = $headers;
|
||||||
|
|
||||||
|
parent::__construct($message, $code, $previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStatusCode(): int
|
||||||
|
{
|
||||||
|
return $this->statusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHeaders(): array
|
||||||
|
{
|
||||||
|
return $this->headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setHeaders(array $headers)
|
||||||
|
{
|
||||||
|
$this->headers = $headers;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
*/
|
||||||
|
class NotFoundHttpException extends HttpException
|
||||||
|
{
|
||||||
|
public function __construct(string $message = '', \Throwable $previous = null, int $code = 0, array $headers = [])
|
||||||
|
{
|
||||||
|
parent::__construct(404, $message, $previous, $headers, $code);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class ValidationException extends Exception {
|
||||||
|
protected $errors;
|
||||||
|
|
||||||
|
public function __construct(array $errors, $message = "Validation errors occurred", $code = 0, Exception $previous = null) {
|
||||||
|
parent::__construct($message, $code, $previous);
|
||||||
|
$this->errors = $errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getErrors() {
|
||||||
|
return $this->errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString() {
|
||||||
|
return __CLASS__ . ": [{$this->code}]: {$this->message}\n" . $this->formatErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formatErrors() {
|
||||||
|
return implode("\n", array_map(function ($error) {
|
||||||
|
return "- {$error}";
|
||||||
|
}, $this->errors));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Router\Middleware;
|
||||||
|
use App\Router\Request\IRequest;
|
||||||
|
use Shared\Validation\Validator;
|
||||||
|
|
||||||
|
class RequestValidationMiddleware extends Middleware {
|
||||||
|
private $validator;
|
||||||
|
private $rules;
|
||||||
|
|
||||||
|
public function __construct(Validator $validator, array $rules) {
|
||||||
|
$this->validator = $validator;
|
||||||
|
$this->rules = $rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(IRequest $request, callable $next) {
|
||||||
|
$this->validateRequest($request);
|
||||||
|
return parent::handle($request, $next);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function validateRequest(IRequest $request) {
|
||||||
|
foreach ($this->rules as $param => $ruleSet) {
|
||||||
|
foreach ($ruleSet as $rule) {
|
||||||
|
$this->validator->rule($param, $rule['callback'], $rule['message']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$requestData = array_merge($request->getQueryParameters(), $request->getRequestParameters());
|
||||||
|
$this->validator->assert($requestData);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// $validationRules = [
|
||||||
|
// 'email' => [
|
||||||
|
// ['callback' => Validator::required(), 'message' => 'Email is required.'],
|
||||||
|
// ['callback' => Validator::email(), 'message' => 'Email must be a valid email address.']
|
||||||
|
// ],
|
||||||
|
// // Add more rules as needed
|
||||||
|
// ];
|
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Router\Middleware;
|
||||||
|
|
||||||
|
use App\Router\Request\IRequest;
|
||||||
|
|
||||||
|
interface IHttpMiddleware {
|
||||||
|
public function handle(IRequest $request, callable $next);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Router\Middleware;
|
||||||
|
|
||||||
|
use App\Router\Request\IRequest;
|
||||||
|
|
||||||
|
class LoggingMiddleware extends Middleware {
|
||||||
|
public function handle(IRequest $request, callable $next) {
|
||||||
|
// Logique de journalisation
|
||||||
|
echo "LoggingMiddleware: Log request - Method: {$request->getMethod()}, URI: {$request->getRequestUri()}\n";
|
||||||
|
return parent::handle($request, $next);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
// Chain of Responsibility
|
||||||
|
// 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
|
||||||
|
// 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 {
|
||||||
|
protected $next;
|
||||||
|
|
||||||
|
public function setNext(IHttpMiddleware $nextMiddleware) {
|
||||||
|
$this->next = $nextMiddleware;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(IRequest $request, callable $next) {
|
||||||
|
if ($this->next !== null) {
|
||||||
|
return $this->next->handle($request, $next);
|
||||||
|
}
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Router\Request;
|
||||||
|
|
||||||
|
interface ContentStrategy {
|
||||||
|
public function getContent(): array;
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Router\Request;
|
||||||
|
|
||||||
|
// should maybe change this
|
||||||
|
class ContentStrategyFactory {
|
||||||
|
private static $strategyMap = [
|
||||||
|
'application/json' => JsonContentStrategy::class,
|
||||||
|
// Format...
|
||||||
|
];
|
||||||
|
|
||||||
|
public static function createContentStrategy(string $contentType, string $requestMethod): ContentStrategy {
|
||||||
|
foreach (self::$strategyMap as $type => $className) {
|
||||||
|
if ($contentType === $type || in_array($requestMethod, ['PUT', 'PATCH', 'DELETE'])) {
|
||||||
|
return new $className();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new FormContentStrategy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function registerStrategy(string $contentType, string $className): void {
|
||||||
|
self::$strategyMap[$contentType] = $className;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Router\Request;
|
||||||
|
|
||||||
|
|
||||||
|
class FormContentStrategy implements ContentStrategy {
|
||||||
|
public function getContent(): array {
|
||||||
|
return $_POST;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Router\Request;
|
||||||
|
|
||||||
|
class HttpRequest implements IRequest {
|
||||||
|
private $queryParameters;
|
||||||
|
private $requestParameters;
|
||||||
|
private $method;
|
||||||
|
private $requestUri;
|
||||||
|
private $headers;
|
||||||
|
|
||||||
|
private array $body;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
array $query,
|
||||||
|
array $server,
|
||||||
|
array $headers,
|
||||||
|
ContentStrategy $contentStrategy,
|
||||||
|
array $body
|
||||||
|
) {
|
||||||
|
$this->queryParameters = $query;
|
||||||
|
$this->requestUri = $server['REQUEST_URI'] ?? '';
|
||||||
|
$this->method = strtoupper($server['REQUEST_METHOD'] ?? 'GET');
|
||||||
|
$this->headers = $headers;
|
||||||
|
$this->requestParameters = $contentStrategy->getContent();
|
||||||
|
$this->body = $body;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQueryParameters(): array {
|
||||||
|
return $this->queryParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRequestParameters(): array {
|
||||||
|
return $this->requestParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMethod(): string {
|
||||||
|
return $this->method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRequestUri(): string {
|
||||||
|
return $this->requestUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHeaders(): array {
|
||||||
|
return $this->headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBody(): array{
|
||||||
|
return $this->body;
|
||||||
|
}
|
||||||
|
public function addToBody(string|array $attributes){
|
||||||
|
$this->body[] = $attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Router\Request;
|
||||||
|
|
||||||
|
|
||||||
|
interface IRequest
|
||||||
|
{
|
||||||
|
public function getRequestUri();
|
||||||
|
|
||||||
|
public function getBody();
|
||||||
|
public function addToBody(string|array $attributes);
|
||||||
|
|
||||||
|
public function getHeaders();
|
||||||
|
public function getMethod();
|
||||||
|
public function getQueryParameters(): array;
|
||||||
|
public function getRequestParameters(): array;
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Router\Request;
|
||||||
|
|
||||||
|
class JsonContentStrategy implements ContentStrategy {
|
||||||
|
public function getContent(): array {
|
||||||
|
$rawContent = file_get_contents('php://input');
|
||||||
|
return json_decode($rawContent, true) ?? [];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
namespace App\Router\Request;
|
||||||
|
|
||||||
|
class RequestFactory {
|
||||||
|
|
||||||
|
public static function createFromGlobals(): IRequest {
|
||||||
|
$query = $_GET;
|
||||||
|
$server = $_SERVER;
|
||||||
|
$headers = self::getRequestHeaders();
|
||||||
|
|
||||||
|
$contentType = $headers['Content-Type'] ?? '';
|
||||||
|
$contentStrategy = ContentStrategyFactory::createContentStrategy($contentType, $server['REQUEST_METHOD']);
|
||||||
|
|
||||||
|
return new HttpRequest($query, $server, $headers, $contentStrategy);
|
||||||
|
}
|
||||||
|
// should not be heare
|
||||||
|
private static function getRequestHeaders(): array {
|
||||||
|
$headers = [];
|
||||||
|
foreach ($_SERVER as $key => $value) {
|
||||||
|
if (substr($key, 0, 5) === 'HTTP_') {
|
||||||
|
$header = str_replace(' ', '-', ucwords(str_replace('_', ' ', strtolower(substr($key, 5)))));
|
||||||
|
$headers[$header] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $headers;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
interface ResponseInterface {
|
||||||
|
public function getContent(): string;
|
||||||
|
public function setContent(string $content): void;
|
||||||
|
public function getStatusCode(): int;
|
||||||
|
public function setStatusCode(int $statusCode): void;
|
||||||
|
public function getHeaders(): array;
|
||||||
|
public function setHeader(string $key, string $value): void;
|
||||||
|
public function send(): void;
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
<!-- its can be a HTML page, JSON, XML, a file download, a redirect, a 404 error or anything else -->
|
||||||
|
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Response implements IResponce {
|
||||||
|
private string $content;
|
||||||
|
private int $statusCode;
|
||||||
|
private array $headers;
|
||||||
|
|
||||||
|
public function __construct(string $content = "", int $statusCode = 200, array $headers = []) {
|
||||||
|
$this->content = $content;
|
||||||
|
$this->statusCode = $statusCode;
|
||||||
|
$this->headers = $headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getContent(): string {
|
||||||
|
return $this->content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setContent(string $content): void {
|
||||||
|
$this->content = $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStatusCode(): int {
|
||||||
|
return $this->statusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setStatusCode(int $statusCode): void {
|
||||||
|
$this->statusCode = $statusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHeaders(): array {
|
||||||
|
return $this->headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setHeader(string $key, string $value): void {
|
||||||
|
$this->headers[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function send(): void {
|
||||||
|
foreach ($this->headers as $key => $value) {
|
||||||
|
header("{$key}: {$value}");
|
||||||
|
}
|
||||||
|
http_response_code($this->statusCode);
|
||||||
|
echo $this->content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
?>
|
@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
abstract class AbstractField implements IField {
|
||||||
|
protected $name;
|
||||||
|
protected $value;
|
||||||
|
protected $validators = [];
|
||||||
|
|
||||||
|
public function __construct($name) {
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName() {
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Autres méthodes...
|
||||||
|
}
|
||||||
|
|
||||||
|
// abstract class AbstractField {
|
||||||
|
// protected $name;
|
||||||
|
// protected $value;
|
||||||
|
// protected $attributes;
|
||||||
|
// protected $errors = [];
|
||||||
|
// protected $validators = [];
|
||||||
|
|
||||||
|
// public function __construct($name, $value = '', $attributes = []) {
|
||||||
|
// $this->name = $name;
|
||||||
|
// $this->value = $value;
|
||||||
|
// $this->attributes = $attributes;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function getName() {
|
||||||
|
// return $this->name;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function getValue() {
|
||||||
|
// return $this->value;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function setValue($value) {
|
||||||
|
// $this->value = $value;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function addValidator(callable $validator) {
|
||||||
|
// $this->validators[] = $validator;
|
||||||
|
// return $this;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function isValid() {
|
||||||
|
// foreach ($this->validators as $validator) {
|
||||||
|
// if (!$validator($this->value)) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function getErrors() {
|
||||||
|
// return $this->errors;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function addError($error) {
|
||||||
|
// $this->errors[] = $error;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function getAttributesAsString() {
|
||||||
|
// $attributesStr = '';
|
||||||
|
// foreach ($this->attributes as $key => $value) {
|
||||||
|
// $attributesStr .= " $key=\"$value\"";
|
||||||
|
// }
|
||||||
|
// return $attributesStr;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// abstract public function render();
|
||||||
|
// }
|
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class AbstractType implements FormTypeInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
protected $fields = [];
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function buildView(FormView $view, FormInterface $form, array $options)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function finishView(FormView $view, FormInterface $form, array $options)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
class FieldFactory {
|
||||||
|
public static function createField($type, $name) {
|
||||||
|
switch($type) {
|
||||||
|
case 'text': return new TextField($name);
|
||||||
|
// Autres cas...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class FormBuilder {
|
||||||
|
private $form;
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
$this->form = new BasicForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addText($name, $options) {
|
||||||
|
$this->form->add(FieldFactory::createField('text', $options));
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function build() {
|
||||||
|
return $this->form;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
<?php
|
||||||
|
interface FieldInterface {
|
||||||
|
public function render();
|
||||||
|
public function validate($value);
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
interface FormInterface {
|
||||||
|
public function add(FieldInterface $field);
|
||||||
|
public function remove($fieldName);
|
||||||
|
public function submit($requestData);
|
||||||
|
public function isValid();
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
<!-- rendering HTML form fields, validating submitted data, mapping the form data into objects and a lot more -->
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Login extends AbstractForm {
|
||||||
|
// Implémentation spécifique de BasicForm
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
?>
|
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class TextField extends AbstractField {
|
||||||
|
public function render() {
|
||||||
|
return "<input type='text' name='{$this->name}' value='{$this->value}' />";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validate($value) {
|
||||||
|
// Logique de validation
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
{# templates/login/index.html.twig #}
|
||||||
|
{% extends 'base.html.twig' %}
|
||||||
|
|
||||||
|
{# ... #}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
{% if error %}
|
||||||
|
<div>{{ error.messageKey|trans(error.messageData, 'security') }}</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<form action="{{ path('app_login') }}" method="post">
|
||||||
|
<label for="username">Email:</label>
|
||||||
|
<input type="text" id="username" name="_username" value="{{ last_username }}">
|
||||||
|
|
||||||
|
<label for="password">Password:</label>
|
||||||
|
<input type="password" id="password" name="_password">
|
||||||
|
|
||||||
|
{# If you want to control the URL the user is redirected to on success
|
||||||
|
<input type="hidden" name="_target_path" value="/account"> #}
|
||||||
|
|
||||||
|
<button type="submit">login</button>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
namespace Console;
|
||||||
|
|
||||||
|
class Application extends Shared\Application{
|
||||||
|
private $dataManager;
|
||||||
|
private Menu $currentMenu;
|
||||||
|
public function __construct(DataManager $dataManager) {
|
||||||
|
$this->dataManager = $dataManager;
|
||||||
|
$this->currentMenu = new AuthMenu();
|
||||||
|
}
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
while (true) {
|
||||||
|
if (!$this->authenticationController->isLoggedIn()) {
|
||||||
|
$this->authenticationController->displayAuthMenu();
|
||||||
|
} else {
|
||||||
|
$this->menuController->displayMainMenu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class AuthMenu extends Menu {
|
||||||
|
public function display() {
|
||||||
|
$this->clearScreen();
|
||||||
|
echo "\n\n";
|
||||||
|
echo " +--------------------------+\n";
|
||||||
|
echo " | Authentification |\n";
|
||||||
|
echo " +--------------------------+\n";
|
||||||
|
echo " | 1. Se connecter |\n";
|
||||||
|
echo " | 2. S'inscrire |\n";
|
||||||
|
echo " | 0. Quitter |\n";
|
||||||
|
echo " +--------------------------+\n";
|
||||||
|
echo " Choisissez une option: ";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
class ClearScreenCommand {
|
||||||
|
public function execute() {
|
||||||
|
system('clear || cls');
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
<?php
|
||||||
|
interface IPrinter {
|
||||||
|
public function display();
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class Menu implements IPrinter {
|
||||||
|
protected ClearScreenCommand $clearScreenCommand;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->clearScreenCommand = new ClearScreenCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function clearScreen()
|
||||||
|
{
|
||||||
|
$this->clearScreenCommand->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public function display();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Security
|
||||||
|
{
|
||||||
|
const tokenSession = 'tokenSession';
|
||||||
|
private array $session;
|
||||||
|
private UserRepository $userGateway;
|
||||||
|
private ?User $user = null;
|
||||||
|
|
||||||
|
public function __construct(UserRepository $userGateway, array &$session)
|
||||||
|
{
|
||||||
|
$this->userGateway = $userGateway;
|
||||||
|
$this->session = &$session;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function initLogin(string $login, string $rawPassword): bool
|
||||||
|
{
|
||||||
|
$user = $this->userGateway->getByLogin($login);
|
||||||
|
if ($user === null || !password_verify($rawPassword, $user->getPasswordHash())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$this->session[tokenSession] = $user->getId();
|
||||||
|
$this->user = $user;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function logout(): bool
|
||||||
|
{
|
||||||
|
|
||||||
|
if(session_unset()){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
$this->user = null;
|
||||||
|
session_unset();
|
||||||
|
session_destroy();
|
||||||
|
$_SESSION['role'] = "";
|
||||||
|
$_SESSION=array();
|
||||||
|
unset($this->session[tokenSession]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCurrentUser(): ?User
|
||||||
|
{
|
||||||
|
if (!empty($this->session[tokenSession]) && $this->user === null) {
|
||||||
|
$this->user = $this->userGateway->getById($this->session[tokenSession]);
|
||||||
|
}
|
||||||
|
return $this->user;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
@ -1,8 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Model;
|
namespace Model;
|
||||||
|
|
||||||
|
|
||||||
class Coach extends Role {
|
class Coach extends Role {
|
||||||
// Attributs spécifiques au Coach si nécessaire
|
// Attributs spécifiques au Coach si nécessaire
|
||||||
|
private $idCoach;
|
||||||
|
private array $athletes;
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
class Validator {
|
||||||
|
protected $rules = [];
|
||||||
|
|
||||||
|
public function rule($field, callable $callback, $message = '') {
|
||||||
|
$this->rules[$field][] = [
|
||||||
|
'callback' => $callback,
|
||||||
|
'message' => $message
|
||||||
|
];
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validate(array $data) {
|
||||||
|
$errors = [];
|
||||||
|
|
||||||
|
foreach ($this->rules as $field => $fieldRules) {
|
||||||
|
foreach ($fieldRules as $rule) {
|
||||||
|
if (!array_key_exists($field, $data) || !call_user_func($rule['callback'], $data[$field])) {
|
||||||
|
$errors[$field][] = $rule['message'] ?: "The field {$field} is invalid.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function assert(array $data) {
|
||||||
|
$errors = $this->validate($data);
|
||||||
|
if (!empty($errors)) {
|
||||||
|
throw new ValidationException($errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static helper methods for common validations
|
||||||
|
public static function required() {
|
||||||
|
return function ($value) {
|
||||||
|
return !empty($value);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function email() {
|
||||||
|
return function ($value) {
|
||||||
|
return filter_var($value, FILTER_VALIDATE_EMAIL) !== false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function minLength($length) {
|
||||||
|
return function ($value) use ($length) {
|
||||||
|
return mb_strlen($value) >= $length;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function maxLength($length) {
|
||||||
|
return function ($value) use ($length) {
|
||||||
|
return mb_strlen($value) <= $length;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function regex($pattern) {
|
||||||
|
return function ($value) use ($pattern) {
|
||||||
|
return preg_match($pattern, $value) === 1;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function number() {
|
||||||
|
return function ($value) {
|
||||||
|
return filter_var($value, FILTER_VALIDATE_FLOAT) !== 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";
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
language: php
|
||||||
|
php:
|
||||||
|
- 5.3
|
||||||
|
- 5.4
|
||||||
|
- 5.5
|
||||||
|
|
||||||
|
script: phpunit --coverage-text ./
|
@ -0,0 +1,270 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class AltoRouter {
|
||||||
|
|
||||||
|
protected $routes = array();
|
||||||
|
protected $namedRoutes = array();
|
||||||
|
protected $basePath = '';
|
||||||
|
protected $matchTypes = array(
|
||||||
|
'i' => '[0-9]++',
|
||||||
|
'a' => '[0-9A-Za-z]++',
|
||||||
|
'h' => '[0-9A-Fa-f]++',
|
||||||
|
'*' => '.+?',
|
||||||
|
'**' => '.++',
|
||||||
|
'' => '[^/\.]++'
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create router in one call from config.
|
||||||
|
*
|
||||||
|
* @param array $routes
|
||||||
|
* @param string $basePath
|
||||||
|
* @param array $matchTypes
|
||||||
|
*/
|
||||||
|
public function __construct( $routes = array(), $basePath = '', $matchTypes = array() ) {
|
||||||
|
$this->addRoutes($routes);
|
||||||
|
$this->setBasePath($basePath);
|
||||||
|
$this->addMatchTypes($matchTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add multiple routes at once from array in the following format:
|
||||||
|
*
|
||||||
|
* $routes = array(
|
||||||
|
* array($method, $route, $target, $name)
|
||||||
|
* );
|
||||||
|
*
|
||||||
|
* @param array $routes
|
||||||
|
* @return void
|
||||||
|
* @author Koen Punt
|
||||||
|
*/
|
||||||
|
public function addRoutes($routes){
|
||||||
|
if(!is_array($routes) && !$routes instanceof Traversable) {
|
||||||
|
throw new \Exception('Routes should be an array or an instance of Traversable');
|
||||||
|
}
|
||||||
|
foreach($routes as $route) {
|
||||||
|
call_user_func_array(array($this, 'map'), $route);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the base path.
|
||||||
|
* Useful if you are running your application from a subdirectory.
|
||||||
|
*/
|
||||||
|
public function setBasePath($basePath) {
|
||||||
|
$this->basePath = $basePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add named match types. It uses array_merge so keys can be overwritten.
|
||||||
|
*
|
||||||
|
* @param array $matchTypes The key is the name and the value is the regex.
|
||||||
|
*/
|
||||||
|
public function addMatchTypes($matchTypes) {
|
||||||
|
$this->matchTypes = array_merge($this->matchTypes, $matchTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map a route to a target
|
||||||
|
*
|
||||||
|
* @param string $method One of 4 HTTP Methods, or a pipe-separated list of multiple HTTP Methods (GET|POST|PUT|DELETE)
|
||||||
|
* @param string $route The route regex, custom regex must start with an @. You can use multiple pre-set regex filters, like [i:id]
|
||||||
|
* @param mixed $target The target where this route should point to. Can be anything.
|
||||||
|
* @param string $name Optional name of this route. Supply if you want to reverse route this url in your application.
|
||||||
|
*/
|
||||||
|
public function map($method, $route, $target, $name = null) {
|
||||||
|
|
||||||
|
$this->routes[] = array($method, $route, $target, $name);
|
||||||
|
|
||||||
|
if($name) {
|
||||||
|
if(isset($this->namedRoutes[$name])) {
|
||||||
|
throw new \Exception("Can not redeclare route '{$name}'");
|
||||||
|
} else {
|
||||||
|
$this->namedRoutes[$name] = $route;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reversed routing
|
||||||
|
*
|
||||||
|
* Generate the URL for a named route. Replace regexes with supplied parameters
|
||||||
|
*
|
||||||
|
* @param string $routeName The name of the route.
|
||||||
|
* @param array @params Associative array of parameters to replace placeholders with.
|
||||||
|
* @return string The URL of the route with named parameters in place.
|
||||||
|
*/
|
||||||
|
public function generate($routeName, array $params = array()) {
|
||||||
|
|
||||||
|
// Check if named route exists
|
||||||
|
if(!isset($this->namedRoutes[$routeName])) {
|
||||||
|
throw new \Exception("Route '{$routeName}' does not exist.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace named parameters
|
||||||
|
$route = $this->namedRoutes[$routeName];
|
||||||
|
|
||||||
|
// prepend base path to route url again
|
||||||
|
$url = $this->basePath . $route;
|
||||||
|
|
||||||
|
if (preg_match_all('`(/|\.|)\[([^:\]]*+)(?::([^:\]]*+))?\](\?|)`', $route, $matches, PREG_SET_ORDER)) {
|
||||||
|
|
||||||
|
foreach($matches as $match) {
|
||||||
|
list($block, $pre, $type, $param, $optional) = $match;
|
||||||
|
|
||||||
|
if ($pre) {
|
||||||
|
$block = substr($block, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($params[$param])) {
|
||||||
|
$url = str_replace($block, $params[$param], $url);
|
||||||
|
} elseif ($optional) {
|
||||||
|
$url = str_replace($pre . $block, '', $url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Match a given Request Url against stored routes
|
||||||
|
* @param string $requestUrl
|
||||||
|
* @param string $requestMethod
|
||||||
|
* @return array|boolean Array with route information on success, false on failure (no match).
|
||||||
|
*/
|
||||||
|
public function match($requestUrl = null, $requestMethod = null) {
|
||||||
|
|
||||||
|
$params = array();
|
||||||
|
$match = false;
|
||||||
|
|
||||||
|
// set Request Url if it isn't passed as parameter
|
||||||
|
if($requestUrl === null) {
|
||||||
|
$requestUrl = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
// strip base path from request url
|
||||||
|
$requestUrl = substr($requestUrl, strlen($this->basePath));
|
||||||
|
|
||||||
|
// Strip query string (?a=b) from Request Url
|
||||||
|
if (($strpos = strpos($requestUrl, '?')) !== false) {
|
||||||
|
$requestUrl = substr($requestUrl, 0, $strpos);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set Request Method if it isn't passed as a parameter
|
||||||
|
if($requestMethod === null) {
|
||||||
|
$requestMethod = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force request_order to be GP
|
||||||
|
// http://www.mail-archive.com/internals@lists.php.net/msg33119.html
|
||||||
|
$_REQUEST = array_merge($_GET, $_POST);
|
||||||
|
|
||||||
|
foreach($this->routes as $handler) {
|
||||||
|
list($method, $_route, $target, $name) = $handler;
|
||||||
|
|
||||||
|
$methods = explode('|', $method);
|
||||||
|
$method_match = false;
|
||||||
|
|
||||||
|
// Check if request method matches. If not, abandon early. (CHEAP)
|
||||||
|
foreach($methods as $method) {
|
||||||
|
if (strcasecmp($requestMethod, $method) === 0) {
|
||||||
|
$method_match = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method did not match, continue to next route.
|
||||||
|
if(!$method_match) continue;
|
||||||
|
|
||||||
|
// Check for a wildcard (matches all)
|
||||||
|
if ($_route === '*') {
|
||||||
|
$match = true;
|
||||||
|
} elseif (isset($_route[0]) && $_route[0] === '@') {
|
||||||
|
$match = preg_match('`' . substr($_route, 1) . '`u', $requestUrl, $params);
|
||||||
|
} else {
|
||||||
|
$route = null;
|
||||||
|
$regex = false;
|
||||||
|
$j = 0;
|
||||||
|
$n = isset($_route[0]) ? $_route[0] : null;
|
||||||
|
$i = 0;
|
||||||
|
|
||||||
|
// Find the longest non-regex substring and match it against the URI
|
||||||
|
while (true) {
|
||||||
|
if (!isset($_route[$i])) {
|
||||||
|
break;
|
||||||
|
} elseif (false === $regex) {
|
||||||
|
$c = $n;
|
||||||
|
$regex = $c === '[' || $c === '(' || $c === '.';
|
||||||
|
if (false === $regex && false !== isset($_route[$i+1])) {
|
||||||
|
$n = $_route[$i + 1];
|
||||||
|
$regex = $n === '?' || $n === '+' || $n === '*' || $n === '{';
|
||||||
|
}
|
||||||
|
if (false === $regex && $c !== '/' && (!isset($requestUrl[$j]) || $c !== $requestUrl[$j])) {
|
||||||
|
continue 2;
|
||||||
|
}
|
||||||
|
$j++;
|
||||||
|
}
|
||||||
|
$route .= $_route[$i++];
|
||||||
|
}
|
||||||
|
|
||||||
|
$regex = $this->compileRoute($route);
|
||||||
|
$match = preg_match($regex, $requestUrl, $params);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(($match == true || $match > 0)) {
|
||||||
|
|
||||||
|
if($params) {
|
||||||
|
foreach($params as $key => $value) {
|
||||||
|
if(is_numeric($key)) unset($params[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'target' => $target,
|
||||||
|
'params' => $params,
|
||||||
|
'name' => $name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compile the regex for a given route (EXPENSIVE)
|
||||||
|
*/
|
||||||
|
private function compileRoute($route) {
|
||||||
|
if (preg_match_all('`(/|\.|)\[([^:\]]*+)(?::([^:\]]*+))?\](\?|)`', $route, $matches, PREG_SET_ORDER)) {
|
||||||
|
|
||||||
|
$matchTypes = $this->matchTypes;
|
||||||
|
foreach($matches as $match) {
|
||||||
|
list($block, $pre, $type, $param, $optional) = $match;
|
||||||
|
|
||||||
|
if (isset($matchTypes[$type])) {
|
||||||
|
$type = $matchTypes[$type];
|
||||||
|
}
|
||||||
|
if ($pre === '.') {
|
||||||
|
$pre = '\.';
|
||||||
|
}
|
||||||
|
|
||||||
|
//Older versions of PCRE require the 'P' in (?P<named>)
|
||||||
|
$pattern = '(?:'
|
||||||
|
. ($pre !== '' ? $pre : null)
|
||||||
|
. '('
|
||||||
|
. ($param !== '' ? "?P<$param>" : null)
|
||||||
|
. $type
|
||||||
|
. '))'
|
||||||
|
. ($optional !== '' ? '?' : null);
|
||||||
|
|
||||||
|
$route = str_replace($block, $pattern, $route);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return "`^$route$`u";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,423 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require 'AltoRouter.php';
|
||||||
|
|
||||||
|
class AltoRouterDebug extends AltoRouter{
|
||||||
|
|
||||||
|
public function getNamedRoutes(){
|
||||||
|
return $this->namedRoutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRoutes(){
|
||||||
|
return $this->routes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBasePath(){
|
||||||
|
return $this->basePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class SimpleTraversable implements Iterator{
|
||||||
|
|
||||||
|
protected $_position = 0;
|
||||||
|
|
||||||
|
protected $_data = array(
|
||||||
|
array('GET', '/foo', 'foo_action', null),
|
||||||
|
array('POST', '/bar', 'bar_action', 'second_route')
|
||||||
|
);
|
||||||
|
|
||||||
|
public function current(){
|
||||||
|
return $this->_data[$this->_position];
|
||||||
|
}
|
||||||
|
public function key(){
|
||||||
|
return $this->_position;
|
||||||
|
}
|
||||||
|
public function next(){
|
||||||
|
++$this->_position;
|
||||||
|
}
|
||||||
|
public function rewind(){
|
||||||
|
$this->_position = 0;
|
||||||
|
}
|
||||||
|
public function valid(){
|
||||||
|
return isset($this->_data[$this->_position]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generated by PHPUnit_SkeletonGenerator 1.2.1 on 2013-07-14 at 17:47:46.
|
||||||
|
*/
|
||||||
|
class AltoRouterTest extends PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var AltoRouter
|
||||||
|
*/
|
||||||
|
protected $router;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up the fixture, for example, opens a network connection.
|
||||||
|
* This method is called before a test is executed.
|
||||||
|
*/
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
$this->router = new AltoRouterDebug;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tears down the fixture, for example, closes a network connection.
|
||||||
|
* This method is called after a test is executed.
|
||||||
|
*/
|
||||||
|
protected function tearDown()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers AltoRouter::addRoutes
|
||||||
|
*/
|
||||||
|
public function testAddRoutes()
|
||||||
|
{
|
||||||
|
$method = 'POST';
|
||||||
|
$route = '/[:controller]/[:action]';
|
||||||
|
$target = function(){};
|
||||||
|
|
||||||
|
$this->router->addRoutes(array(
|
||||||
|
array($method, $route, $target),
|
||||||
|
array($method, $route, $target, 'second_route')
|
||||||
|
));
|
||||||
|
|
||||||
|
$routes = $this->router->getRoutes();
|
||||||
|
|
||||||
|
$this->assertEquals(array($method, $route, $target, null), $routes[0]);
|
||||||
|
$this->assertEquals(array($method, $route, $target, 'second_route'), $routes[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers AltoRouter::addRoutes
|
||||||
|
*/
|
||||||
|
public function testAddRoutesAcceptsTraverable()
|
||||||
|
{
|
||||||
|
$traversable = new SimpleTraversable();
|
||||||
|
$this->router->addRoutes($traversable);
|
||||||
|
|
||||||
|
$traversable->rewind();
|
||||||
|
|
||||||
|
$first = $traversable->current();
|
||||||
|
$traversable->next();
|
||||||
|
$second = $traversable->current();
|
||||||
|
|
||||||
|
$routes = $this->router->getRoutes();
|
||||||
|
|
||||||
|
$this->assertEquals($first, $routes[0]);
|
||||||
|
$this->assertEquals($second, $routes[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers AltoRouter::addRoutes
|
||||||
|
* @expectedException Exception
|
||||||
|
*/
|
||||||
|
public function testAddRoutesThrowsExceptionOnInvalidArgument()
|
||||||
|
{
|
||||||
|
$this->router->addRoutes(new stdClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers AltoRouter::setBasePath
|
||||||
|
*/
|
||||||
|
public function testSetBasePath()
|
||||||
|
{
|
||||||
|
$basePath = $this->router->setBasePath('/some/path');
|
||||||
|
$this->assertEquals('/some/path', $this->router->getBasePath());
|
||||||
|
|
||||||
|
$basePath = $this->router->setBasePath('/some/path');
|
||||||
|
$this->assertEquals('/some/path', $this->router->getBasePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers AltoRouter::map
|
||||||
|
*/
|
||||||
|
public function testMap()
|
||||||
|
{
|
||||||
|
$method = 'POST';
|
||||||
|
$route = '/[:controller]/[:action]';
|
||||||
|
$target = function(){};
|
||||||
|
|
||||||
|
$this->router->map($method, $route, $target);
|
||||||
|
|
||||||
|
$routes = $this->router->getRoutes();
|
||||||
|
|
||||||
|
$this->assertEquals(array($method, $route, $target, null), $routes[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers AltoRouter::map
|
||||||
|
*/
|
||||||
|
public function testMapWithName()
|
||||||
|
{
|
||||||
|
$method = 'POST';
|
||||||
|
$route = '/[:controller]/[:action]';
|
||||||
|
$target = function(){};
|
||||||
|
$name = 'myroute';
|
||||||
|
|
||||||
|
$this->router->map($method, $route, $target, $name);
|
||||||
|
|
||||||
|
$routes = $this->router->getRoutes();
|
||||||
|
$this->assertEquals(array($method, $route, $target, $name), $routes[0]);
|
||||||
|
|
||||||
|
$named_routes = $this->router->getNamedRoutes();
|
||||||
|
$this->assertEquals($route, $named_routes[$name]);
|
||||||
|
|
||||||
|
try{
|
||||||
|
$this->router->map($method, $route, $target, $name);
|
||||||
|
$this->fail('Should not be able to add existing named route');
|
||||||
|
}catch(Exception $e){
|
||||||
|
$this->assertEquals("Can not redeclare route '{$name}'", $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers AltoRouter::generate
|
||||||
|
*/
|
||||||
|
public function testGenerate()
|
||||||
|
{
|
||||||
|
$params = array(
|
||||||
|
'controller' => 'test',
|
||||||
|
'action' => 'someaction'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->router->map('GET', '/[:controller]/[:action]', function(){}, 'foo_route');
|
||||||
|
|
||||||
|
$this->assertEquals('/test/someaction',
|
||||||
|
$this->router->generate('foo_route', $params));
|
||||||
|
|
||||||
|
$params = array(
|
||||||
|
'controller' => 'test',
|
||||||
|
'action' => 'someaction',
|
||||||
|
'type' => 'json'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals('/test/someaction',
|
||||||
|
$this->router->generate('foo_route', $params));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGenerateWithOptionalUrlParts()
|
||||||
|
{
|
||||||
|
$this->router->map('GET', '/[:controller]/[:action].[:type]?', function(){}, 'bar_route');
|
||||||
|
|
||||||
|
$params = array(
|
||||||
|
'controller' => 'test',
|
||||||
|
'action' => 'someaction'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals('/test/someaction',
|
||||||
|
$this->router->generate('bar_route', $params));
|
||||||
|
|
||||||
|
$params = array(
|
||||||
|
'controller' => 'test',
|
||||||
|
'action' => 'someaction',
|
||||||
|
'type' => 'json'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals('/test/someaction.json',
|
||||||
|
$this->router->generate('bar_route', $params));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGenerateWithNonexistingRoute()
|
||||||
|
{
|
||||||
|
try{
|
||||||
|
$this->router->generate('nonexisting_route');
|
||||||
|
$this->fail('Should trigger an exception on nonexisting named route');
|
||||||
|
}catch(Exception $e){
|
||||||
|
$this->assertEquals("Route 'nonexisting_route' does not exist.", $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers AltoRouter::match
|
||||||
|
* @covers AltoRouter::compileRoute
|
||||||
|
*/
|
||||||
|
public function testMatch()
|
||||||
|
{
|
||||||
|
$this->router->map('GET', '/foo/[:controller]/[:action]', 'foo_action', 'foo_route');
|
||||||
|
|
||||||
|
$this->assertEquals(array(
|
||||||
|
'target' => 'foo_action',
|
||||||
|
'params' => array(
|
||||||
|
'controller' => 'test',
|
||||||
|
'action' => 'do'
|
||||||
|
),
|
||||||
|
'name' => 'foo_route'
|
||||||
|
), $this->router->match('/foo/test/do', 'GET'));
|
||||||
|
|
||||||
|
$this->assertFalse($this->router->match('/foo/test/do', 'POST'));
|
||||||
|
|
||||||
|
$this->assertEquals(array(
|
||||||
|
'target' => 'foo_action',
|
||||||
|
'params' => array(
|
||||||
|
'controller' => 'test',
|
||||||
|
'action' => 'do'
|
||||||
|
),
|
||||||
|
'name' => 'foo_route'
|
||||||
|
), $this->router->match('/foo/test/do?param=value', 'GET'));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMatchWithFixedParamValues()
|
||||||
|
{
|
||||||
|
$this->router->map('POST','/users/[i:id]/[delete|update:action]', 'usersController#doAction', 'users_do');
|
||||||
|
|
||||||
|
$this->assertEquals(array(
|
||||||
|
'target' => 'usersController#doAction',
|
||||||
|
'params' => array(
|
||||||
|
'id' => 1,
|
||||||
|
'action' => 'delete'
|
||||||
|
),
|
||||||
|
'name' => 'users_do'
|
||||||
|
), $this->router->match('/users/1/delete', 'POST'));
|
||||||
|
|
||||||
|
$this->assertFalse($this->router->match('/users/1/delete', 'GET'));
|
||||||
|
$this->assertFalse($this->router->match('/users/abc/delete', 'POST'));
|
||||||
|
$this->assertFalse($this->router->match('/users/1/create', 'GET'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMatchWithServerVars()
|
||||||
|
{
|
||||||
|
$this->router->map('GET', '/foo/[:controller]/[:action]', 'foo_action', 'foo_route');
|
||||||
|
|
||||||
|
$_SERVER['REQUEST_URI'] = '/foo/test/do';
|
||||||
|
$_SERVER['REQUEST_METHOD'] = 'GET';
|
||||||
|
|
||||||
|
$this->assertEquals(array(
|
||||||
|
'target' => 'foo_action',
|
||||||
|
'params' => array(
|
||||||
|
'controller' => 'test',
|
||||||
|
'action' => 'do'
|
||||||
|
),
|
||||||
|
'name' => 'foo_route'
|
||||||
|
), $this->router->match());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMatchWithOptionalUrlParts()
|
||||||
|
{
|
||||||
|
$this->router->map('GET', '/bar/[:controller]/[:action].[:type]?', 'bar_action', 'bar_route');
|
||||||
|
|
||||||
|
$this->assertEquals(array(
|
||||||
|
'target' => 'bar_action',
|
||||||
|
'params' => array(
|
||||||
|
'controller' => 'test',
|
||||||
|
'action' => 'do',
|
||||||
|
'type' => 'json'
|
||||||
|
),
|
||||||
|
'name' => 'bar_route'
|
||||||
|
), $this->router->match('/bar/test/do.json', 'GET'));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMatchWithWildcard()
|
||||||
|
{
|
||||||
|
$this->router->map('GET', '/a', 'foo_action', 'foo_route');
|
||||||
|
$this->router->map('GET', '*', 'bar_action', 'bar_route');
|
||||||
|
|
||||||
|
$this->assertEquals(array(
|
||||||
|
'target' => 'bar_action',
|
||||||
|
'params' => array(),
|
||||||
|
'name' => 'bar_route'
|
||||||
|
), $this->router->match('/everything', 'GET'));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMatchWithCustomRegexp()
|
||||||
|
{
|
||||||
|
$this->router->map('GET', '@^/[a-z]*$', 'bar_action', 'bar_route');
|
||||||
|
|
||||||
|
$this->assertEquals(array(
|
||||||
|
'target' => 'bar_action',
|
||||||
|
'params' => array(),
|
||||||
|
'name' => 'bar_route'
|
||||||
|
), $this->router->match('/everything', 'GET'));
|
||||||
|
|
||||||
|
$this->assertFalse($this->router->match('/some-other-thing', 'GET'));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMatchWithUnicodeRegex()
|
||||||
|
{
|
||||||
|
$pattern = '/(?<path>[^';
|
||||||
|
// Arabic characters
|
||||||
|
$pattern .= '\x{0600}-\x{06FF}';
|
||||||
|
$pattern .= '\x{FB50}-\x{FDFD}';
|
||||||
|
$pattern .= '\x{FE70}-\x{FEFF}';
|
||||||
|
$pattern .= '\x{0750}-\x{077F}';
|
||||||
|
// Alphanumeric, /, _, - and space characters
|
||||||
|
$pattern .= 'a-zA-Z0-9\/_-\s';
|
||||||
|
// 'ZERO WIDTH NON-JOINER'
|
||||||
|
$pattern .= '\x{200C}';
|
||||||
|
$pattern .= ']+)';
|
||||||
|
|
||||||
|
$this->router->map('GET', '@' . $pattern, 'unicode_action', 'unicode_route');
|
||||||
|
|
||||||
|
$this->assertEquals(array(
|
||||||
|
'target' => 'unicode_action',
|
||||||
|
'name' => 'unicode_route',
|
||||||
|
'params' => array(
|
||||||
|
'path' => '大家好'
|
||||||
|
)
|
||||||
|
), $this->router->match('/大家好', 'GET'));
|
||||||
|
|
||||||
|
$this->assertFalse($this->router->match('/﷽', 'GET'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers AltoRouter::addMatchTypes
|
||||||
|
*/
|
||||||
|
public function testMatchWithCustomNamedRegex()
|
||||||
|
{
|
||||||
|
$this->router->addMatchTypes(array('cId' => '[a-zA-Z]{2}[0-9](?:_[0-9]++)?'));
|
||||||
|
$this->router->map('GET', '/bar/[cId:customId]', 'bar_action', 'bar_route');
|
||||||
|
|
||||||
|
$this->assertEquals(array(
|
||||||
|
'target' => 'bar_action',
|
||||||
|
'params' => array(
|
||||||
|
'customId' => 'AB1',
|
||||||
|
),
|
||||||
|
'name' => 'bar_route'
|
||||||
|
), $this->router->match('/bar/AB1', 'GET'));
|
||||||
|
|
||||||
|
$this->assertEquals(array(
|
||||||
|
'target' => 'bar_action',
|
||||||
|
'params' => array(
|
||||||
|
'customId' => 'AB1_0123456789',
|
||||||
|
),
|
||||||
|
'name' => 'bar_route'
|
||||||
|
), $this->router->match('/bar/AB1_0123456789', 'GET'));
|
||||||
|
|
||||||
|
$this->assertFalse($this->router->match('/some-other-thing', 'GET'));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMatchWithCustomNamedUnicodeRegex()
|
||||||
|
{
|
||||||
|
$pattern = '[^';
|
||||||
|
// Arabic characters
|
||||||
|
$pattern .= '\x{0600}-\x{06FF}';
|
||||||
|
$pattern .= '\x{FB50}-\x{FDFD}';
|
||||||
|
$pattern .= '\x{FE70}-\x{FEFF}';
|
||||||
|
$pattern .= '\x{0750}-\x{077F}';
|
||||||
|
$pattern .= ']+';
|
||||||
|
|
||||||
|
$this->router->addMatchTypes(array('nonArabic' => $pattern));
|
||||||
|
$this->router->map('GET', '/bar/[nonArabic:string]', 'non_arabic_action', 'non_arabic_route');
|
||||||
|
|
||||||
|
$this->assertEquals(array(
|
||||||
|
'target' => 'non_arabic_action',
|
||||||
|
'name' => 'non_arabic_route',
|
||||||
|
'params' => array(
|
||||||
|
'string' => 'some-path'
|
||||||
|
)
|
||||||
|
), $this->router->match('/bar/some-path', 'GET'));
|
||||||
|
|
||||||
|
$this->assertFalse($this->router->match('/﷽', 'GET'));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
# AltoRouter [](http://travis-ci.org/dannyvankooten/AltoRouter)
|
||||||
|
AltoRouter is a small but powerful routing class for PHP 5.3+, heavily inspired by [klein.php](https://github.com/chriso/klein.php/).
|
||||||
|
|
||||||
|
* Dynamic routing with named parameters
|
||||||
|
* Reversed routing
|
||||||
|
* Flexible regular expression routing (inspired by [Sinatra](http://www.sinatrarb.com/))
|
||||||
|
* Custom regexes
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
1. PHP 5.3.x is required
|
||||||
|
2. Install AltoRouter using Composer or manually
|
||||||
|
2. Setup URL rewriting so that all requests are handled by **index.php**
|
||||||
|
3. Create an instance of AltoRouter, map your routes and match a request.
|
||||||
|
4. Have a look at the basic example in the `examples` directory for a better understanding on how to use AltoRouter.
|
||||||
|
|
||||||
|
## Routing
|
||||||
|
```php
|
||||||
|
$router = new AltoRouter();
|
||||||
|
$router->setBasePath('/AltoRouter'); // (optional) the subdir AltoRouter lives in
|
||||||
|
|
||||||
|
// mapping routes
|
||||||
|
$router->map('GET|POST','/', 'home#index', 'home');
|
||||||
|
$router->map('GET','/users', array('c' => 'UserController', 'a' => 'ListAction'));
|
||||||
|
$router->map('GET','/users/[i:id]', 'users#show', 'users_show');
|
||||||
|
$router->map('POST','/users/[i:id]/[delete|update:action]', 'usersController#doAction', 'users_do');
|
||||||
|
|
||||||
|
// reversed routing
|
||||||
|
$router->generate('users_show', array('id' => 5));
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
**You can use the following limits on your named parameters. AltoRouter will create the correct regexes for you.**
|
||||||
|
|
||||||
|
```php
|
||||||
|
* // Match all request URIs
|
||||||
|
[i] // Match an integer
|
||||||
|
[i:id] // Match an integer as 'id'
|
||||||
|
[a:action] // Match alphanumeric characters as 'action'
|
||||||
|
[h:key] // Match hexadecimal characters as 'key'
|
||||||
|
[:action] // Match anything up to the next / or end of the URI as 'action'
|
||||||
|
[create|edit:action] // Match either 'create' or 'edit' as 'action'
|
||||||
|
[*] // Catch all (lazy, stops at the next trailing slash)
|
||||||
|
[*:trailing] // Catch all as 'trailing' (lazy)
|
||||||
|
[**:trailing] // Catch all (possessive - will match the rest of the URI)
|
||||||
|
.[:format]? // Match an optional parameter 'format' - a / or . before the block is also optional
|
||||||
|
```
|
||||||
|
|
||||||
|
**Some more complicated examples**
|
||||||
|
|
||||||
|
```php
|
||||||
|
@/(?[A-Za-z]{2}_[A-Za-z]{2})$ // custom regex, matches language codes like "en_us" etc.
|
||||||
|
/posts/[*:title][i:id] // Matches "/posts/this-is-a-title-123"
|
||||||
|
/output.[xml|json:format]? // Matches "/output", "output.xml", "output.json"
|
||||||
|
/[:controller]?/[:action]? // Matches the typical /controller/action format
|
||||||
|
```
|
||||||
|
|
||||||
|
**The character before the colon (the 'match type') is a shortcut for one of the following regular expressions**
|
||||||
|
|
||||||
|
```php
|
||||||
|
'i' => '[0-9]++'
|
||||||
|
'a' => '[0-9A-Za-z]++'
|
||||||
|
'h' => '[0-9A-Fa-f]++'
|
||||||
|
'*' => '.+?'
|
||||||
|
'**' => '.++'
|
||||||
|
'' => '[^/\.]++'
|
||||||
|
```
|
||||||
|
|
||||||
|
**New match types can be added using the `addMatchTypes()` method**
|
||||||
|
|
||||||
|
```php
|
||||||
|
$router->addMatchTypes(array('cId' => '[a-zA-Z]{2}[0-9](?:_[0-9]++)?'));
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
- [Danny van Kooten](https://github.com/dannyvankooten)
|
||||||
|
- [Koen Punt](https://github.com/koenpunt)
|
||||||
|
- [John Long](https://github.com/adduc)
|
||||||
|
- [Niahoo Osef](https://github.com/niahoo)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
(MIT License)
|
||||||
|
|
||||||
|
Copyright (c) 2012-2013 Danny van Kooten <hi@dannyvankooten.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"name": "altorouter/altorouter",
|
||||||
|
"description": "A lightning fast router for PHP",
|
||||||
|
"keywords": ["router", "routing", "lightweight"],
|
||||||
|
"homepage": "https://github.com/dannyvankooten/AltoRouter",
|
||||||
|
"license": "MIT",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Danny van Kooten",
|
||||||
|
"email": "dannyvankooten@gmail.com",
|
||||||
|
"homepage": "http://dannyvankooten.com/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Koen Punt",
|
||||||
|
"homepage": "https://github.com/koenpunt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "niahoo",
|
||||||
|
"homepage": "https://github.com/niahoo"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.3.0"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"classmap": ["AltoRouter.php"]
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
RewriteEngine On
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteRule . index.php [L]
|
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require '../../AltoRouter.php';
|
||||||
|
|
||||||
|
$router = new AltoRouter();
|
||||||
|
$router->setBasePath('/AltoRouter/examples/basic');
|
||||||
|
$router->map('GET|POST','/', 'home#index', 'home');
|
||||||
|
$router->map('GET','/users/', array('c' => 'UserController', 'a' => 'ListAction'));
|
||||||
|
$router->map('GET','/users/[i:id]', 'users#show', 'users_show');
|
||||||
|
$router->map('POST','/users/[i:id]/[delete|update:action]', 'usersController#doAction', 'users_do');
|
||||||
|
|
||||||
|
// match current request
|
||||||
|
$match = $router->match();
|
||||||
|
?>
|
||||||
|
<h1>AltoRouter</h1>
|
||||||
|
|
||||||
|
<h3>Current request: </h3>
|
||||||
|
<pre>
|
||||||
|
Target: <?php var_dump($match['target']); ?>
|
||||||
|
Params: <?php var_dump($match['params']); ?>
|
||||||
|
Name: <?php var_dump($match['name']); ?>
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<h3>Try these requests: </h3>
|
||||||
|
<p><a href="<?php echo $router->generate('home'); ?>">GET <?php echo $router->generate('home'); ?></a></p>
|
||||||
|
<p><a href="<?php echo $router->generate('users_show', array('id' => 5)); ?>">GET <?php echo $router->generate('users_show', array('id' => 5)); ?></a></p>
|
||||||
|
<p><form action="<?php echo $router->generate('users_do', array('id' => 10, 'action' => 'update')); ?>" method="post"><button type="submit"><?php echo $router->generate('users_do', array('id' => 10, 'action' => 'update')); ?></button></form></p>
|
Loading…
Reference in new issue