feat : restructuration des dossiers pour implementer plus facilement la suite des WS
This commit is contained in:
@@ -1,112 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Malio\EdnotifBundle\Api;
|
||||
|
||||
use Malio\EdnotifBundle\Auth\TokenProvider;
|
||||
use Malio\EdnotifBundle\Dto\DossierAnimalDto;
|
||||
use Malio\EdnotifBundle\Exception\EdnotifException;
|
||||
use SoapClient;
|
||||
use SoapFault;
|
||||
|
||||
final class BovinApi implements BovinApiInterface
|
||||
{
|
||||
public function __construct(
|
||||
private TokenProvider $tokenProvider,
|
||||
private SoapClient $metierClient,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getDossierAnimal(string $exploitationNumero, string $numeroNational, string $codePays = 'FR'): DossierAnimalDto
|
||||
{
|
||||
$token = $this->tokenProvider->getToken();
|
||||
|
||||
$payload = [[
|
||||
'JetonAuthentification' => $token,
|
||||
'Exploitation' => [
|
||||
'CodePays' => $codePays,
|
||||
'NumeroExploitation' => $exploitationNumero,
|
||||
],
|
||||
'Bovin' => [
|
||||
'CodePays' => $codePays,
|
||||
'NumeroNational' => $numeroNational,
|
||||
],
|
||||
]];
|
||||
|
||||
try {
|
||||
/** @var object $response */
|
||||
$response = $this->metierClient->__soapCall('IpBGetDossierAnimal', $payload);
|
||||
} catch (SoapFault $e) {
|
||||
// Si c’est un souci de jeton, tu peux invalider et retenter une fois (optionnel)
|
||||
throw new \RuntimeException('SOAP Fault lors de IpBGetDossierAnimal: ' . $e->getMessage(), 0, $e);
|
||||
}
|
||||
|
||||
$rs = $response->ReponseStandard ?? null;
|
||||
$ok = is_object($rs) && (($rs->Resultat ?? false) === true);
|
||||
|
||||
if (!$ok) {
|
||||
$anom = $rs->Anomalie ?? null;
|
||||
$code = (string)($anom->Code ?? 'UNKNOWN');
|
||||
$sev = (int)($anom->Severite ?? 1);
|
||||
$msg = (string)($anom->Message ?? 'Appel EDNOTIF refusé');
|
||||
throw new EdnotifException($code, $sev, $msg);
|
||||
}
|
||||
|
||||
$identite = [];
|
||||
$periodes = [];
|
||||
|
||||
$bovinNode = $response->ReponseSpecifique->Bovin ?? null;
|
||||
if (is_object($bovinNode)) {
|
||||
$identiteObj = $bovinNode->IdentiteBovin ?? null;
|
||||
if (is_object($identiteObj)) {
|
||||
$identite = $this->objectToArray($identiteObj);
|
||||
}
|
||||
|
||||
$pp = $bovinNode->PeriodesPresences->PeriodePresence ?? null;
|
||||
foreach ($this->normalizeList($pp) as $periode) {
|
||||
if (!is_object($periode)) {
|
||||
continue;
|
||||
}
|
||||
$entree = is_object($periode->Entree ?? null) ? $this->objectToArray($periode->Entree) : [];
|
||||
$sortie = is_object($periode->Sortie ?? null) ? $this->objectToArray($periode->Sortie) : null;
|
||||
|
||||
$row = ['entree' => $entree];
|
||||
if ($sortie !== null) {
|
||||
$row['sortie'] = $sortie;
|
||||
}
|
||||
$periodes[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
return new DossierAnimalDto(
|
||||
numeroNational: $numeroNational,
|
||||
identiteBovin: $identite,
|
||||
periodesPresence: $periodes,
|
||||
rawResponse: $response,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<mixed>
|
||||
*/
|
||||
private function normalizeList(mixed $value): array
|
||||
{
|
||||
if ($value === null) {
|
||||
return [];
|
||||
}
|
||||
if (is_array($value)) {
|
||||
return $value;
|
||||
}
|
||||
return [$value];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
private function objectToArray(object $obj): array
|
||||
{
|
||||
// conversion simple (suffisante pour démarrer)
|
||||
return json_decode(json_encode($obj, JSON_THROW_ON_ERROR), true, 512, JSON_THROW_ON_ERROR);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Malio\EdnotifBundle\Api;
|
||||
|
||||
use Malio\EdnotifBundle\Dto\DossierAnimalDto;
|
||||
|
||||
interface BovinApiInterface
|
||||
{
|
||||
public function getDossierAnimal(
|
||||
string $exploitationNumero,
|
||||
string $numeroNational,
|
||||
string $codePays = 'FR'
|
||||
): DossierAnimalDto;
|
||||
}
|
||||
@@ -4,12 +4,14 @@ declare(strict_types=1);
|
||||
|
||||
namespace Malio\EdnotifBundle\Auth;
|
||||
|
||||
use Malio\EdnotifBundle\Exception\EdnotifException;
|
||||
use Malio\EdnotifBundle\Shared\Exception\EdnotifException;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Psr\Cache\InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use SoapClient;
|
||||
use SoapFault;
|
||||
|
||||
final class TokenProvider
|
||||
final readonly class TokenProvider
|
||||
{
|
||||
public function __construct(
|
||||
private SoapClient $guichetClient,
|
||||
@@ -20,17 +22,19 @@ final class TokenProvider
|
||||
private string $password,
|
||||
private int $tokenTtlSeconds,
|
||||
private CacheItemPoolInterface $cachePool,
|
||||
) {
|
||||
}
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function getToken(): string
|
||||
{
|
||||
$cacheKey = $this->getCacheKey();
|
||||
$item = $this->cachePool->getItem($cacheKey);
|
||||
$item = $this->cachePool->getItem($cacheKey);
|
||||
|
||||
if ($item->isHit()) {
|
||||
$token = $item->get();
|
||||
if (is_string($token) && $token !== '') {
|
||||
if (is_string($token) && '' !== $token) {
|
||||
return $token;
|
||||
}
|
||||
}
|
||||
@@ -44,6 +48,9 @@ final class TokenProvider
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function invalidateToken(): void
|
||||
{
|
||||
$this->cachePool->deleteItem($this->getCacheKey());
|
||||
@@ -52,16 +59,16 @@ final class TokenProvider
|
||||
private function createToken(): string
|
||||
{
|
||||
$profil = array_filter([
|
||||
'Entreprise' => $this->entreprise,
|
||||
'Zone' => $this->zone,
|
||||
'Entreprise' => $this->entreprise,
|
||||
'Zone' => $this->zone,
|
||||
'Application' => $this->application,
|
||||
], static fn ($v) => $v !== null && $v !== '');
|
||||
], static fn ($v) => null !== $v && '' !== $v);
|
||||
|
||||
$payload = [
|
||||
'Identification' => [
|
||||
'UserId' => $this->login,
|
||||
'UserId' => $this->login,
|
||||
'Password' => $this->password,
|
||||
'Profil' => $profil,
|
||||
'Profil' => $profil,
|
||||
],
|
||||
];
|
||||
|
||||
@@ -69,7 +76,7 @@ final class TokenProvider
|
||||
/** @var object $response */
|
||||
$response = $this->guichetClient->__soapCall('tkCreateIdentification', [$payload]);
|
||||
} catch (SoapFault $e) {
|
||||
throw new \RuntimeException('SOAP Fault lors de tkCreateIdentification: ' . $e->getMessage(), 0, $e);
|
||||
throw new RuntimeException('SOAP Fault lors de tkCreateIdentification: '.$e->getMessage(), 0, $e);
|
||||
}
|
||||
|
||||
$rs = $response->ReponseStandard ?? null;
|
||||
@@ -77,15 +84,16 @@ final class TokenProvider
|
||||
|
||||
if (!$ok) {
|
||||
$anom = $rs->Anomalie ?? null;
|
||||
$code = (string)($anom->Code ?? 'UNKNOWN');
|
||||
$sev = (int)($anom->Severite ?? 1);
|
||||
$msg = (string)($anom->Message ?? 'Authentification refusée');
|
||||
$code = (string) ($anom->Code ?? 'UNKNOWN');
|
||||
$sev = (int) ($anom->Severite ?? 1);
|
||||
$msg = (string) ($anom->Message ?? 'Authentification refusée');
|
||||
|
||||
throw new EdnotifException($code, $sev, $msg);
|
||||
}
|
||||
|
||||
$token = $response->Jeton ?? null;
|
||||
if (!is_string($token) || $token === '') {
|
||||
throw new \RuntimeException('Guichet: réponse OK mais Jeton absent.');
|
||||
if (!is_string($token) || '' === $token) {
|
||||
throw new RuntimeException('Guichet: réponse OK mais Jeton absent.');
|
||||
}
|
||||
|
||||
return $token;
|
||||
@@ -93,6 +101,6 @@ final class TokenProvider
|
||||
|
||||
private function getCacheKey(): string
|
||||
{
|
||||
return 'ednotif.token.' . hash('sha256', $this->entreprise . '|' . $this->login);
|
||||
return 'ednotif.token.'.hash('sha256', $this->entreprise.'|'.$this->login);
|
||||
}
|
||||
}
|
||||
|
||||
64
src/Bovin/Api/BovinApi.php
Normal file
64
src/Bovin/Api/BovinApi.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Malio\EdnotifBundle\Bovin\Api;
|
||||
|
||||
use Malio\EdnotifBundle\Auth\TokenProvider;
|
||||
use Malio\EdnotifBundle\Bovin\Dto\AnimalFileDto;
|
||||
use Malio\EdnotifBundle\Bovin\Mapper\AnimalFileMapper;
|
||||
use Malio\EdnotifBundle\Shared\Exception\EdnotifException;
|
||||
use RuntimeException;
|
||||
use SoapClient;
|
||||
use SoapFault;
|
||||
|
||||
final readonly class BovinApi implements BovinApiInterface
|
||||
{
|
||||
public function __construct(
|
||||
private TokenProvider $tokenProvider,
|
||||
private SoapClient $businessClient,
|
||||
private AnimalFileMapper $bovinDossierMapper,
|
||||
private string $exploitationCountryCode,
|
||||
private string $exploitationNumber,
|
||||
) {}
|
||||
|
||||
public function getAnimalFile(string $nationalNumber, string $countryCode = 'FR'): AnimalFileDto
|
||||
{
|
||||
$token = $this->tokenProvider->getToken();
|
||||
|
||||
$requestPayload = [[
|
||||
'JetonAuthentification' => $token,
|
||||
'Exploitation' => [
|
||||
'CodePays' => $this->exploitationCountryCode,
|
||||
'NumeroExploitation' => $this->exploitationNumber,
|
||||
],
|
||||
'Bovin' => [
|
||||
'CodePays' => $countryCode,
|
||||
'NumeroNational' => $nationalNumber,
|
||||
],
|
||||
]];
|
||||
|
||||
try {
|
||||
/** @var object $soapResponse */
|
||||
$soapResponse = $this->businessClient->__soapCall('IpBGetDossierAnimal', $requestPayload);
|
||||
} catch (SoapFault $soapFault) {
|
||||
throw new RuntimeException('SOAP Fault on IpBGetDossierAnimal: '.$soapFault->getMessage(), 0, $soapFault);
|
||||
}
|
||||
|
||||
// Throw uniquement si Resultat=false (erreur métier)
|
||||
$standardResponseNode = $soapResponse->ReponseStandard ?? null;
|
||||
$isOk = is_object($standardResponseNode) && (($standardResponseNode->Resultat ?? false) === true);
|
||||
|
||||
if (!$isOk) {
|
||||
$anomalyNode = is_object($standardResponseNode) ? ($standardResponseNode->Anomalie ?? null) : null;
|
||||
|
||||
throw new EdnotifException(
|
||||
codeAnomalie: (string) ($anomalyNode->Code ?? 'UNKNOWN'),
|
||||
severite: (int) ($anomalyNode->Severite ?? 1),
|
||||
message: (string) ($anomalyNode->Message ?? 'EDNOTIF error')
|
||||
);
|
||||
}
|
||||
|
||||
return $this->bovinDossierMapper->map($soapResponse);
|
||||
}
|
||||
}
|
||||
12
src/Bovin/Api/BovinApiInterface.php
Normal file
12
src/Bovin/Api/BovinApiInterface.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Malio\EdnotifBundle\Bovin\Api;
|
||||
|
||||
use Malio\EdnotifBundle\Bovin\Dto\AnimalFileDto;
|
||||
|
||||
interface BovinApiInterface
|
||||
{
|
||||
public function getAnimalFile(string $nationalNumber, string $countryCode = 'FR'): AnimalFileDto;
|
||||
}
|
||||
20
src/Bovin/Dto/AnimalFileDto.php
Normal file
20
src/Bovin/Dto/AnimalFileDto.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Malio\EdnotifBundle\Bovin\Dto;
|
||||
|
||||
use Malio\EdnotifBundle\Shared\Dto\StandardResponseDto;
|
||||
|
||||
final readonly class AnimalFileDto
|
||||
{
|
||||
/**
|
||||
* @param list<PresencePeriodDto> $presencePeriods
|
||||
*/
|
||||
public function __construct(
|
||||
public StandardResponseDto $standardResponse,
|
||||
public ?BovinIdentificationDto $identification,
|
||||
public array $presencePeriods,
|
||||
public ?object $rawSoapResponse, // pour garder 100% des data
|
||||
) {}
|
||||
}
|
||||
20
src/Bovin/Dto/BovinIdentificationDto.php
Normal file
20
src/Bovin/Dto/BovinIdentificationDto.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Malio\EdnotifBundle\Bovin\Dto;
|
||||
|
||||
final readonly class BovinIdentificationDto
|
||||
{
|
||||
public function __construct(
|
||||
public ?BovinRef $bovin,
|
||||
public ?string $sex,
|
||||
public ?string $breedType,
|
||||
public ?DateValueDto $birthDate,
|
||||
public ?string $workNumber,
|
||||
public ?bool $isFilie,
|
||||
public ?ParentInfoDto $motherCarrier,
|
||||
public ?ParentInfoDto $fatherIpg,
|
||||
public ?ExploitationRef $birthExploitation,
|
||||
) {}
|
||||
}
|
||||
13
src/Bovin/Dto/BovinRef.php
Normal file
13
src/Bovin/Dto/BovinRef.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Malio\EdnotifBundle\Bovin\Dto;
|
||||
|
||||
final readonly class BovinRef
|
||||
{
|
||||
public function __construct(
|
||||
public ?string $countryCode,
|
||||
public ?string $nationalNumber,
|
||||
) {}
|
||||
}
|
||||
15
src/Bovin/Dto/DateValueDto.php
Normal file
15
src/Bovin/Dto/DateValueDto.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Malio\EdnotifBundle\Bovin\Dto;
|
||||
|
||||
use DateTimeImmutable;
|
||||
|
||||
final readonly class DateValueDto
|
||||
{
|
||||
public function __construct(
|
||||
public ?DateTimeImmutable $date,
|
||||
public ?string $completenessFlag,
|
||||
) {}
|
||||
}
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Malio\EdnotifBundle\Dto;
|
||||
namespace Malio\EdnotifBundle\Bovin\Dto;
|
||||
|
||||
final readonly class DossierAnimalDto
|
||||
{
|
||||
/**
|
||||
* @param array<string,mixed> $identiteBovin
|
||||
* @param array<string,mixed> $identiteBovin
|
||||
* @param list<array{entree: array<string,mixed>, sortie?: array<string,mixed>}> $periodesPresence
|
||||
*/
|
||||
public function __construct(
|
||||
@@ -15,6 +15,5 @@ final readonly class DossierAnimalDto
|
||||
public array $identiteBovin,
|
||||
public array $periodesPresence,
|
||||
public object $rawResponse,
|
||||
) {
|
||||
}
|
||||
) {}
|
||||
}
|
||||
13
src/Bovin/Dto/ExploitationRef.php
Normal file
13
src/Bovin/Dto/ExploitationRef.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Malio\EdnotifBundle\Bovin\Dto;
|
||||
|
||||
final readonly class ExploitationRef
|
||||
{
|
||||
public function __construct(
|
||||
public ?string $countryCode,
|
||||
public ?string $exploitationNumber,
|
||||
) {}
|
||||
}
|
||||
16
src/Bovin/Dto/MovementDto.php
Normal file
16
src/Bovin/Dto/MovementDto.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Malio\EdnotifBundle\Bovin\Dto;
|
||||
|
||||
use DateTimeImmutable;
|
||||
|
||||
final readonly class MovementDto
|
||||
{
|
||||
public function __construct(
|
||||
public ?DateTimeImmutable $date,
|
||||
public ?string $cause,
|
||||
public ?ExploitationRef $exploitation,
|
||||
) {}
|
||||
}
|
||||
13
src/Bovin/Dto/ParentInfoDto.php
Normal file
13
src/Bovin/Dto/ParentInfoDto.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Malio\EdnotifBundle\Bovin\Dto;
|
||||
|
||||
final readonly class ParentInfoDto
|
||||
{
|
||||
public function __construct(
|
||||
public ?BovinRef $bovin,
|
||||
public ?string $breedType,
|
||||
) {}
|
||||
}
|
||||
13
src/Bovin/Dto/PresencePeriodDto.php
Normal file
13
src/Bovin/Dto/PresencePeriodDto.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Malio\EdnotifBundle\Bovin\Dto;
|
||||
|
||||
final readonly class PresencePeriodDto
|
||||
{
|
||||
public function __construct(
|
||||
public ?MovementDto $entry,
|
||||
public ?MovementDto $exit,
|
||||
) {}
|
||||
}
|
||||
235
src/Bovin/Mapper/AnimalFileMapper.php
Normal file
235
src/Bovin/Mapper/AnimalFileMapper.php
Normal file
@@ -0,0 +1,235 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Malio\EdnotifBundle\Bovin\Mapper;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use Malio\EdnotifBundle\Bovin\Dto\AnimalFileDto;
|
||||
use Malio\EdnotifBundle\Bovin\Dto\BovinIdentificationDto;
|
||||
use Malio\EdnotifBundle\Bovin\Dto\BovinRef;
|
||||
use Malio\EdnotifBundle\Bovin\Dto\DateValueDto;
|
||||
use Malio\EdnotifBundle\Bovin\Dto\ExploitationRef;
|
||||
use Malio\EdnotifBundle\Bovin\Dto\MovementDto;
|
||||
use Malio\EdnotifBundle\Bovin\Dto\ParentInfoDto;
|
||||
use Malio\EdnotifBundle\Bovin\Dto\PresencePeriodDto;
|
||||
use Malio\EdnotifBundle\Shared\Dto\AnomalyDto;
|
||||
use Malio\EdnotifBundle\Shared\Dto\StandardResponseDto;
|
||||
use Throwable;
|
||||
|
||||
final class AnimalFileMapper
|
||||
{
|
||||
public function map(object $soapResponse): AnimalFileDto
|
||||
{
|
||||
$standardResponse = $this->mapStandardResponse($soapResponse->ReponseStandard ?? null);
|
||||
|
||||
$specificResponseNode = $soapResponse->ReponseSpecifique ?? null;
|
||||
$bovinNode = is_object($specificResponseNode) ? ($specificResponseNode->Bovin ?? null) : null;
|
||||
|
||||
$identification = null;
|
||||
$presencePeriods = [];
|
||||
|
||||
if (is_object($bovinNode)) {
|
||||
$identificationNode = $bovinNode->IdentiteBovin ?? null;
|
||||
if (is_object($identificationNode)) {
|
||||
$identification = $this->mapIdentification($identificationNode);
|
||||
}
|
||||
|
||||
$presencePeriodsNode = $bovinNode->PeriodesPresences->PeriodePresence ?? null;
|
||||
foreach ($this->normalizeToList($presencePeriodsNode) as $presencePeriodNode) {
|
||||
if (!is_object($presencePeriodNode)) {
|
||||
continue;
|
||||
}
|
||||
$presencePeriods[] = $this->mapPresencePeriod($presencePeriodNode);
|
||||
}
|
||||
}
|
||||
|
||||
return new AnimalFileDto(
|
||||
standardResponse: $standardResponse,
|
||||
identification: $identification,
|
||||
presencePeriods: $presencePeriods,
|
||||
rawSoapResponse: $soapResponse
|
||||
);
|
||||
}
|
||||
|
||||
private function mapStandardResponse(mixed $standardResponseNode): StandardResponseDto
|
||||
{
|
||||
$result = (bool) ($standardResponseNode->Resultat ?? false);
|
||||
|
||||
$anomalyNode = $standardResponseNode->Anomalie ?? null;
|
||||
$anomaly = null;
|
||||
|
||||
if (is_object($anomalyNode)) {
|
||||
$anomaly = new AnomalyDto(
|
||||
code: $this->toNullableString($anomalyNode->Code ?? null),
|
||||
severity: $this->toNullableInt($anomalyNode->Severite ?? null),
|
||||
message: $this->toNullableString($anomalyNode->Message ?? null),
|
||||
);
|
||||
}
|
||||
|
||||
return new StandardResponseDto($result, $anomaly);
|
||||
}
|
||||
|
||||
private function mapIdentification(object $identificationNode): BovinIdentificationDto
|
||||
{
|
||||
$bovinRef = $this->mapBovinRef($identificationNode->Bovin ?? null);
|
||||
|
||||
$birthDate = null;
|
||||
$birthDateNode = $identificationNode->DateNaissance ?? null;
|
||||
if (is_object($birthDateNode)) {
|
||||
$birthDate = new DateValueDto(
|
||||
date: $this->toNullableDate($birthDateNode->Date ?? null),
|
||||
completenessFlag: $this->toNullableString($birthDateNode->TemoinCompletude ?? null),
|
||||
);
|
||||
}
|
||||
|
||||
$motherCarrier = $this->mapParentInfo($identificationNode->MerePorteuse ?? null);
|
||||
$fatherIpg = $this->mapParentInfo($identificationNode->PereIPG ?? null);
|
||||
$birthExploitation = $this->mapExploitationRef($identificationNode->ExploitationNaissance ?? null);
|
||||
|
||||
return new BovinIdentificationDto(
|
||||
bovin: $bovinRef,
|
||||
sex: $this->toNullableString($identificationNode->Sexe ?? null),
|
||||
breedType: $this->toNullableString($identificationNode->TypeRacial ?? null),
|
||||
birthDate: $birthDate,
|
||||
workNumber: $this->toNullableString($identificationNode->NumeroTravail ?? null),
|
||||
isFilie: $this->toNullableBool($identificationNode->StatutFilie ?? null),
|
||||
motherCarrier: $motherCarrier,
|
||||
fatherIpg: $fatherIpg,
|
||||
birthExploitation: $birthExploitation,
|
||||
);
|
||||
}
|
||||
|
||||
private function mapPresencePeriod(object $presencePeriodNode): PresencePeriodDto
|
||||
{
|
||||
$entryNode = $presencePeriodNode->Entree ?? null;
|
||||
$exitNode = $presencePeriodNode->Sortie ?? null;
|
||||
|
||||
$entryMovement = is_object($entryNode) ? $this->mapMovement($entryNode, 'entry') : null;
|
||||
$exitMovement = is_object($exitNode) ? $this->mapMovement($exitNode, 'exit') : null;
|
||||
|
||||
return new PresencePeriodDto(
|
||||
entry: $entryMovement,
|
||||
exit: $exitMovement,
|
||||
);
|
||||
}
|
||||
|
||||
private function mapMovement(object $movementNode, string $direction): MovementDto
|
||||
{
|
||||
$dateValue = null;
|
||||
$causeValue = null;
|
||||
|
||||
if ('entry' === $direction) {
|
||||
// SOAP: DateEntree / CauseEntree
|
||||
$dateValue = $movementNode->DateEntree ?? ($movementNode->Date ?? ($movementNode->DateMouvement ?? null));
|
||||
$causeValue = $movementNode->CauseEntree ?? null;
|
||||
} else {
|
||||
// SOAP (souvent): DateSortie / CauseSortie
|
||||
$dateValue = $movementNode->DateSortie ?? ($movementNode->Date ?? ($movementNode->DateMouvement ?? null));
|
||||
$causeValue = $movementNode->CauseSortie ?? null;
|
||||
}
|
||||
|
||||
$exploitationRef = $this->mapExploitationRef($movementNode->Exploitation ?? null);
|
||||
|
||||
return new MovementDto(
|
||||
date: $this->toNullableDate($dateValue),
|
||||
cause: $this->toNullableString($causeValue),
|
||||
exploitation: $exploitationRef,
|
||||
);
|
||||
}
|
||||
|
||||
private function mapParentInfo(mixed $parentNode): ?ParentInfoDto
|
||||
{
|
||||
if (!is_object($parentNode)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$bovinRef = $this->mapBovinRef($parentNode->Bovin ?? null);
|
||||
|
||||
return new ParentInfoDto(
|
||||
bovin: $bovinRef,
|
||||
breedType: $this->toNullableString($parentNode->TypeRacial ?? null),
|
||||
);
|
||||
}
|
||||
|
||||
private function mapBovinRef(mixed $bovinNode): ?BovinRef
|
||||
{
|
||||
if (!is_object($bovinNode)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new BovinRef(
|
||||
countryCode: $this->toNullableString($bovinNode->CodePays ?? null),
|
||||
nationalNumber: $this->toNullableString($bovinNode->NumeroNational ?? null),
|
||||
);
|
||||
}
|
||||
|
||||
private function mapExploitationRef(mixed $exploitationNode): ?ExploitationRef
|
||||
{
|
||||
if (!is_object($exploitationNode)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ExploitationRef(
|
||||
countryCode: $this->toNullableString($exploitationNode->CodePays ?? null),
|
||||
exploitationNumber: $this->toNullableString($exploitationNode->NumeroExploitation ?? null),
|
||||
);
|
||||
}
|
||||
|
||||
/** @return list<mixed> */
|
||||
private function normalizeToList(mixed $value): array
|
||||
{
|
||||
if (null === $value) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return is_array($value) ? $value : [$value];
|
||||
}
|
||||
|
||||
private function toNullableString(mixed $value): ?string
|
||||
{
|
||||
if (null === $value) {
|
||||
return null;
|
||||
}
|
||||
$stringValue = trim((string) $value);
|
||||
|
||||
return '' === $stringValue ? null : $stringValue;
|
||||
}
|
||||
|
||||
private function toNullableInt(mixed $value): ?int
|
||||
{
|
||||
if (null === $value) {
|
||||
return null;
|
||||
}
|
||||
if (is_int($value)) {
|
||||
return $value;
|
||||
}
|
||||
if (is_numeric($value)) {
|
||||
return (int) $value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function toNullableBool(mixed $value): ?bool
|
||||
{
|
||||
if (null === $value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (bool) $value;
|
||||
}
|
||||
|
||||
private function toNullableDate(mixed $value): ?DateTimeImmutable
|
||||
{
|
||||
if (!is_string($value) || '' === trim($value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return new DateTimeImmutable($value);
|
||||
} catch (Throwable) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,9 @@ namespace Malio\EdnotifBundle\DependencyInjection;
|
||||
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||
|
||||
use const SOAP_SINGLE_ELEMENT_ARRAYS;
|
||||
use const WSDL_CACHE_BOTH;
|
||||
|
||||
final class Configuration implements ConfigurationInterface
|
||||
{
|
||||
public function getConfigTreeBuilder(): TreeBuilder
|
||||
@@ -26,6 +29,9 @@ final class Configuration implements ConfigurationInterface
|
||||
->scalarNode('login')->cannotBeEmpty()->isRequired()->end()
|
||||
->scalarNode('password')->cannotBeEmpty()->isRequired()->end()
|
||||
|
||||
->scalarNode('exploitation_number')->cannotBeEmpty()->isRequired()->end()
|
||||
->scalarNode('exploitation_country_code')->defaultValue('FR')->end()
|
||||
|
||||
->integerNode('token_ttl_seconds')->min(30)->defaultValue(900)->end()
|
||||
|
||||
->arrayNode('soap_options')
|
||||
@@ -34,11 +40,12 @@ final class Configuration implements ConfigurationInterface
|
||||
->booleanNode('trace')->defaultFalse()->end()
|
||||
->booleanNode('exceptions')->defaultTrue()->end()
|
||||
->integerNode('connection_timeout')->min(1)->defaultValue(15)->end()
|
||||
->integerNode('cache_wsdl')->defaultValue(\WSDL_CACHE_BOTH)->end()
|
||||
->integerNode('features')->defaultValue(\SOAP_SINGLE_ELEMENT_ARRAYS)->end()
|
||||
->integerNode('cache_wsdl')->defaultValue(WSDL_CACHE_BOTH)->end()
|
||||
->integerNode('features')->defaultValue(SOAP_SINGLE_ELEMENT_ARRAYS)->end()
|
||||
->end()
|
||||
->end()
|
||||
->end();
|
||||
->end()
|
||||
;
|
||||
|
||||
return $treeBuilder;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ final class EdnotifExtension extends Extension
|
||||
public function load(array $configs, ContainerBuilder $container): void
|
||||
{
|
||||
$configuration = new Configuration();
|
||||
|
||||
/** @var array{
|
||||
* guichet_wsdl:string,
|
||||
* metier_wsdl:string,
|
||||
@@ -35,13 +36,16 @@ final class EdnotifExtension extends Extension
|
||||
$container->setParameter('ednotif.zone', $config['zone']);
|
||||
$container->setParameter('ednotif.application', $config['application']);
|
||||
|
||||
$container->setParameter('ednotif.exploitation_number', $config['exploitation_number']);
|
||||
$container->setParameter('ednotif.exploitation_country_code', $config['exploitation_country_code']);
|
||||
|
||||
$container->setParameter('ednotif.login', $config['login']);
|
||||
$container->setParameter('ednotif.password', $config['password']);
|
||||
|
||||
$container->setParameter('ednotif.token_ttl_seconds', $config['token_ttl_seconds']);
|
||||
$container->setParameter('ednotif.soap_options', $config['soap_options']);
|
||||
|
||||
$loader = new PhpFileLoader($container, new FileLocator(__DIR__ . '/../../config'));
|
||||
$loader = new PhpFileLoader($container, new FileLocator(__DIR__.'/../../config'));
|
||||
$loader->load('services.php');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,4 @@ namespace Malio\EdnotifBundle;
|
||||
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
|
||||
final class EdnotifBundle extends Bundle
|
||||
{
|
||||
}
|
||||
final class EdnotifBundle extends Bundle {}
|
||||
|
||||
14
src/Shared/Dto/AnomalyDto.php
Normal file
14
src/Shared/Dto/AnomalyDto.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Malio\EdnotifBundle\Shared\Dto;
|
||||
|
||||
final readonly class AnomalyDto
|
||||
{
|
||||
public function __construct(
|
||||
public ?string $code,
|
||||
public ?int $severity,
|
||||
public ?string $message,
|
||||
) {}
|
||||
}
|
||||
13
src/Shared/Dto/StandardResponseDto.php
Normal file
13
src/Shared/Dto/StandardResponseDto.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Malio\EdnotifBundle\Shared\Dto;
|
||||
|
||||
final readonly class StandardResponseDto
|
||||
{
|
||||
public function __construct(
|
||||
public bool $result,
|
||||
public ?AnomalyDto $anomaly,
|
||||
) {}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Malio\EdnotifBundle\Exception;
|
||||
namespace Malio\EdnotifBundle\Shared\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Malio\EdnotifBundle\Soap;
|
||||
namespace Malio\EdnotifBundle\Shared\Soap;
|
||||
|
||||
use SoapClient;
|
||||
|
||||
@@ -11,9 +11,7 @@ final class SoapClientFactory
|
||||
/**
|
||||
* @param array<string,mixed> $soapOptions
|
||||
*/
|
||||
public function __construct(private array $soapOptions = [])
|
||||
{
|
||||
}
|
||||
public function __construct(private array $soapOptions = []) {}
|
||||
|
||||
public function create(string $wsdl): SoapClient
|
||||
{
|
||||
Reference in New Issue
Block a user