Chapitre 1 : Backend
1. Classe Dolibarr (optionnel)
Si vous utilisez un objet Dolibarr existant (Product, Facture, etc.), passez cette étape.
Pour un nouvel objet :
- snippet.php
<?php // class/task.class.php require_once DOL_DOCUMENT_ROOT . '/core/class/commonobject.class.php'; class Task extends CommonObject { public $element = 'task'; public $table_element = 'monmodule_task'; public $fk_element = 'fk_task'; public $id; public $ref; public $label; public $description; public $fk_user; public $status; public $priority; public $date_start; public $date_end; public $date_creation; public $tms; const STATUS_DRAFT = 0; const STATUS_TODO = 1; const STATUS_DONE = 2; public function __construct($db) { global $langs; $this->db = $db; } public function create($user, $notrigger = 0) { $this->ref = $this->getNextNumRef(); $this->date_creation = dol_now(); $this->fk_user = $user->id; $sql = "INSERT INTO " . MAIN_DB_PREFIX . $this->table_element; $sql .= " (ref, label, description, fk_user, status, priority,"; $sql .= " date_start, date_end, date_creation, entity)"; $sql .= " VALUES ("; $sql .= "'" . $this->db->escape($this->ref) . "',"; $sql .= "'" . $this->db->escape($this->label) . "',"; $sql .= "'" . $this->db->escape($this->description) . "',"; $sql .= (int) $this->fk_user . ","; $sql .= (int) $this->status . ","; $sql .= (int) $this->priority . ","; $sql .= ($this->date_start ? "'" . $this->db->idate($this->date_start) . "'" : "NULL") . ","; $sql .= ($this->date_end ? "'" . $this->db->idate($this->date_end) . "'" : "NULL") . ","; $sql .= "'" . $this->db->idate($this->date_creation) . "',"; $sql .= $conf->entity; $sql .= ")"; $resql = $this->db->query($sql); if ($resql) { $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . $this->table_element); return $this->id; } $this->error = $this->db->lasterror(); return -1; } public function fetch($id, $ref = '') { $sql = "SELECT * FROM " . MAIN_DB_PREFIX . $this->table_element; $sql .= " WHERE entity IN (" . getEntity($this->element) . ")"; if ($id) { $sql .= " AND rowid = " . (int) $id; } elseif ($ref) { $sql .= " AND ref = '" . $this->db->escape($ref) . "'"; } $resql = $this->db->query($sql); if ($resql && $this->db->num_rows($resql)) { $obj = $this->db->fetch_object($resql); $this->id = $obj->rowid; $this->ref = $obj->ref; $this->label = $obj->label; $this->description = $obj->description; $this->fk_user = $obj->fk_user; $this->status = $obj->status; $this->priority = $obj->priority; $this->date_start = $this->db->jdate($obj->date_start); $this->date_end = $this->db->jdate($obj->date_end); $this->date_creation = $this->db->jdate($obj->date_creation); $this->tms = $this->db->jdate($obj->tms); return 1; } return 0; } public function update($user, $notrigger = 0) { $sql = "UPDATE " . MAIN_DB_PREFIX . $this->table_element . " SET"; $sql .= " label = '" . $this->db->escape($this->label) . "',"; $sql .= " description = '" . $this->db->escape($this->description) . "',"; $sql .= " status = " . (int) $this->status . ","; $sql .= " priority = " . (int) $this->priority . ","; $sql .= " date_start = " . ($this->date_start ? "'" . $this->db->idate($this->date_start) . "'" : "NULL") . ","; $sql .= " date_end = " . ($this->date_end ? "'" . $this->db->idate($this->date_end) . "'" : "NULL"); $sql .= " WHERE rowid = " . (int) $this->id; $resql = $this->db->query($sql); if ($resql) { return 1; } $this->error = $this->db->lasterror(); return -1; } public function delete($user, $notrigger = 0) { $sql = "DELETE FROM " . MAIN_DB_PREFIX . $this->table_element; $sql .= " WHERE rowid = " . (int) $this->id; $resql = $this->db->query($sql); if ($resql) { return 1; } $this->error = $this->db->lasterror(); return -1; } }
2. Routes API
- snippet.php
<?php // pwa/api.php require_once '../smartmaker-api-prepend.php'; use SmartAuth\Api\AuthController; use SmartAuth\Api\RouteController as Route; use MonModule\Api\TaskController; // Authentification Route::get('login', AuthController::class, 'index'); Route::post('login', AuthController::class, 'login'); Route::get('refresh', AuthController::class, 'refresh'); Route::post('logout', AuthController::class, 'logout', true); // Tâches Route::get('tasks', TaskController::class, 'index', true); Route::get('tasks/{id}', TaskController::class, 'show', true); Route::post('tasks', TaskController::class, 'create', true); Route::put('tasks/{id}', TaskController::class, 'update', true); Route::delete('tasks/{id}', TaskController::class, 'delete', true); // Fallback json_reply('Access denied', 403);
3. Controller
- snippet.php
<?php // smartmaker-api/Controllers/TaskController.php namespace MonModule\Api; use MonModule\Api\Mappers\dmTask; class TaskController { public function index($payload = null) { global $db, $user; require_once DOL_DOCUMENT_ROOT . '/custom/monmodule/class/task.class.php'; // Filtres $status = $payload['status'] ?? null; $limit = min($payload['limit'] ?? 50, 100); $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "monmodule_task"; $sql .= " WHERE fk_user = " . (int) $user->id; $sql .= " AND entity IN (" . getEntity('task') . ")"; if ($status !== null) { $sql .= " AND status = " . (int) $status; } $sql .= " ORDER BY priority DESC, date_start ASC"; $sql .= " LIMIT " . (int) $limit; $resql = $db->query($sql); $tasks = []; $mapper = new dmTask(); while ($obj = $db->fetch_object($resql)) { $task = new \Task($db); $task->fetch($obj->rowid); $tasks[] = $mapper->exportMappedData($task); } return [['tasks' => $tasks], 200]; } public function show($payload = null) { global $db, $user; $id = $payload['id'] ?? null; require_once DOL_DOCUMENT_ROOT . '/custom/monmodule/class/task.class.php'; $task = new \Task($db); $res = $task->fetch($id); if ($res <= 0) { return ['Task not found', 404]; } // Vérifier que c'est bien la tâche de l'utilisateur if ($task->fk_user != $user->id) { return ['Forbidden', 403]; } $mapper = new dmTask(); return [$mapper->exportMappedData($task), 200]; } public function create($payload = null) { global $db, $user; if (empty($payload['label'])) { return ['Label required', 400]; } require_once DOL_DOCUMENT_ROOT . '/custom/monmodule/class/task.class.php'; $task = new \Task($db); $task->label = $payload['label']; $task->description = $payload['description'] ?? ''; $task->status = $payload['status'] ?? 1; $task->priority = $payload['priority'] ?? 0; $task->date_start = $payload['date_start'] ?? null; $task->date_end = $payload['date_end'] ?? null; $res = $task->create($user); if ($res < 0) { return ['Error: ' . $task->error, 500]; } return [['id' => $res], 201]; } public function update($payload = null) { global $db, $user; $id = $payload['id'] ?? null; require_once DOL_DOCUMENT_ROOT . '/custom/monmodule/class/task.class.php'; $task = new \Task($db); $res = $task->fetch($id); if ($res <= 0) { return ['Task not found', 404]; } if ($task->fk_user != $user->id) { return ['Forbidden', 403]; } // Mise à jour des champs if (isset($payload['label'])) $task->label = $payload['label']; if (isset($payload['description'])) $task->description = $payload['description']; if (isset($payload['status'])) $task->status = $payload['status']; if (isset($payload['priority'])) $task->priority = $payload['priority']; if (isset($payload['date_start'])) $task->date_start = $payload['date_start']; if (isset($payload['date_end'])) $task->date_end = $payload['date_end']; $res = $task->update($user); if ($res < 0) { return ['Error: ' . $task->error, 500]; } return ['Updated', 200]; } public function delete($payload = null) { global $db, $user; $id = $payload['id'] ?? null; require_once DOL_DOCUMENT_ROOT . '/custom/monmodule/class/task.class.php'; $task = new \Task($db); $res = $task->fetch($id); if ($res <= 0) { return ['Task not found', 404]; } if ($task->fk_user != $user->id) { return ['Forbidden', 403]; } $res = $task->delete($user); if ($res < 0) { return ['Error: ' . $task->error, 500]; } return ['Deleted', 200]; } }
4. Mapper
- snippet.php
<?php // smartmaker-api/Mappers/dmTask.php namespace MonModule\Api\Mappers; class dmTask extends \SmartAuth\DolibarrMapping\dmBase { use \SmartAuth\DolibarrMapping\dmTrait; protected $type = "object"; protected $parentClassName = 'Task'; protected $listOfPublishedFields = [ 'rowid' => 'id', 'ref' => 'ref', 'label' => 'label', 'description' => 'description', 'status' => 'status', 'priority' => 'priority', 'date_start' => 'date_start', 'date_end' => 'date_end', 'date_creation' => 'created_at' ]; public function __construct() { $this->boot(); } public function fieldFilterValueStatus($object) { $labels = [ 0 => 'draft', 1 => 'todo', 2 => 'done' ]; return $labels[$object->status] ?? 'unknown'; } public function fieldFilterValueDateStart($object) { return $object->date_start ? date('Y-m-d', $object->date_start) : null; } public function fieldFilterValueDateEnd($object) { return $object->date_end ? date('Y-m-d', $object->date_end) : null; } }
Test de l'API
Avec curl ou Postman :
- snippet.bash
# Login curl -X POST https://monsite.com/modules/monmodule/pwa/api.php \ -H "Content-Type: application/json" \ -d '{"login":"user@example.com","password":"secret"}' # Liste des tâches curl https://monsite.com/modules/monmodule/pwa/api.php?route=tasks \ -H "Authorization: Bearer <token>" # Créer une tâche curl -X POST https://monsite.com/modules/monmodule/pwa/api.php?route=tasks \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{"label":"Ma tâche","priority":1}'