# Arcadia API PHP Client [![PHP Version](https://img.shields.io/badge/php-^8.5-blue.svg)](https://www.php.net/) [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE) [![Tests: Pest](https://img.shields.io/badge/tests-Pest%20PHP-purple.svg)](https://pestphp.com/) [![PHPStan: Level 10](https://img.shields.io/badge/phpstan-level%2010-brightgreen.svg)](https://phpstan.org/) Client PHP haut niveau, fortement typé et orienté domaine pour l'API Arcadia. Il s'appuie sur le client OpenAPI généré par Kiota (`uwil/arcadia-kiota-open-api-client`) et fournit : - Une couche de services métier (`EmployeeService`, `IncoService`, `BrandService`, `ApiService`). - Des Value Objects stricts (`ArcadiaEmployeeId`, `IncoId`, `IncoCompoId`, `BrandCode`, `SiteId`, etc.). - Des DTOs riches (`Employee`, `Inco`, `IncoCompo`, `IncoShort`, `Brand`) avec typage complet et conformité `JsonSerializable`. - Une gestion unifiée de la pagination (`PageOf`, `Pagination`) et du parcours continu par flux (`StreamOf`). - L'authentification automatique avec signature HMAC (`HMAC-SHA256`) et gestion des nonces. - Le support de la journalisation (PSR-3 `LoggerInterface`) et de l'observabilité (OpenTelemetry). - Une gestion explicite des erreurs via la hiérarchie `ApiError`. --- ## Sommaire - [Prérequis](#prérequis) - [Installation](#installation) - [Initialisation](#initialisation) - [Services et Utilisation](#services-et-utilisation) - [Vérification de l'API (`apiService`)](#vérification-de-lapi-apiservice) - [Gestion des Collaborateurs (`employees`)](#gestion-des-collaborateurs-employees) - [Fiches INCO & Compositions (`incoSheets`)](#fiches-inco--compositions-incosheets) - [Gestion des Marques (`brands`)](#gestion-des-marques-brands) - [Pagination et Streaming](#pagination-et-streaming) - [Gestion des Erreurs](#gestion-des-erreurs) - [Tests et Qualité](#tests-et-qualité) - [Licence](#licence) --- ## Prérequis - **PHP 8.5+** - Extensions PHP : `ext-curl`, `ext-mbstring` - Accès au registre GitLab Composer de LDC Digital --- ## Installation Comme cette bibliothèque et sa sous-dépendance Kiota sont hébergées sur le registre privé GitLab de LDC, configurez le dépôt Composer dans le `composer.json` de votre projet : ```json { "repositories": [ { "type": "composer", "url": "https://lab.s-web.fr/api/v4/group/23/-/packages/composer/packages.json" } ] } ``` Puis installez le client via Composer : ```bash composer require uwil/arcadia-api-php-client ``` Assurez-vous d'avoir configuré vos identifiants d'accès GitLab pour Composer (via `auth.json` ou variable d'environnement CI) : ```bash composer config gitlab-token.lab.s-web.fr ``` --- ## Initialisation L'entrée principale de la bibliothèque est [`ArcadiaApiClient`](src/ArcadiaApiClient.php), configurée avec [`ApiConfig`](src/Lib/ApiConfig.php) : ```php use GuzzleHttp\Psr7\Utils; use Uwil\ArcadiaApiPhpClient\ArcadiaApiClient; use Uwil\ArcadiaApiPhpClient\Auth\ClientIdentifier; use Uwil\ArcadiaApiPhpClient\Auth\ClientSecret; use Uwil\ArcadiaApiPhpClient\Lib\ApiConfig; $config = new ApiConfig( endpoint: Utils::uriFor('https://arcadia-api.domain.tld/api'), apiKey: new ClientIdentifier('VOTRE_API_KEY'), secret: new ClientSecret('VOTRE_SECRET_KEY'), curlTimeOut: 20.0, // secondes (optionnel, défaut: 20.0) maxRetries: 3, // tentatives en cas d'erreur réseau (optionnel, défaut: 0) retryDelaySeconds: 1, // délai entre les retries (optionnel, défaut: 1) ignoreSelfSignedCert: false, // pour environnements locaux de test (défaut: false) logger: null, // ?Psr\Log\LoggerInterface tracer: null, // ?OpenTelemetry\API\Trace\TracerInterface ); $client = new ArcadiaApiClient($config); ``` --- ## Services et Utilisation ### Vérification de l'API (`apiService`) Permet de vérifier la disponibilité et la santé de l'API Arcadia : ```php $isAlive = $client->apiService()->isAlive(); if ($isAlive) { echo "L'API Arcadia est joignable et opérationnelle.\n"; } ``` --- ### Gestion des Collaborateurs (`employees`) Le service [`EmployeeService`](src/Service/EmployeeService.php) permet de consulter et rechercher les salariés. #### Récupérer par identifiant ```php use Uwil\ArcadiaApiPhpClient\Lib\ApiValueObject\ArcadiaEmployeeId; use Uwil\ArcadiaApiPhpClient\Error\ApiError; $employee = $client->employees()->findBy(new ArcadiaEmployeeId('0115590')); if ($employee instanceof ApiError) { echo "Erreur API: " . $employee->getMessage(); } elseif ($employee === null) { echo "Collaborateur non trouvé (404).\n"; } else { echo "Salarié: {$employee->firstname} {$employee->lastname} (Site: {$employee->site})\n"; } ``` #### Récupérer par site(s) ```php use Uwil\ArcadiaApiPhpClient\Lib\ApiValueObject\SiteId; use Uwil\ArcadiaApiPhpClient\Lib\ApiSorter\EmployeeSorter; use Uwil\ArcadiaApiPhpClient\Lib\ApiSorter\EmployeeSortColumn; // Pour un site unique avec tri par matricule $page = $client->employees()->getAllOfSites( new SiteId('01'), new EmployeeSorter(EmployeeSortColumn::MATRICULE, 'asc') ); // Pour plusieurs sites modifiés depuis une date $page = $client->employees()->getAllOfSitesSince( [new SiteId('01'), new SiteId('02')], new DateTimeImmutable('2026-01-01') ); ``` #### Streaming de tous les collaborateurs Le streaming parcourt automatiquement toutes les pages de façon transparente grâce à un générateur PHP : ```php foreach ($client->employees()->streamAll() as $employee) { echo "{$employee->matricule} - {$employee->lastname}\n"; } ``` --- ### Fiches INCO & Compositions (`incoSheets`) Le service [`IncoService`](src/Service/IncoService.php) gère les fiches techniques produit (INCO) et leurs compositions nutritionnelles détaillées. #### Consulter une fiche INCO ```php use Uwil\ArcadiaApiPhpClient\Lib\ApiValueObject\IncoId; $inco = $client->incoSheets()->findBy(new IncoId('12345')); if ($inco !== null && !($inco instanceof ApiError)) { echo "Fiche: {$inco->commercialLabel}\n"; echo "Nutri-Score: {$inco->nutriscore?->grade}\n"; } ``` #### Consulter la composition nutritionnelle Vous pouvez interroger la composition par son `IncoCompoId` ou directement par l'`IncoId` : ```php use Uwil\ArcadiaApiPhpClient\Lib\ApiValueObject\IncoCompoId; // Directement via IncoCompoId $compo = $client->incoSheets()->findCompo(new IncoCompoId('98765')); // Ou via IncoId $compo = $client->incoSheets()->findCompo(new IncoId('12345')); if ($compo !== null && !($compo instanceof ApiError)) { echo "Énergie (kJ): {$compo->energy?->kJ?->value}\n"; echo "Acides gras saturés: {$compo->fattyAcids?->saturatedFattyAcids?->value}\n"; echo "Points Nutri-Score: {$compo->nutriScorePoints?->totalPoints}\n"; } ``` #### Recherche et listage par marque ```php use Uwil\ArcadiaApiPhpClient\Lib\ApiValueObject\BrandCode; // Liste courte (IncoShort) pour optimiser les performances d'affichage $shortsPage = $client->incoSheets()->getAllShortOfBrands(new BrandCode('GAULOIS')); // Recherche par motif d'identifiant $results = $client->incoSheets()->findByIncoIdLike('POULET%', new BrandCode('GAULOIS')); // Streaming de toutes les fiches d'une marque foreach ($client->incoSheets()->streamAllOfBrands(new BrandCode('LEGAULOIS')) as $sheet) { echo "Fiche #{$sheet->id->value}: {$sheet->commercialLabel}\n"; } ``` --- ### Gestion des Marques (`brands`) Le service [`BrandService`](src/Service/BrandService.php) donne accès aux marques référencées : ```php use Uwil\ArcadiaApiPhpClient\Lib\ApiValueObject\BrandCode; // Récupérer une marque $brand = $client->brands()->findBy(new BrandCode('GAULOIS')); // Parcourir toutes les marques foreach ($client->brands()->streamAll() as $brand) { echo "Marque [{$brand->code->value}] : {$brand->label}\n"; } ``` --- ## Pagination et Streaming ### Objet `PageOf` Toutes les méthodes de liste paginées retournent un objet [`PageOf`](src/Lib/ApiDto/Dto/PageOf.php) contenant les éléments et les métadonnées de pagination : ```php $page = $client->employees()->getAll(); // Éléments de la page courante $employees = $page->items; // Métadonnées echo "Page actuelle : " . $page->pagination->pageNumber->value . "\n"; echo "Taille de page : " . $page->pagination->pageSize->value . "\n"; echo "Total éléments : " . $page->pagination->totalItems . "\n"; echo "Total pages : " . $page->pagination->totalPages . "\n"; ``` ### Objet `StreamOf` Toutes les méthodes `stream*()` retournent un [`StreamOf`](src/Lib/Pagination/StreamOf.php) qui implémente `\IteratorAggregate`. Il effectue les requêtes de page suivante automatiquement à la demande : ```php $stream = $client->employees()->streamAll(); foreach ($stream as $employee) { // Les pages suivantes sont chargées en arrière-plan au fur et à mesure de l'itération } ``` --- ## Gestion des Erreurs Les méthodes du client ne lancent pas d'exceptions inattendues pour les erreurs HTTP ou de communication ; elles renvoient une instance de [`ApiError`](src/Error/ApiError.php) (ou ses sous-classes spécialisées) : ```php use Uwil\ArcadiaApiPhpClient\Error\AuthenticationError; use Uwil\ArcadiaApiPhpClient\Error\ValidationError; use Uwil\ArcadiaApiPhpClient\Error\NetworkError; use Uwil\ArcadiaApiPhpClient\Error\RateLimitError; use Uwil\ArcadiaApiPhpClient\Error\ServerError; use Uwil\ArcadiaApiPhpClient\Error\ApiError; $result = $client->employees()->findBy(new ArcadiaEmployeeId('0115590')); match (true) { $result instanceof AuthenticationError => logAuthFailure($result), $result instanceof ValidationError => logValidationDetails($result->getViolations()), $result instanceof NetworkError => retryLater($result), $result instanceof RateLimitError => handleRateLimit($result), $result instanceof ServerError => notifyAdmin($result), $result instanceof ApiError => logGenericError($result), $result === null => handleNotFound(), default => handleEmployee($result), }; ``` --- ## Tests et Qualité Le projet est rigoureusement testé avec une suite complète de tests unitaires et d'architecture. ```bash # Lancer les tests unitaires composer test # Vérifier la couverture de code (seuil minimal 85% configuré) composer test:coverage # Analyse statique PHPStan (niveau 10) composer lint:phpstan # Vérifier le style du code (Laravel Pint) composer lint:pint # Formater le code automatiquement composer format ``` --- ## Licence Ce projet est sous licence MIT. Consultez le fichier [LICENSE](LICENSE) pour plus d'informations.