tmp
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
parent
153418181e
commit
0e5e671423
After Width: | Height: | Size: 81 KiB |
@ -1,9 +1,30 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
require_once __DIR__ . '/../config/config.php';
|
||||
if (APP_ENV === 'console') {
|
||||
require_once __DIR__ . '/../src/console/Console.php';
|
||||
}
|
||||
elseif (APP_ENV === 'development') {
|
||||
require_once __DIR__ . 'index.html';
|
||||
// turn the if in obj mode
|
||||
// if (APP_ENV === 'console') {
|
||||
// require_once __DIR__ . '/../src/console/Console.php';
|
||||
// }
|
||||
// elseif (APP_ENV === 'development') {
|
||||
// on pourait aussi gérer le port sois ici comme dans express sois comme dans un fichier de config json...
|
||||
$appFactory = new AppCreator();
|
||||
// builder.Services.AddScoped<AuthMiddlewareFliter>();
|
||||
$app = $appFactory->registerService('','');
|
||||
|
||||
$appFactory.errorProvider(class:: or port)
|
||||
|
||||
// connexion string
|
||||
|
||||
// var connectionString = builder.Configuration.GetConnectionString("LolDatabase");
|
||||
// builder.Services.AddDbContext<LolDbContext>(options =>
|
||||
// options.UseSqlite(connectionString), ServiceLifetime.Singleton);
|
||||
|
||||
$app->use(new LoggingMiddleware());
|
||||
$app = $appFactory->create();
|
||||
$app.addHttpClient(HttpClient::class)
|
||||
|
||||
// je veux pas faire sa pour load les controller avec les anotation
|
||||
$app->RegisterControllers();
|
||||
$app->
|
||||
$app->run();
|
||||
}
|
||||
|
@ -0,0 +1,84 @@
|
||||
<?
|
||||
|
||||
class App {
|
||||
private $appName;
|
||||
private $version;
|
||||
|
||||
private IHttpMiddleware $middlewarePipeline;
|
||||
|
||||
private DiContainer $container;
|
||||
|
||||
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() {
|
||||
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;
|
||||
// }
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
class AppCreator {
|
||||
public function __construct() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -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);
|
||||
|
||||
// You can add error handling here if needed
|
||||
|
||||
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,45 @@
|
||||
<?php
|
||||
namespace App\Controllers;
|
||||
|
||||
class AthleteController extends BaseController
|
||||
{
|
||||
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,101 @@
|
||||
<?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}.
|
||||
*/
|
||||
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__);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function callAction($method, $parameters)
|
||||
{
|
||||
return $this->{$method}(...array_values($parameters));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
// App etre sur que la persone a le droit defaire
|
||||
class FrontController {
|
||||
private $router;
|
||||
|
||||
public function __construct(Router $router) {
|
||||
$this->router = $router;
|
||||
}
|
||||
|
||||
public function dispatch(IRequest $request) {
|
||||
$match = $this->router->match($request);
|
||||
|
||||
if ($match) {
|
||||
$controllerName = $match['controller'];
|
||||
$actionName = $match['action'];
|
||||
|
||||
// Utilisez l'injection de dépendances pour créer le contrôleur
|
||||
$controller = $this->createController($controllerName);
|
||||
|
||||
if ($controller) {
|
||||
// Appeler l'action correspondante
|
||||
$controller->$actionName();
|
||||
} 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 createController($controllerName) {
|
||||
// Utilisez un conteneur d'injection de dépendances pour créer le contrôleur
|
||||
return DependencyContainer::create($controllerName);
|
||||
}
|
||||
|
||||
private function handleError() {// composant twig
|
||||
header("HTTP/1.0 404 Not Found");
|
||||
echo "Page not found";
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
<!--
|
||||
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,22 @@
|
||||
<?php
|
||||
|
||||
class Route
|
||||
{
|
||||
|
||||
private string $name;
|
||||
|
||||
private array $parrams;
|
||||
|
||||
private $callable;
|
||||
|
||||
public function __construct(array $params, callable $callable, string $name = null)
|
||||
{
|
||||
$this->path = $params;
|
||||
$this->callable = $callable;
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
<!-- 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
|
||||
|
||||
// Just a url matcher
|
||||
|
||||
class Router {
|
||||
|
||||
private string $path;
|
||||
|
||||
// routes collection
|
||||
private AltoRouter $routes;
|
||||
|
||||
// public static $verbs = ['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'];
|
||||
|
||||
public function __construct(string $path = "/PHP/project/index.php") {
|
||||
$this->path = $path;
|
||||
$this->routes = new AltoRouter($this->$path);
|
||||
}
|
||||
|
||||
public function add(Route $route, $name) {}
|
||||
|
||||
// extrait également les paramètres d'URL de l'URL demandée
|
||||
|
||||
public function extractParams(string $path) {}
|
||||
|
||||
public function get(string $path, callable $callable, $name) {
|
||||
$this->router->map('GET', $path, $callable, $name);
|
||||
}
|
||||
|
||||
public function post(string $path, callable $callable, $name) {
|
||||
$this->router->map('POST', $path, $callable, $name);
|
||||
}
|
||||
public function put(string $path, callable $callable, $name) {
|
||||
$this->router->map('PUT', $path, $callable, $name);
|
||||
}
|
||||
|
||||
public function match (IRequest $request): ?Route {
|
||||
$result = $this->routes->match($request->getRequestUri(), $request->getMethod());
|
||||
if ($result) {
|
||||
return new Route($result['params'],$result['target'],$result['name']) ;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -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,36 @@
|
||||
<?php
|
||||
|
||||
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,5 @@
|
||||
<?php
|
||||
interface IHttpMiddleware {
|
||||
public function handle(IRequest $request, callable $next);
|
||||
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
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,19 @@
|
||||
<?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.
|
||||
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,5 @@
|
||||
<?php
|
||||
|
||||
interface ContentStrategy {
|
||||
public function getContent(): array;
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
// 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,8 @@
|
||||
<?php
|
||||
|
||||
|
||||
class FormContentStrategy implements ContentStrategy {
|
||||
public function getContent(): array {
|
||||
return $_POST;
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
|
||||
interface IRequest
|
||||
{
|
||||
public function getRequestUri();
|
||||
public function getHeaders();
|
||||
public function getMethod();
|
||||
public function getQueryParameters(): array;
|
||||
public function getRequestParameters(): array;
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
class JsonContentStrategy implements ContentStrategy {
|
||||
public function getContent(): array {
|
||||
$rawContent = file_get_contents('php://input');
|
||||
return json_decode($rawContent, true) ?? [];
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
class HttpRequest implements IRequest {
|
||||
private $queryParameters;
|
||||
private $requestParameters;
|
||||
private $method;
|
||||
private $requestUri;
|
||||
private $headers;
|
||||
|
||||
public function __construct(
|
||||
array $query,
|
||||
array $server,
|
||||
array $headers,
|
||||
ContentStrategy $contentStrategy
|
||||
) {
|
||||
$this->queryParameters = $query;
|
||||
$this->requestUri = $server['REQUEST_URI'] ?? '';
|
||||
$this->method = strtoupper($server['REQUEST_METHOD'] ?? 'GET');
|
||||
$this->headers = $headers;
|
||||
$this->requestParameters = $contentStrategy->getContent();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
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,5 @@
|
||||
<?php
|
||||
interface FieldInterface {
|
||||
public function render();
|
||||
public function validate($value);
|
||||
}
|
@ -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,57 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Silex\Security;
|
||||
|
||||
use Silex\Gateway\UserGateway;
|
||||
use Silex\Model\User;
|
||||
|
||||
|
||||
class Security
|
||||
{
|
||||
const tokenSession = 'tokenSession';
|
||||
private array $session;
|
||||
private UserGateway $userGateway;
|
||||
private ?User $user = null;
|
||||
|
||||
public function __construct(UserGateway $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;
|
||||
}
|
||||
}
|
@ -1,8 +1,11 @@
|
||||
<?php
|
||||
namespace Model;
|
||||
|
||||
|
||||
class Coach extends Role {
|
||||
// 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,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