SmarMaker - Documentation
Docs» 15_training:module9-integration:backend

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}'

← Retour au module | Chapitre suivant : Frontend →

Previous Next

Made with ❤ by CAP-REL · SmartMaker · GNU AGPL v3+
Code source · Faire un don
SmarMaker - Documentation
Traductions de cette page:
  • Français
  • Deutsch
  • English
  • Español
  • Italiano
  • Nederlands

Table of Contents

Table des matières

  • Chapitre 1 : Backend
    • 1. Classe Dolibarr (optionnel)
    • 2. Routes API
    • 3. Controller
    • 4. Mapper
    • Test de l'API
  • SmartAuth
  • SmartMaker - Back (PHP)
    • Mapping Dolibarr - React
  • SmartMaker - Front (React)
    • Animations de pages
    • Architecture
    • Astuces
    • Calendar
    • Composants et pages
    • Configuration du Provider
    • Debug et Logs
    • Hooks SmartCommon
    • PWA (Progressive Web App)
    • Requêtes API
    • Routage
    • SmartCommon
    • Stockage de données
    • Thèmes
    • Traductions
  • HowTo - Pas à pas - Votre première application
    • Développement PHP (back)
    • Développement React (front)
    • Première étape : Module Builder Dolibarr
    • SmartAuth
    • SmartBoot : Un "squelette" quasiment prêt à l'emploi
  • Formation SmartMaker
    • Module 1 : Fondamentaux JavaScript ES6+
      • Chapitre 1 : Variables et Scope
      • Chapitre 2 : Fonctions
      • Chapitre 3 : Programmation Asynchrone
      • Chapitre 4 : Modules ES6
    • Module 2 : Introduction à React
      • Chapitre 1 : Philosophie React
      • Chapitre 2 : JSX
      • Chapitre 3 : Composants
    • Module 3 : Hooks React Fondamentaux
      • Chapitre 1 : useState
      • Chapitre 2 : useEffect
      • Chapitre 3 : useRef
      • Chapitre 4 : useContext
    • Module 4 : React Avancé
      • Chapitre 1 : useCallback et useMemo
      • Chapitre 2 : Custom Hooks
      • Chapitre 3 : Redux et Redux Toolkit
    • Module 5 : Architecture SmartMaker
      • Chapitre 1 : Structure du projet
      • Chapitre 2 : Configuration
      • Chapitre 3 : Flux de données
    • Module 6 : SmartCommon - Composants
      • Chapitre 1 : Mise en page
      • Chapitre 2 : Navigation
      • Chapitre 3 : Formulaires
      • Chapitre 4 : Affichage
    • Module 7 : SmartCommon - Hooks
      • Chapitre 1 : useApi
      • Chapitre 2 : Gestion d'état
      • Chapitre 3 : Hooks utilitaires
    • Module 8 : Backend API (PHP)
      • Chapitre 1 : Routage
      • Chapitre 2 : Controllers
      • Chapitre 3 : Mappers
      • Extrafields et formulaires dynamiques
    • Module 9 : Intégration complète
      • Chapitre 1 : Backend
      • Chapitre 2 : Frontend
      • Chapitre 3 : Déploiement
    • Module 10 : Fonctionnalités avancées
      • Chapitre 1 : Mode offline
      • Chapitre 2 : Internationalisation (i18n)
      • Chapitre 3 : Autres fonctionnalités
    • Module 11 : Bonnes pratiques
  • Démonstration
  • Start
  • Composants et pages
  • Afficher le texte source
  • Anciennes révisions
  • Liens de retour
  • Haut de page