Comparer les révisions
Pas de révisions en commun. "f67a7470ad1b50fd23de4a4fccf1523c785e88df" et "efcc4d312aed09f04967bab2b6774c7479ab109f" ont des historiques entièrement différents.
f67a7470ad
...
efcc4d312a
7 fichiers modifiés avec 380 ajouts et 17 suppressions
22
README.md
22
README.md
|
@ -34,21 +34,21 @@ ## Installation
|
|||
```
|
||||
|
||||
## Routes disponibles
|
||||
- ```baseURL/webroutes``` : rend une documentation des endpoints configurés.
|
||||
- ```baseURL/logs``` : rend une interface de lecture des logs.
|
||||
- ```baseURL```/webroutes : rend une documentation des endpoints configurés
|
||||
- ```baseURL```/logs : rend une interface de lecture des logs
|
||||
|
||||
## Philosophie de développement
|
||||
### Bridge Pattern
|
||||
Afin de permettre une abstraction et une réusabilité accrue, l'applicatif est entendu de manière modulaire.
|
||||
Afin de permettre une hermécité, et une réusabilité accrue, l'applicatif est entendu de manière modulaire.
|
||||
|
||||
Chaque module peut disposer d'une classe publique et dispose nécessairement d'une classe privée.
|
||||
|
||||
La classe publique, qui étend la classe privée de son module, est la seule à pouvoir discuter avec le routeur, elle fait toutes les vérifications d'intégrité des données en entrée, gère la transaction avec la base donnée (commit/rollback), capture les levées d'exception; elle est la seule à communiquer en sortie avec le client.
|
||||
La classe publique, qui étend la classe privée de son module, est la seule à pouvoir discuter avec le routeur, elle fait toutes les vérifications d'intégrité des données en entrée, gère la transaction avec la base donnée (commit/rollback), elle est la seule à communiquer en sortie avec l'utilisateur.
|
||||
|
||||
__Une classe publique ne peut pas instancier une autre classe privée : elle dépend de sa classe mère.__ Totalement arbitraire, mais évite le spaghetti code, cela peut amener de la redondance sur les noms de méthodes, mais cela garantit une seule manière de faire transiter l'information.
|
||||
__Une classe publique ne peut pas instancier une autre classe privée : elle dépend de sa classe mère.__ Totalement arbitraire, mais évite le spaghetti code, cela peut amener de la redondance sur les noms de méthodes, mais ça garantit une seule manière de faire transiter l'information.
|
||||
|
||||
Chaque classe privée est abstraite de la classe publique, les opérations de calcul et de communication avec le SGBD y résident.
|
||||
Une classe privée peut utiliser une autre classe privée d'un autre module, ou d'une autre classe située en dehors du dossier ```app/Http/Controllers/Modules```. Dès lors la classe privée doit aussi comprendre les contrôles des arguments de méthodes mais ne capture pas les levées d'exception, elle ne fait qu'en émettre.
|
||||
Chaque classe privée est abstraite de la classe publique, les opérations de calcul sont fait dans la classe privée alors que la classe publique ne sert de contrôle des données.
|
||||
Une classe privée peut utiliser une autre classe privée d'un autre module, ou d'une autre classe située en dehors du dossier ```app/Http/Controllers/Modules```
|
||||
|
||||
### Gestion des levées d'exceptions
|
||||
Afin de ne pas multiplier les gestions des exceptions personnalisées des différents modules et vendors, la classe publique se bornera à ne capter que deux types d'exceptions : ```Exception``` et ```QueryException```.
|
||||
|
@ -72,9 +72,9 @@ ### Architecture API
|
|||
Pour une même route, avec la même syntaxe, en fonction de la méthode utilisée, l'action ne sera pas la même.
|
||||
|
||||
Le retour de chaque route comporte au moins une clé : ```status```.
|
||||
Cette clé prend en valeur 0 ou 1 sous la forme d'un entier.
|
||||
Quand la valeur est 1, l'opération, quelle qu'elle soit, est réussie, si la valeur est 0, une erreur est survenue.
|
||||
Si ```status``` est égal à 0, alors une autre clé est nécessairement disponible : ```msg```.
|
||||
La clé ```msg``` doit contenir le retour d'erreur pour le client, dans la langue voulue.
|
||||
Cette clé peut prendre en valeur 0 ou 1 sous la forme d'un entier.
|
||||
Quand la valeur est 1, l'opération, quelle qu'elle soit est réussie, si la valeur est 0, une erreur est survenue.
|
||||
Si status est égal à 0, alors une autre clé doit être nécessairement disponible : ```msg```.
|
||||
La clé ```msg``` doit nécessairement contenir le retour pour l'utilisateur, dans sa langue.
|
||||
|
||||
On s'affranchit donc des codes HTTP de retour : ça fonctionne ou ça ne fonctionne pas.
|
16
app/Http/Controllers/Core/CommonController.php
Fichier normal
16
app/Http/Controllers/Core/CommonController.php
Fichier normal
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Core;
|
||||
|
||||
use App\Http\Controllers\Core\Controller;
|
||||
|
||||
class CommonController extends Controller{
|
||||
|
||||
/**
|
||||
* Constructeur
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -2,6 +2,11 @@
|
|||
|
||||
namespace App\Http\Controllers\Core;
|
||||
|
||||
// use App\Http\Utility\arrayUtility;
|
||||
|
||||
// use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
// use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
// use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
|
||||
// Surcharge du controller principal
|
||||
|
|
30
app/Http/Controllers/Core/apiException.php
Fichier normal
30
app/Http/Controllers/Core/apiException.php
Fichier normal
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Core;
|
||||
|
||||
use App\Http\Utility\debug;
|
||||
|
||||
class apiException extends \Exception{
|
||||
public function __construct($message = null, $method = '', $code = 0, Throwable $previous = null) {
|
||||
$trace = $this->getTrace();
|
||||
if(is_array($trace)){
|
||||
//$last_call = $trace[1]['class'].'\\'.$trace[1]['function'];
|
||||
$last_call = $trace[1];
|
||||
}else{
|
||||
$last_call = $trace;
|
||||
}
|
||||
//$method = ($method!='') ? ( (is_array($method)) ? print_r($method,true) : $method ) : $last_call;
|
||||
$messageLog = ($method!='') ? $method . ' : '. $message : $message;
|
||||
|
||||
debug::consign($messageLog,'Api_Log','ERROR');
|
||||
debug::consign($last_call,'Api_Log','ERROR');
|
||||
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
||||
// public function __toString() {
|
||||
// return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
|
||||
// }
|
||||
|
||||
|
||||
}
|
|
@ -18,8 +18,7 @@ public function up()
|
|||
$table->string('login')->unique();
|
||||
$table->string('email')->unique();
|
||||
$table->string('password');
|
||||
$table->string('token')->nullable();
|
||||
$table->string('ip')->nullable();
|
||||
$table->string('token')->nullable();;
|
||||
$table->integer('isadmin');
|
||||
$table->integer('creation_date');
|
||||
$table->integer('modification_date');
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
// Pourquoi pas Blade ? Parce que cette documentation doit rester fonctionnelle quoi qu'il en coûte.
|
||||
// Si elle s'affiche, alors vos fichiers de routage sont correctement écris : elle sert aussi de validation du routing.
|
||||
// Si elle s'affiche, alors vos fichiers de routage sont correctement écris : ça sert aussi de validation du routing.
|
||||
// Pourquoi pas de dépendances lié à l'architecture et du CSS en ligne par exemple : exactement pour les mêmes raisons : on s'affranchit totalement du moteur de Laravel en cas de souci, on ne respecte que le routeur.
|
||||
|
||||
use App\Http\Utility\routeCollector;
|
||||
|
@ -454,8 +454,8 @@ function GenerateAnApiDoc($key,$apiArray){
|
|||
<pre><code class=\"lang-php\">return [
|
||||
// nom de l'API et préfixe de l'URL, est unique au système
|
||||
'api'=>'apiname'
|
||||
// namespace de la classe publique
|
||||
,'class'=>'public\\class\\namespace'
|
||||
// la classe publique LARAVEL connecté à cette route, relativement à /app/Http/Controllers/..
|
||||
,'class'=>'entityOrModules\\path\\to\\publicfunction'
|
||||
// Les possibles restrictions d'accès au groupe de route (FACULTATIF). Tous les routes de tous les types seront restreint par les accès utilisateur
|
||||
// Restrictions possibles :
|
||||
// - sys_admin : administrateur système
|
||||
|
@ -615,6 +615,301 @@ function GenerateAnApiDoc($key,$apiArray){
|
|||
]
|
||||
];</code></pre>
|
||||
</div>";
|
||||
$html.="
|
||||
<div class='deploybox'>
|
||||
<div class='deploybtn'>Voir un exemple</div>
|
||||
<pre><code class=\"lang-php\">return [
|
||||
'api'=>'articlemanager'
|
||||
,'class'=>'Modules\ArticleManager\ArticleManagerPublic'
|
||||
,'get'=>[
|
||||
[
|
||||
'desc'=>'Récupère les prix de l\'article par la quantité',
|
||||
'url'=>'{idtask}/getpricewithqty'
|
||||
,'method'=>'getPriceWithQty'
|
||||
,'params'=>[
|
||||
'idtask' =>'\d+',
|
||||
]
|
||||
,'params_desc'=>[
|
||||
'idtask' =>'Identifiant tâche'
|
||||
]
|
||||
,'get_params'=>[
|
||||
'thpId' =>'\d+',
|
||||
'qty' =>'\d+\.?\d*',
|
||||
'discountId' =>'\d+',
|
||||
'productUnitId' =>'\d+',
|
||||
]
|
||||
,'get_params_desc'=>[
|
||||
'thpId' =>'Identifiant de ligne de tâche',
|
||||
'qty' =>'Quantité',
|
||||
'discountId' =>'Identifant remise',
|
||||
'productUnitId' =>'Identifiant de l\'unité du produit',
|
||||
]
|
||||
],
|
||||
[
|
||||
'desc'=>'Récupère les prix de l\'article par un prix donné',
|
||||
'url'=>'{idtask}/getpricewithprice'
|
||||
,'method'=>'getPriceWithPrice'
|
||||
,'params'=>[
|
||||
'idtask' =>'\d+',
|
||||
]
|
||||
,'params_desc'=>[
|
||||
'idtask' =>'Identifiant tâche'
|
||||
]
|
||||
,'get_params'=>[
|
||||
'thpId' =>'\d+',
|
||||
'qty' =>'\d+\.?\d*',
|
||||
'discountId' =>'\d+',
|
||||
'productUnitId' =>'\d+',
|
||||
'priceType' =>'unitprice|packprice',
|
||||
'price' =>'\d+\.?\d*',
|
||||
]
|
||||
,'get_params_desc'=>[
|
||||
'thpId' =>'Identifiant de ligne de tâche',
|
||||
'qty' =>'Quantité',
|
||||
'discountId' =>'Identifant remise',
|
||||
'productUnitId' =>'Identifiant de l\'unité du produit',
|
||||
'priceType' =>'Le type de price souhaite : prix unitaire, prix conditionnement',
|
||||
'price' =>'Prix',
|
||||
]
|
||||
],
|
||||
[
|
||||
'desc'=>'Recherche des articles',
|
||||
'url'=>'{idtask}/search'
|
||||
,'method'=>'search'
|
||||
,'params'=>[
|
||||
'idtask' =>'\d+',
|
||||
]
|
||||
,'params_desc'=>[
|
||||
'idtask' =>'Identifiant tâche'
|
||||
]
|
||||
,'get_params'=>[
|
||||
'search' =>'\w+',
|
||||
]
|
||||
,'get_params_desc'=>[
|
||||
'search' =>'Terme de la recherche',
|
||||
]
|
||||
],
|
||||
[
|
||||
'desc'=>'Récupère un objet de grille Vgrid',
|
||||
'url'=>'{idtask}/list/{gridType}/'
|
||||
,'method'=>'getProductList'
|
||||
,'params'=>[
|
||||
'idtask' =>'\d+',
|
||||
'gridType' =>'productall|productfromprice|alreadyemployed|compmodels|devices',
|
||||
]
|
||||
,'params_desc'=>[
|
||||
'idtask' =>'Identifiant tâche',
|
||||
'gridType' =>'Le type de grille souhaité : Tous les produits, Produit des tarifs, Produits déjà utilisés, Composant modèles, Machines',
|
||||
]
|
||||
],
|
||||
]
|
||||
,'post'=>[
|
||||
[
|
||||
'desc'=>'Ajoute un article en fonction de son type',
|
||||
'url'=>'{idtask}/addarticle/'
|
||||
,'method'=>'addArticle'
|
||||
,'params'=>[
|
||||
'idtask' =>'\d+',
|
||||
]
|
||||
,'params_desc'=>[
|
||||
'idtask' =>'Identifiant tâche'
|
||||
]
|
||||
,'post_params'=>[
|
||||
'pid' =>'\d+',
|
||||
'type' =>'\w+',
|
||||
'uid' =>'\d+',
|
||||
]
|
||||
,'post_params_desc'=>[
|
||||
'pid' =>'Identifiant produit',
|
||||
'type' =>'Type de produit : product, device',
|
||||
'uid' =>'Identifiant de l\'unité',
|
||||
]
|
||||
],
|
||||
[
|
||||
'desc'=>'test JSON',
|
||||
'url'=>'equipment'
|
||||
,'method'=>'addArticle'
|
||||
,'params'=>[
|
||||
// 'idtask' =>'\d+',
|
||||
]
|
||||
,'params_desc'=>[
|
||||
// 'idtask' =>'Identifiant tâche'
|
||||
]
|
||||
,'post_params'=>[
|
||||
'data' =>'JSON',
|
||||
]
|
||||
,'post_params_desc'=>[
|
||||
'data'=>[
|
||||
'external_id'=>'Id externe (ID SAGE)',
|
||||
'code'=>'Code de la société [REQUIRED]',
|
||||
'name'=>'Nom de la société',
|
||||
'email'=>'Email de la société',
|
||||
'web_site'=>'Adresse web de la société',
|
||||
'siret'=>'Siret de la société',
|
||||
'parent_id'=>'Id de la société mère (centrale d\'achat)',
|
||||
'parent_code'=>'Code de la société mère (centrale d\'achat)',
|
||||
'parent_external_id'=>'Id externe de la société mère (centrale d\'achat)',
|
||||
'contacts'=>[
|
||||
[
|
||||
'external_id'=>'Id externe (ID SAGE)',
|
||||
'code'=>'Code du contact [REQUIRED]',
|
||||
'name'=>'Nom du contact',
|
||||
'first_name'=>'Prénom du contact',
|
||||
'phone'=>'Téléphone du contact',
|
||||
'email'=>'Email du contact',
|
||||
'linkedin'=>'Adresse LinkedIn du contact',
|
||||
],
|
||||
[
|
||||
'external_id'=>'Id externe (ID SAGE)',
|
||||
'code'=>'Code du contact [REQUIRED]',
|
||||
'name'=>'Nom du contact',
|
||||
'first_name'=>'Prénom du contact',
|
||||
'phone'=>'Téléphone du contact',
|
||||
'email'=>'Email du contact',
|
||||
'linkedin'=>'Adresse LinkedIn du contact',
|
||||
]
|
||||
],
|
||||
'locations'=>[
|
||||
'!COMMENT!_1'=>'Code adresse principale, Une seule adresse principale [REQUIRED]',
|
||||
'main'=>[
|
||||
'external_id'=>'Id externe (ID SAGE)',
|
||||
'address1'=>'Zone d\'adresse 1 de l\'adresse principale',
|
||||
'address2'=>'Zone d\'adresse 2 de l\'adresse principale',
|
||||
'postal'=>'Code postale de l\'adresse principale',
|
||||
'city'=>'Ville de l\'adresse principale',
|
||||
'country'=>'Pays de l\'adresse principale',
|
||||
'phone'=>'Téléphone de l\'adresse principale',
|
||||
'email'=>'Email de l\'adresse principale',
|
||||
],
|
||||
'!COMMENT!_2'=>'Code adresse de livraison, Peut y en avoir plusieurs ',
|
||||
'delivery'=>[
|
||||
'external_id'=>'Id externe (ID SAGE)',
|
||||
'address1'=>'Zone d\'adresse 1 de l\'adresse principale',
|
||||
'address2'=>'Zone d\'adresse 2 de l\'adresse principale',
|
||||
'postal'=>'Code postale de l\'adresse principale',
|
||||
'city'=>'Ville de l\'adresse principale',
|
||||
'country'=>'Pays de l\'adresse principale',
|
||||
'phone'=>'Téléphone de l\'adresse principale',
|
||||
'email'=>'Email de l\'adresse principale',
|
||||
]
|
||||
],
|
||||
],
|
||||
]
|
||||
],
|
||||
]
|
||||
,'patch'=>[
|
||||
[
|
||||
'desc'=>'Met à jour un article',
|
||||
'url'=>'{idtask}/updatearticle/'
|
||||
,'method'=>'updateArticle'
|
||||
,'params'=>[
|
||||
'idtask' =>'\d+',
|
||||
]
|
||||
,'params_desc'=>[
|
||||
'idtask' =>'Identifiant tâche'
|
||||
]
|
||||
,'post_params'=>[
|
||||
'thpId'=>'\d+',
|
||||
'unitId'=>'\d+',
|
||||
'unitPrice'=>'\d+',
|
||||
'packPrice'=>'\d+',
|
||||
'name'=>'\w+',
|
||||
'qty'=>'\d+\.?\d*',
|
||||
]
|
||||
,'opt_post_params'=>[
|
||||
'deliveryDate'=>'\d{4}\/\d{2}\/\d{2}(?>\s?\d{2}:\d{2}|)',
|
||||
'discountId'=>'\d+',
|
||||
]
|
||||
,'post_params_desc'=>[
|
||||
'thpId'=>'Identifiant ligne de tâche',
|
||||
'unitId'=>'Identifiant de l\'unité',
|
||||
'unitPrice'=>'Prix unitaire',
|
||||
'packPrice'=>'Prix de conditionnement',
|
||||
'name'=>'Nom du produit',
|
||||
'qty'=>'Quantité',
|
||||
'deliveryDate'=>'Date de livraison',
|
||||
'discountId'=>'Identifiant de la remise',
|
||||
]
|
||||
],
|
||||
[
|
||||
'desc'=>'Change l\'ordre d\'une ligne',
|
||||
'url'=>'{idtask}/moveline/'
|
||||
,'method'=>'moveLine'
|
||||
,'params'=>[
|
||||
'idtask' =>'\d+',
|
||||
]
|
||||
,'params_desc'=>[
|
||||
'idtask' =>'Identifiant tâche'
|
||||
]
|
||||
,'post_params'=>[
|
||||
'type' =>'product|comment',
|
||||
'index' =>'\d+',
|
||||
'oid' =>'\d+',
|
||||
]
|
||||
,'post_params_desc'=>[
|
||||
'type' =>'Type de ligne : produit ou commentaire',
|
||||
'index' =>'Ordre de la ligne dans la liste',
|
||||
'oid' =>'Identifiant de la ligne',
|
||||
]
|
||||
],
|
||||
[
|
||||
'desc'=>'Met à jour un commentaire',
|
||||
'url'=>'{idtask}/updatecomment/'
|
||||
,'method'=>'changeComment'
|
||||
,'params'=>[
|
||||
'idtask' =>'\d+',
|
||||
]
|
||||
,'params_desc'=>[
|
||||
'idtask' =>'Identifiant tâche'
|
||||
]
|
||||
,'post_params'=>[
|
||||
'txt' =>'\w+',
|
||||
'commentId' =>'\d+',
|
||||
]
|
||||
,'post_params_desc'=>[
|
||||
'txt' =>'Text du commentaire',
|
||||
'commentId' =>'Identifiant du commentaire',
|
||||
]
|
||||
],
|
||||
]
|
||||
,'delete'=>[
|
||||
[
|
||||
'desc'=>'Supprime un article',
|
||||
'url'=>'{idtask}/deletearticle/'
|
||||
,'method'=>'delArticle'
|
||||
,'params'=>[
|
||||
'idtask' =>'\d+',
|
||||
]
|
||||
,'params_desc'=>[
|
||||
'idtask' =>'Identifiant tâche'
|
||||
]
|
||||
,'post_params'=>[
|
||||
'thpId' =>'\d+',
|
||||
]
|
||||
,'post_params_desc'=>[
|
||||
'thpId' =>'Identifiant ligne de tâche',
|
||||
]
|
||||
],
|
||||
[
|
||||
'desc'=>'Supprime un commentaire',
|
||||
'url'=>'{idtask}/deletecomment/'
|
||||
,'method'=>'delComment'
|
||||
,'params'=>[
|
||||
'idtask' =>'\d+',
|
||||
]
|
||||
,'params_desc'=>[
|
||||
'idtask' =>'Identifiant tâche'
|
||||
]
|
||||
,'post_params'=>[
|
||||
'thcId' =>'\d+',
|
||||
]
|
||||
,'post_params_desc'=>[
|
||||
'thpId' =>'Identifiant ligne de tâche',
|
||||
]
|
||||
],
|
||||
]
|
||||
];</code></pre>
|
||||
</div>";
|
||||
|
||||
$html.=' </div>
|
||||
<div class="content">'.$body.'</div>
|
||||
|
|
18
tests/Unit/ExampleTest.php
Fichier normal
18
tests/Unit/ExampleTest.php
Fichier normal
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ExampleTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* A basic test example.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_example()
|
||||
{
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
}
|
Chargement…
Référencer dans un nouveau ticket