From 55beea56d08a6373d1188f67544aadc3ab21b736 Mon Sep 17 00:00:00 2001 From: dave Date: Fri, 29 Sep 2023 09:41:33 +0200 Subject: [PATCH] first push for test | try to create archi --- .drone.yml | 114 +++++++ .gitignore | 24 ++ Documents/Images/Gitflow.png | Bin 0 -> 28459 bytes README.md | 93 ++++++ Sources/.dockerignore | 3 + Sources/.env.test | 0 Sources/composer.json | 0 Sources/config/Dockerfile | 17 + Sources/config/config.php | 11 + Sources/index.php | 0 .../src/core/network/service/AuthService.php | 0 .../src/core/network/service/IAuthService.php | 0 Sources/src/core/stub/ActivitiesManager.php | 0 Sources/src/core/stub/StubData.php | 1 + Sources/src/core/stub/UserManager.php | 8 + Sources/src/shared/router/AltoRouter.php | 302 ++++++++++++++++++ Sources/src/shared/router/Router.php | 87 +++++ Sources/src/utils/SplClassLoader.php | 208 ++++++++++++ Sources/src/utils/Validation.php | 109 +++++++ notify.sh | 11 + 20 files changed, 988 insertions(+) create mode 100644 .drone.yml create mode 100644 .gitignore create mode 100644 Documents/Images/Gitflow.png create mode 100644 README.md create mode 100644 Sources/.dockerignore create mode 100644 Sources/.env.test create mode 100644 Sources/composer.json create mode 100644 Sources/config/Dockerfile create mode 100644 Sources/config/config.php create mode 100644 Sources/index.php create mode 100644 Sources/src/core/network/service/AuthService.php create mode 100644 Sources/src/core/network/service/IAuthService.php create mode 100644 Sources/src/core/stub/ActivitiesManager.php create mode 100644 Sources/src/core/stub/StubData.php create mode 100644 Sources/src/core/stub/UserManager.php create mode 100644 Sources/src/shared/router/AltoRouter.php create mode 100644 Sources/src/shared/router/Router.php create mode 100644 Sources/src/utils/SplClassLoader.php create mode 100644 Sources/src/utils/Validation.php create mode 100644 notify.sh diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 00000000..53acd087 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,114 @@ +kind: pipeline +type: docker +name: HeartWave + +# dev is DMZ + +trigger: + event: + - push + +steps: + - name: test + image: php:7.4 + commands: + - cd Sources + # Installe les dépendances PHP si nécessaire + - composer install + # - composer require phpunit/phpunit + - vendor/bin/phpunit common/Tests + + # build CONTAINER for app-build on flutter IMAGE + - name: docker-build + build: Sources/src/config + ports: + - "8080:80" + volumes: + - ./php/vhosts:/etc/apache2/sites-enabled + - ./:/var/www + restart: always + + - name: code-analysis + image: ##### + environment: + SONAR_TOKEN: + from_secret: SONAR_TOKEN + commands: + - export SONAR_SCANNER_VERSION=4.7.0.2747 + - export SONAR_SCANNER_HOME=$HOME/.sonar/sonar-scanner-$SONAR_SCANNER_VERSION-linux + - curl --create-dirs -sSLo $HOME/.sonar/sonar-scanner.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$SONAR_SCANNER_VERSION-linux.zip + - unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/ + - export PATH=$SONAR_SCANNER_HOME/bin:$PATH + - export SONAR_SCANNER_OPTS="-server" + - sonar-scanner -D sonar.projectKey=Bowl_in -D sonar.sources=./Sources/bowlin_project -D sonar.host.url=https://codefirst.iut.uca.fr/sonar -D sonar.flutter.coverage.reportPath=./Sources/bowlin_project/coverage/lcov.info + depends_on: [ test ] + + + # database container deployment + - name: container-mysql + image: hub.codefirst.iut.uca.fr/thomas.bellembois/codefirst-dockerproxy-clientdrone:latest + volumes: + - db-data:/var/lib/mysql + environment: + IMAGENAME: mariadb:10 + CONTAINERNAME: mysql + COMMAND: create + # OVERWRITE: false + # should be true + PRIVATE: false + CODEFIRST_CLIENTDRONE_ENV_MARIADB_ROOT_PASSWORD: + from_secret: db_root_password + CODEFIRST_CLIENTDRONE_ENV_MARIADB_DATABASE: + from_secret: db_database + CODEFIRST_CLIENTDRONE_ENV_MARIADB_USER: + from_secret: db_user + CODEFIRST_CLIENTDRONE_ENV_MARIADB_PASSWORD: + from_secret: db_password + ADMINS: antoineperederii,antoinepinagot,kevinmonteiro,paullevrault,davidd_almeida + + - name: phpmyadmin-container + # should find a goog version + image: phpmyadmin + restart: always + ports: + - 8082:80 + environment: + PMA_HOST: container-mysql + depends_on: + -container-mysql + networks: + - admin + + + - name: docker-push + image: plugins/docker + settings: + username: + from_secret: DOCKER_USERNAME + password: + from_secret: DOCKER_PASSWORD + repo: myusername/my-php-app + tags: latest + auto_tag: true + registry: docker.io + + - name: deploy-container + image: docker + commands: + - docker stop my-php-container || true + - docker rm my-php-container || true + - docker run -d --name my-php-container -p 80:80 myusername/my-php-app + - name: notify + image: ruby:2.1 + rules: + - if: "$CI_COMMIT_TAG =~ /^.*-demo$/" + when: on_success + script: + - sh ./notifymail.sh + +volumes: + db-data: + +networks: + admin: + diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..becd7966 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +.idea +node_modules +.vscode +*.swp +*.swo +.env +# Cache files for Sublime Text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache + +# Workspace files are user-specific +*.sublime-workspace + +# Project files should be checked into the repository, unless a significant +# proportion of contributors will probably not be using Sublime Text +*.sublime-project + +# SFTP configuration file +sftp-config.json +sftp-config-alt*.json + +*.log* +coverage/ diff --git a/Documents/Images/Gitflow.png b/Documents/Images/Gitflow.png new file mode 100644 index 0000000000000000000000000000000000000000..b420e7ee24c9a9d0466f48826351e8881b219786 GIT binary patch literal 28459 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 z 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 literal 0 HcmV?d00001 diff --git a/README.md b/README.md new file mode 100644 index 00000000..ad14a470 --- /dev/null +++ b/README.md @@ -0,0 +1,93 @@ +# HeartTrack + +## Présentation + +**Nom de l'application :** HeartTrack + +### Contexte + +HeartTrack est une application web PHP et mobile Android destinée aux sportifs pour l'analyse de courbes cardiaques. L'objectif principal de cette application est de récupérer les données de fréquence cardiaque à partir d'une montre, de les afficher sous forme de courbes, d'identifier des patterns, de fournir des statistiques et de réaliser des prédictions liées à l'effort physique, à la chaleur, à la récupération, etc. + +## Récapitulatif du Projet + +Le projet HeartTrack, avec son application HeartTrack, vise à offrir une solution complète pour l'analyse des données de fréquence cardiaque, en mettant l'accent sur les besoins des sportifs. L'application sera capable de traiter et d'interpréter les données de manière intelligente, fournissant ainsi des informations précieuses pour optimiser les performances sportives et la santé. + +## Répartition du Git + +[**Sources**](Sources) : **Code de l'application** + +[**Documents**](Documents) : **Documentation de l'application** + +-- + + + +Le projet HeartTrack utilise un modèle de flux de travail Git (Gitflow) pour organiser le développement. Voici une brève explication des principales branches : + +- **branche prod** : Cette branche contient la version de production stable de l'application. Les modifications sur cette branche sont généralement destinées à des mises en production. + +- **branche master** : La branche master est similaire à la branche de production, mais elle peut contenir des fonctionnalités en cours de développement qui sont presque prêtes pour une mise en production. + +- **branche test** : Cette branche est utilisée pour déployer une version démo de l'application. Elle est mise à jour avec les dernières fonctionnalités et surtout la totalité de leurs test en développement. + +- **branche issue** : Pour chaque problème (issue) que vous résolvez, vous devez créer une branche portant le nom de l'issue, par exemple, "issue_#32_nom" où 32 est le numéro de l'issue et nom est une description courte de l'issue. Une fois l'issue résolue, assurez-vous de mettre à jour le changelog et de créer une merge request. + + +## Développement + +### Travailler sur une Issue + +Si vous êtes amené à travailler sur une issue, suivez ces principes : + +1. Les issues sont créées dans le système de gestion de versions (Git), chaque issue ayant un numéro unique. + +2. Lorsque vous décidez de travailler sur une issue, attribuez-vous l'issue et créez une branche avec un nom correspondant à l'issue sous la forme suivante : "issue_#32_nom" où 32 est le numéro de l'issue et nom est son libellé. + +3. Une fois que vous avez résolu l'issue dans votre branche, assurez-vous de mettre à jour le changelog avec les modifications apportées. + +4. Ensuite, poussez votre branche sur le référentiel distant et créez une merge request pour que vos modifications soient examinées par les autres membres de l'équipe. + +## Prérequis + +Avant de commencer à travailler sur le projet HeartTrack, assurez-vous d'avoir les prérequis suivants installés : + +- Serveur web (par exemple, Apache) +- PHP (version recommandée) +- Base de données (par exemple, MySQL) +- Git + +## Installation + +Pour installer et exécuter le projet HeartTrack, suivez ces étapes : + +1. Clonez ce référentiel sur votre machine locale en utilisant la commande suivante : + `git clone https://codefirst.iut.uca.fr/git/FitDev/Projet_fit_web` + +2. Configurez votre environnement de développement avec les prérequis mentionnés ci-dessus. + +3. Copiez le fichier de configuration d'exemple et configurez les paramètres de l'application : + +cp config/config.example.php config/config.php + +4. Importez la structure de la base de données à partir du fichier SQL fourni : + +mysql -u votre_nom_utilisateur -p < db_schema.sql + + +5. Démarrez votre serveur web et accédez à l'application via le navigateur. + +## Exécution + +Pour exécuter l'application, suivez les instructions d'installation ci-dessus. Une fois l'application configurée et le serveur web en cours d'exécution, accédez à l'application via votre navigateur web. + +## Déploiement en Démo + +Pour déployer une version de démonstration de l'application, utilisez la branche "demo" du référentiel. Cette branche est généralement mise à jour avec les dernières fonctionnalités en développement. + +## Déploiement en Production + +Pour déployer la version de production de l'application, utilisez la branche "prod" du référentiel. + +--- + +N'hésitez pas à contribuer au développement de HeartTrack en résolvant des issues ou en ajoutant de nouvelles fonctionnalités. Nous vous encourageons à suivre les principes et les pratiques décrites dans ce document pour un développement efficace et collaboratif. \ No newline at end of file diff --git a/Sources/.dockerignore b/Sources/.dockerignore new file mode 100644 index 00000000..365317ad --- /dev/null +++ b/Sources/.dockerignore @@ -0,0 +1,3 @@ +vendor/ +node_modules/ +.env diff --git a/Sources/.env.test b/Sources/.env.test new file mode 100644 index 00000000..e69de29b diff --git a/Sources/composer.json b/Sources/composer.json new file mode 100644 index 00000000..e69de29b diff --git a/Sources/config/Dockerfile b/Sources/config/Dockerfile new file mode 100644 index 00000000..ece7cbf8 --- /dev/null +++ b/Sources/config/Dockerfile @@ -0,0 +1,17 @@ +# Utilisez une image de base PHP +FROM php:7.4-apache + +# Définissez le répertoire de travail dans le conteneur +WORKDIR /var/www/ + +# Copiez les fichiers de votre projet dans le conteneur +COPY . /var/www/ + +# Installez les dépendances PHP (par exemple, si vous utilisez Composer) +RUN composer install + +# Exposez le port 80 (port par défaut d'Apache) +EXPOSE 80 + +# Commande pour démarrer Apache (vous pouvez également utiliser d'autres serveurs web comme Nginx) +CMD ["apache2-foreground"] diff --git a/Sources/config/config.php b/Sources/config/config.php new file mode 100644 index 00000000..fa498fc1 --- /dev/null +++ b/Sources/config/config.php @@ -0,0 +1,11 @@ + should use .env var +const DB_HOST = 'londres'; +const DB_DATABASE = 'dbdadalmeida1'; +const DB_USER = 'dadalmeida1'; +const DB_PASSWORD = 'achanger'; +$dsn ='mysql:host=londres.uca.local;dbname=dbdadalmeida1'; + + +const VIEW_PATH = 'views'; diff --git a/Sources/index.php b/Sources/index.php new file mode 100644 index 00000000..e69de29b diff --git a/Sources/src/core/network/service/AuthService.php b/Sources/src/core/network/service/AuthService.php new file mode 100644 index 00000000..e69de29b diff --git a/Sources/src/core/network/service/IAuthService.php b/Sources/src/core/network/service/IAuthService.php new file mode 100644 index 00000000..e69de29b diff --git a/Sources/src/core/stub/ActivitiesManager.php b/Sources/src/core/stub/ActivitiesManager.php new file mode 100644 index 00000000..e69de29b diff --git a/Sources/src/core/stub/StubData.php b/Sources/src/core/stub/StubData.php new file mode 100644 index 00000000..6c3b525f --- /dev/null +++ b/Sources/src/core/stub/StubData.php @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Sources/src/core/stub/UserManager.php b/Sources/src/core/stub/UserManager.php new file mode 100644 index 00000000..4ea60ce6 --- /dev/null +++ b/Sources/src/core/stub/UserManager.php @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/Sources/src/shared/router/AltoRouter.php b/Sources/src/shared/router/AltoRouter.php new file mode 100644 index 00000000..31aa3381 --- /dev/null +++ b/Sources/src/shared/router/AltoRouter.php @@ -0,0 +1,302 @@ + + +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. +*/ + +class AltoRouter +{ + + /** + * @var array Array of all routes (incl. named routes). + */ + protected $routes = []; + + /** + * @var array Array of all named routes. + */ + protected $namedRoutes = []; + + /** + * @var string Can be used to ignore leading part of the Request URL (if main file lives in subdirectory of host) + */ + protected $basePath = ''; + + /** + * @var array Array of default match types (regex helpers) + */ + protected $matchTypes = [ + '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 + * @throws Exception + */ + public function __construct(array $routes = [], $basePath = '', array $matchTypes = []) + { + $this->addRoutes($routes); + $this->setBasePath($basePath); + $this->addMatchTypes($matchTypes); + } + + /** + * Retrieves all routes. + * Useful if you want to process or display routes. + * @return array All routes. + */ + public function getRoutes() + { + return $this->routes; + } + + /** + * Add multiple routes at once from array in the following format: + * + * $routes = [ + * [$method, $route, $target, $name] + * ]; + * + * @param array $routes + * @return void + * @author Koen Punt + * @throws Exception + */ + public function addRoutes($routes) + { + if (!is_array($routes) && !$routes instanceof Traversable) { + throw new RuntimeException('Routes should be an array or an instance of Traversable'); + } + foreach ($routes as $route) { + call_user_func_array([$this, 'map'], $route); + } + } + + /** + * Set the base path. + * Useful if you are running your application from a subdirectory. + * @param string $basePath + */ + 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(array $matchTypes) + { + $this->matchTypes = array_merge($this->matchTypes, $matchTypes); + } + + /** + * Map a route to a target + * + * @param string $method One of 5 HTTP Methods, or a pipe-separated list of multiple HTTP Methods (GET|POST|PATCH|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. + * @throws Exception + */ + public function map($method, $route, $target, $name = null) + { + + $this->routes[] = [$method, $route, $target, $name]; + + if ($name) { + if (isset($this->namedRoutes[$name])) { + throw new RuntimeException("Can not redeclare route '{$name}'"); + } + $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. + * @throws Exception + */ + public function generate($routeName, array $params = []) + { + + // Check if named route exists + if (!isset($this->namedRoutes[$routeName])) { + throw new RuntimeException("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 $index => $match) { + list($block, $pre, $type, $param, $optional) = $match; + + if ($pre) { + $block = substr($block, 1); + } + + if (isset($params[$param])) { + // Part is found, replace for param value + $url = str_replace($block, $params[$param], $url); + } elseif ($optional && $index !== 0) { + // Only strip preceding slash if it's not at the base + $url = str_replace($pre . $block, '', $url); + } else { + // Strip match block + $url = str_replace($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 = []; + + // 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); + } + + $lastRequestUrlChar = $requestUrl ? $requestUrl[strlen($requestUrl)-1] : ''; + + // set Request Method if it isn't passed as a parameter + if ($requestMethod === null) { + $requestMethod = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET'; + } + + foreach ($this->routes as $handler) { + list($methods, $route, $target, $name) = $handler; + + $method_match = (stripos($methods, $requestMethod) !== false); + + // Method did not match, continue to next route. + if (!$method_match) { + continue; + } + + if ($route === '*') { + // * wildcard (matches all) + $match = true; + } elseif (isset($route[0]) && $route[0] === '@') { + // @ regex delimiter + $pattern = '`' . substr($route, 1) . '`u'; + $match = preg_match($pattern, $requestUrl, $params) === 1; + } elseif (($position = strpos($route, '[')) === false) { + // No params in url, do string comparison + $match = strcmp($requestUrl, $route) === 0; + } else { + // Compare longest non-param string with url before moving on to regex + // Check if last character before param is a slash, because it could be optional if param is optional too (see https://github.com/dannyvankooten/AltoRouter/issues/241) + if (strncmp($requestUrl, $route, $position) !== 0 && ($lastRequestUrlChar === '/' || $route[$position-1] !== '/')) { + continue; + } + + $regex = $this->compileRoute($route); + $match = preg_match($regex, $requestUrl, $params) === 1; + } + + if ($match) { + if ($params) { + foreach ($params as $key => $value) { + if (is_numeric($key)) { + unset($params[$key]); + } + } + } + + return [ + 'target' => $target, + 'params' => $params, + 'name' => $name + ]; + } + } + + return false; + } + + /** + * Compile the regex for a given route (EXPENSIVE) + * @param $route + * @return string + */ + protected 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 = '\.'; + } + + $optional = $optional !== '' ? '?' : null; + + //Older versions of PCRE require the 'P' in (?P) + $pattern = '(?:' + . ($pre !== '' ? $pre : null) + . '(' + . ($param !== '' ? "?P<$param>" : null) + . $type + . ')' + . $optional + . ')' + . $optional; + + $route = str_replace($block, $pattern, $route); + } + } + return "`^$route$`u"; + } +} diff --git a/Sources/src/shared/router/Router.php b/Sources/src/shared/router/Router.php new file mode 100644 index 00000000..6b8a85fb --- /dev/null +++ b/Sources/src/shared/router/Router.php @@ -0,0 +1,87 @@ +router = new AltoRouter(); + $this->router->setBasePath($this->path); + $this->initialiseRoutes(); + + + $match = $this->router->match(); + if(!$match){ + $tabError[] = 'error : wrong path '; + + require($dir . $vues['error']); + } + switch ($match['target']){ + case 'UserControler' : + $this->userConnexion('UserControler', $match); + break; + case 'VisteurControler' : + $this->callController('VisteurControler', $match); + break; + case 'any': + + VisteurControler::displayView(); + break; + default: + $tabError[] = 'error : Wrong call router'; + require($dir . $vues['error']); + } + }catch (PDOException $exp){ + $tabError[] = 'error data base' . $exp->getMessage(); + require($dir . $vues['error']); + } catch (Exception $exp2){ + $tabError[] = 'unknow exeption' . $exp2->getMessage(); + require($dir . $vues['error']); + }catch (Error $e){ + $tabError[] = 'unknow error' . $e->getMessage(); + require($dir . $vues['error']); + } + } + + private function userConnexion(string $controller, array $match) : void{ + global $dir, $vues; + + if(ModelUser::isUser() != NULL){ + $controller = 'UserControler'; + $this->callController($controller, $match); + } + else{ + VisteurControler::displayView(); + } + + } + + private function initialiseRoutes() : void{ + $this->router->map( 'GET|POST', '/user/[a:action]?/[i:id]?', 'UserControler','user_action'); + $this->router->map( 'GET|POST', '/', 'any'); + $this->router->map( 'GET|POST', '/[a:action]/[i:id]?', 'VisteurControler','vistor_action'); + + } + + private function callController(string $controller, array $match) : void{ + global $dir, $vues; + $action = Validation::val_action($match['params']['action']); + $controller = new $controller; + if(isset($match['params']['id'])){ + $param[] = $match['params']['id']; + } else + $param[] = array(); + if(is_callable(array($controller, $action))) + call_user_func_array(array($controller, $action), $param); + else{ + $tabError[] = 'error : controller '; + require($dir . $vues['error']); + } + } + +} diff --git a/Sources/src/utils/SplClassLoader.php b/Sources/src/utils/SplClassLoader.php new file mode 100644 index 00000000..e1ed7530 --- /dev/null +++ b/Sources/src/utils/SplClassLoader.php @@ -0,0 +1,208 @@ +. + */ + +/** + * SplClassLoader implementation that implements the technical interoperability + * standards for PHP 5.3 namespaces and class names. + * + * http://groups.google.com/group/php-standards/web/psr-0-final-proposal?pli=1 + * + * // Example which loads classes for the Doctrine Common package in the + * // Doctrine\Common namespace. + * $classLoader = new SplClassLoader('Doctrine\Common', '/path/to/doctrine'); + * $classLoader->register(); + * + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @author Jonathan H. Wage + * @author Roman S. Borschel + * @author Matthew Weier O'Phinney + * @author Kris Wallsmith + * @author Fabien Potencier + */ +class SplClassLoader +{ + private $_fileExtension = '.php'; + private $_namespace; + private $_includePath; + private $_namespaceSeparator = '\\'; + + /** + * Creates a new SplClassLoader that loads classes of the + * specified namespace. + * + * @param string $ns The namespace to use. + */ + public function __construct(string $ns = null, string $includePath = null) + { + $this->_namespace = $ns; + $this->_includePath = $includePath; + } + + /** + * Sets the namespace separator used by classes in the namespace of this class loader. + * + * @param string $sep The separator to use. + */ + public function setNamespaceSeparator(string $sep) + { + $this->_namespaceSeparator = $sep; + } + + /** + * Gets the namespace seperator used by classes in the namespace of this class loader. + * + * @return void + */ + public function getNamespaceSeparator() + { + return $this->_namespaceSeparator; + } + + /** + * Sets the base include path for all class files in the namespace of this class loader. + * + * @param string $includePath + */ + public function setIncludePath(string $includePath) + { + $this->_includePath = $includePath; + } + + /** + * Gets the base include path for all class files in the namespace of this class loader. + * + * @return string $includePath + */ + public function getIncludePath() + { + return $this->_includePath; + } + + /** + * Sets the file extension of class files in the namespace of this class loader. + * + * @param string $fileExtension + */ + public function setFileExtension($fileExtension) + { + $this->_fileExtension = $fileExtension; + } + + /** + * Gets the file extension of class files in the namespace of this class loader. + * + * @return string $fileExtension + */ + public function getFileExtension() + { + return $this->_fileExtension; + } + + /** + * Installs this class loader on the SPL autoload stack. + */ + public function register() + { + spl_autoload_register(array($this, 'loadClass')); + } + + /** + * Uninstalls this class loader from the SPL autoloader stack. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + } + + /** + * Loads the given class or interface. + * + * @param string $className The name of the class to load. + * @return void + */ + public function loadClass(string $className) + { + if (null === $this->_namespace || $this->_namespace . $this->_namespaceSeparator === substr($className, 0, strlen($this->_namespace . $this->_namespaceSeparator))) { + $fileName = ''; + $namespace = ''; + if (false !== ($lastNsPos = strripos($className, $this->_namespaceSeparator))) { + $namespace = substr($className, 0, $lastNsPos); + $className = substr($className, $lastNsPos + 1); + $fileName = str_replace($this->_namespaceSeparator, DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR; + } + $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . $this->_fileExtension; + + require ($this->_includePath !== null ? $this->_includePath . DIRECTORY_SEPARATOR : '') . $fileName; + } + } +} + + +// \ No newline at end of file diff --git a/Sources/src/utils/Validation.php b/Sources/src/utils/Validation.php new file mode 100644 index 00000000..98163c28 --- /dev/null +++ b/Sources/src/utils/Validation.php @@ -0,0 +1,109 @@ + diff --git a/notify.sh b/notify.sh new file mode 100644 index 00000000..5b5b563c --- /dev/null +++ b/notify.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +changelog="$(base64 -w 0 CHANGELOG)" + +# This call sends a message to the given recipient with vars and custom vars. +curl -s \ + -X POST \ + --user "46cb7f286b30df20369be709a91424a9:957e3ac14b3b106331ccd9dfe07f67fd" \ + https://api.mailjet.com/v3.1/send \ + -H 'Content-Type: application/json' \ + -d '{ "Messages":[ { "From": { "Email": "contact@lamsterpilotage.fr", "Name": "Equipe de développement" }, "To": [ { { "Email": "equipedev@waveheart.fr", "Name": "dev" } ], "TemplateID": 2687222, "TemplateLanguage": true, "Subject": "Nouvelle version démo", "Variables": {}, "Attachments": [ { "ContentType": "text/plain", "Filename": "changelog.md", "Base64Content": "'"$changelog"'" } ] } ] }' \ No newline at end of file