SmartMaker - Back (PHP)
La partie backoffice de SmartMaker s'intègre dans un module Dolibarr standard.
Structure des dossiers
Lorsque vous déployez SmartMaker dans votre module Dolibarr, les dossiers suivants sont créés :
| Dossier | Description |
|---|---|
mobile/ | Code source React de l'application mobile |
pwa/ | Application compilée + point d'entrée api.php |
smartmaker-api/ | Contrôleurs et mappeurs PHP |
Et un fichier smartmaker-api-prepend.php pour factoriser les includes.
Le routeur PHP
Syntaxe
Route::action(path, Controller::class, method, protected);
| Paramètre | Description |
|---|---|
action | get, post, put, delete |
path | Chemin de l'API (ex: items, items/{id}) |
Controller::class | Classe PHP à appeler |
method | Méthode de la classe |
protected | true = route authentifiée, false = publique |
Exemple complet (api.php)
<?php
require_once '../smartmaker-api-prepend.php';
use SmartAuth\Api\AuthController;
use SmartAuth\Api\RouteController as Route;
use MyModule\Api\ItemController;
// Routes publiques (authentification)
Route::get('login', AuthController::class, 'index');
Route::post('login', AuthController::class, 'login');
Route::get('refresh', AuthController::class, 'refresh');
// Routes protégées (nécessitent un token JWT)
Route::post('logout', AuthController::class, 'logout', true);
Route::post('device', AuthController::class, 'device', true);
// CRUD sur les items
Route::get('items', ItemController::class, 'index', true);
Route::get('items/{id}', ItemController::class, 'show', true);
Route::post('items', ItemController::class, 'create', true);
Route::put('items/{id}', ItemController::class, 'update', true);
Route::delete('items/{id}', ItemController::class, 'delete', true);
// Routes avec filtres
Route::post('items/{filter}', ItemController::class, 'search', true);
// Fichiers
Route::get('file/{element}/{parentid}/{ref}', FileController::class, 'download', true);
// Fallback
json_reply('Access denied', 403);
Paramètres dynamiques
Les paramètres entre accolades sont passés dans le payload :
// Route: GET /items/123
Route::get('items/{id}', ItemController::class, 'show', true);
// Dans le controller:
public function show($payload)
{
$id = $payload['id']; // 123
}
Créer un Controller
Structure de base
<?php
namespace MyModule\Api;
class ItemController
{
public function __construct() {}
/**
* Liste des items
* @param array|null $payload Données de la requête
* @return array [data, httpCode]
*/
public function index($payload = null)
{
global $db, $user;
// Votre logique ici
$items = [];
return [$items, 200];
}
/**
* Récupérer un item
*/
public function show($payload = null)
{
global $db;
$id = $payload['id'] ?? null;
if ($id === null) {
return ['Not Found', 404];
}
// Fetch l'objet
$item = new \MyObject($db);
$res = $item->fetch($id);
if ($res <= 0) {
return ['Not Found', 404];
}
// Mapper pour le front
$mapping = new dmMyObject();
$data = $mapping->exportMappedData($item);
return [$data, 200];
}
/**
* Créer un item
*/
public function create($payload = null)
{
global $db, $user;
$item = new \MyObject($db);
$item->label = $payload['label'];
$item->description = $payload['description'];
$res = $item->create($user);
if ($res < 0) {
return ['Error creating item', 500];
}
return [['id' => $res], 201];
}
/**
* Mettre à jour un item
*/
public function update($payload = null)
{
global $db, $user;
$id = $payload['id'] ?? null;
$item = new \MyObject($db);
$res = $item->fetch($id);
if ($res <= 0) {
return ['Not Found', 404];
}
// Mettre à jour les champs
if (isset($payload['label'])) {
$item->label = $payload['label'];
}
$res = $item->update($user);
if ($res < 0) {
return ['Error updating item', 500];
}
return ['Updated', 200];
}
/**
* Supprimer un item
*/
public function delete($payload = null)
{
global $db, $user;
$id = $payload['id'] ?? null;
$item = new \MyObject($db);
$res = $item->fetch($id);
if ($res <= 0) {
return ['Not Found', 404];
}
$res = $item->delete($user);
if ($res < 0) {
return ['Error deleting item', 500];
}
return ['Deleted', 200];
}
/**
* Recherche avec filtres
*/
public function search($payload = null)
{
global $db;
$filter = $payload['filter'] ?? 'all';
$limit = $payload['limit'] ?? 10;
// Construire la requête SQL
$sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "myobject";
$sql .= " WHERE 1=1";
if ($filter === 'active') {
$sql .= " AND status = 1";
}
$sql .= " LIMIT " . (int) $limit;
$resql = $db->query($sql);
$items = [];
while ($obj = $db->fetch_object($resql)) {
$item = new \MyObject($db);
$item->fetch($obj->rowid);
$mapping = new dmMyObject();
$items[] = $mapping->exportMappedData($item);
}
return [$items, 200];
}
}
Accès à l'utilisateur connecté
L'utilisateur JWT est disponible dans le payload :
public function update($payload = null)
{
$user = $payload['user']; // Objet User Dolibarr
dol_syslog("Action par: " . $user->login);
}
Voir aussi
- Mapping Dolibarr - React - Classes dm*
- SmartAuth - Authentification JWT