Yet another PHP Framework
- Architecture MVC
- Plusieurs niveaux d'abstractions
- 1 installation du framework permet le support de n applications
- 1 application supporte x modules
- Configuration externalisée en fonction du domaine d'exécution
- Support du multi-langue
- Support de connexions multiples à différents serveurs de base de données
- Classe de création de requêtes SQL
- Gestionnaire de routes par un fichier externalisée
- Debugger PHP
- Système de gestion de composants JS/CSS (avec dépendances)
- Système de formulaires (déclaration, validation, affichage par défaut)
Pré-requis :
- Apache
- PHP 7.2
- MySQL
Tout-en-un :
- WAMP Server
- EasyPHP
- ...
WSL2 :
- Installation
- Mettre à jour la liste des paquets puis installer les pré-requis
- S'assurer qu'Apache permet aux dossiers de travail de surcharger la configuration (pour accepter les fichiers .htaccess)
- Activer le module Apache
rewrite
Dans le dossier racine du serveur Apache
- Ouvrir le fichier
includes/applications/setup.jsonet identifier le préfixe associer àlocalhost(par défautdev) - Ouvrir le fichier
includes/applications/dev.config.jsoncorrespondant à la configuration prise en compte- Vérifier les informations renseignées des environnements associés (API et Base de données)
- Si la base est locale, s'assurer que le schéma de base existe et est accessible
Accéder directement à http://localhost/php-fw/
Un ensemble de metadata avancées pour PhpStorm sont disponibles au sein du dossier .phpstorm.meta.php pour préciser l'autocomplétion ou le comportement de certaines méthodes.
En complément, si node est disponible sur la machine de développement, il est possible des watchers afin d'enrichir ce fichier de meta en fonction de la configuration du projet en cours :
.phpstorm.meta.php/watcher.manifest.js: qui devra écouter les modifications du fichierincludes/components/manifest.jsonafin de permettre l'autocomplétion des composants disponibles lors de l'appel à la méthode :core\application\Autoload::addComponent("");.phpstorm.meta.php/watcher.config.js: qui devra écouter les modifications des fichiersincludes/applications/*.config.jsonafin de permettre l'autocomplétion sur les clés disponibles lors de l'appel à la méthode :core\application\Configuration::extra("")
Pour identifier le controller et l'action exécutée, on part de l'URL.
- On regarde la première composante de l'url (chaîne de caractères entre les
/après le domaine), si cette composante correspond à une application existante, c'est cette application qu'il faut suivre, sinon il faut suivre l'applicationmain(par défaut) - On regarde ensuite la seconde composante de l'url, si cette composante correspond à un module, c'est ce module qu'il faut suivre, sinon il faut suivre le module
front(par défaut) - Une fois qu'on a identifié l'
applicationet lemodule, il faut regarder le fichiersrc/routing_rules.jsonde l'application - En fonction de l'url et de la méthode HTTP, on identifie directement le controller, l'action ainsi que le nom des paramètres GET parsés
Exemple d'url :
"article/{$permalink}-{$id}.html": {
"parameters": {
"permalink": "[a-z0-9\\-\\_]+",
"id": "[0-9]+"
},
"GET": {
"controller": "Article",
"action": "byId"
}
}
Les composantes dynamiques présentes dans l'url sont identifiées par des accolades et des noms de variables (IE {$permalink}). Les valeurs potentiels de ces composantes sont définies dans la propriété parameters sous forme d'expression régulière.
Si l'url en cours correspond à la route, le couple controller / action exécuté est déduit du verbe HTTP utilisé :
GETPOSTDELETE...*(wildcard pour tout prendre en compte)
Il est également possible de spécifier plusieurs verbes pour un même couple en concaténant les valeurs avec un pipe : GET|POST
Les fichiers de formulaires sont déclarés dans des fichiers JSON présents dans le dossier forms du module de l'application en cours.
Par exemple, imaginons un formulaire de "login" includes/applications/main/modules/front/form/form.login.json
{
"login":{
"require":true,
"regExp":"TextNoHtml",
"tag":"input",
"attributes":{
"placeholder":"Login",
"type":"text"
}
},
"mdp":{
"require":true,
"regExp":"TextNoHtml",
"tag":"input",
"attributes":{
"placeholder":"Mot de passe",
"type":"password"
}
},
"submit":{
"tag":"input",
"attributes":{
"type":"submit",
"value":"Login",
"class":"button"
}
}
}On peut alors l'instancier dans un controller du même module et de la même application :
$form_login = new Form('login');
if($form_login->isValid())
{
$values = $form_login->getValues();
trace_r($values);
}
else
{
$error = $form_login->getError();
trace($error);
}
$this->addForm('login', $form_login');La méthode addForm déclare l'instance de la classe Form pour permettre son accès dans le template :
<html>
<body>
{form.login->display url='action/route' param1='value1'}
</body>
</html> {
"label":"Input",
"tag":"input",
"require":cool,
"attributes":
{
"type":"text"|"password"|"submit"...,
"value":"Default Value",
"class":...
}
}
{
"label":"Select",
"tag":"select",
"fromModel":
{
"model":"app\\models\\ModelName",
"method":"all",
"name":"field_name",
"value":"field_name_id"
}
}
{
"label":"Datepicker",
"tag":"datepicker"
}
{
"label":"Fichier",
"tag":"upload"
"fileType":"jpg|png|...",
"fileName":"someName{id}",
"resize":[200, 200]
}
{
"label":"Radiogroup",
"tag":"radiogroup",
"display":"block",
"height":"200px",
"width":"400px",
"fromModel":
{
"model":"app\\models\\ModelName",
"method":"all",
"name":"field_name",
"value":"field_name_id"
}
}
{
"label":"Checkboxgroup",
"tag":"checkboxgroup",
"height":"200px",
"width":"400px",
"fromModel":
{
"model":"app\\models\\ModelName",
"method":"all",
"name":"field_name",
"value":"field_name_id"
}
}
{
"label":"Captcha",
"tag":"captcha",
"require":true|false,
"attributes":{
"backgroundColor":"#ffffff",
"fontSizeMax":13,
"fontSizeMin":13,
"width":100,
"height":30,
"rotation":15,
"fontColors":["#444444","#ff0000","#000000"],
"transparent":true,
"length":7,
"type":"random|calculus",
"valueMax":99
}
}
Un composant est un ensemble de resources JS, CSS, medias regroupé pour permettre le bonne affichage / la bonne exécution d'une page / fonctionnalité.
Les composants sont décrits dans le fichier includes/components/manifest.json
Dans le projet, depuis un controller PHP il est possible de charger un composant via la méthode :
Autoload::addComponent($pComponentName);Cette méthode va s'occuper de centraliser l'ensemble des composants à charger afin de n'ajouter qu'une seule balise script et qu'une seule balise link[rel="stylesheet"]. Ces deux balises vont pointer leurs urls vers le StaticController du framework avec la liste des composants à charger en paramètres.
C'est ensuite la classe Dependencies qui va se charger de récupérer la liste des composants à charger pour en déduire les dépendances ainsi que l'ordre des fichiers (js ou css) à renvoyer.
Note : Les urls dans les fichiers css sont relatives aux fichiers et doivent être entourées de guillemets "
IE :
/** mon image est présente dans le dossier path/to/imgs/ présent au même niveau que ma feuille de style **/
.some_class{background:url("path/to/imgs/mymg.png") no-repeat;}/**
* Alias pour Debugger:trace
* Méthode d'affichage d'une chaine de caractère dans le debugger
* @parameter string $pString Données à afficher
* @parameter bool $pOpen Spécifie si le débugger doit être ouvert
**/
trace($pString, $pOpen);
/**
* Alias pour Debugger:trace_r
* Pour les objets & les tableaux
* @parameter object $pString Données à afficher
* @parameter bool $pOpen Spécifie si le débugger doit être ouvert
**/
trace_r($pObject, $pOpen);
/**
* Alias pour Debugger:track
* Méthode de suivi du temps d'exécution et de l'usage de mémoire généré entre deux appels pour le même identifiant
* @paramters string $pId Identifiant du block de code à tracker
*/
track($pId);| namespace | contexte | description |
|---|---|---|
| core \ {subPackage} \ | Global | Classes & interfaces du package core |
| lib \ {package} \ {subPackage} | Global | Classes & interfaces des packages secondaire |
| app \ {appName} \ models | Application | Modèles de l'application appName |
| app \ {appName} \ controllers \ {moduleName} | Application | Controllers du module {moduleName} de l'application {appName} |
| app \ {appName} \ src \ {subPackage} | Application | Classes & interfaces de l'application {appName} |
- Integrate a light Dictionary class with the Dependencies's loaded scripts
- RoutingHandler : method to get a route depending upon controller/action/method/parameters
- Integrate services managing
- Develop an Autocomplete component
- Dependencies : Add minified option
- SimpleCrawler : use Events for logging
- Dictionary : Implement dynamic "title" and "description" tags (like terms)