325 lines
11 KiB
Markdown
325 lines
11 KiB
Markdown
# Arcadia API PHP Client
|
|
|
|
[](https://www.php.net/)
|
|
[](LICENSE)
|
|
[](https://pestphp.com/)
|
|
[](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 <deploy-token-user> <deploy-token-password>
|
|
```
|
|
|
|
---
|
|
|
|
## 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<T>`](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<T>`](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.
|