feat : décodeur ZIP+XML partagé pour les réponses Get* bovin

This commit is contained in:
2026-04-21 08:18:50 +02:00
parent 579c1df495
commit 46f99a4243
2 changed files with 143 additions and 0 deletions

View File

@@ -0,0 +1,82 @@
<?php
declare(strict_types=1);
namespace Malio\EdnotifBundle\Shared\Soap;
use RuntimeException;
use ZipArchive;
final class ZipMessageDecoder
{
/**
* Décode le binaire `MessageZip` retourné par les opérations EDNOTIF de type
* `Get*` (Inventaire / RetourDossiers / SortiesPresumees) : le contenu est déjà
* décodé par ext-soap depuis base64, il reste à dézipper et parser le XML.
*/
public function decode(string $zipBinary): object
{
if ('' === $zipBinary) {
throw new RuntimeException('ZipMessageDecoder: binaire ZIP vide.');
}
$tempFile = tempnam(sys_get_temp_dir(), 'ednotif_zip_');
if (false === $tempFile) {
throw new RuntimeException('ZipMessageDecoder: impossible de créer un fichier temporaire.');
}
try {
if (false === file_put_contents($tempFile, $zipBinary)) {
throw new RuntimeException('ZipMessageDecoder: impossible d\'écrire le fichier temporaire.');
}
$xml = $this->readFirstEntry($tempFile);
} finally {
@unlink($tempFile);
}
$previous = libxml_use_internal_errors(true);
$simpleXml = simplexml_load_string($xml);
libxml_use_internal_errors($previous);
if (false === $simpleXml) {
throw new RuntimeException('ZipMessageDecoder: XML invalide dans l\'archive ZIP.');
}
$json = json_encode($simpleXml);
if (false === $json) {
throw new RuntimeException('ZipMessageDecoder: échec de l\'encodage JSON intermédiaire.');
}
$decoded = json_decode($json, false);
if (!is_object($decoded)) {
throw new RuntimeException('ZipMessageDecoder: décodage JSON non objet.');
}
return $decoded;
}
private function readFirstEntry(string $filePath): string
{
$zip = new ZipArchive();
$openResult = $zip->open($filePath, ZipArchive::RDONLY);
if (true !== $openResult) {
throw new RuntimeException(sprintf('ZipMessageDecoder: ouverture ZIP impossible (code %s).', (string) $openResult));
}
try {
if (0 === $zip->numFiles) {
throw new RuntimeException('ZipMessageDecoder: archive ZIP vide.');
}
$xml = $zip->getFromIndex(0);
if (false === $xml) {
throw new RuntimeException('ZipMessageDecoder: lecture de l\'entrée ZIP impossible.');
}
} finally {
$zip->close();
}
return $xml;
}
}

View File

@@ -0,0 +1,61 @@
<?php
declare(strict_types=1);
namespace Malio\EdnotifBundle\Tests\Unit\Shared\Soap;
use Malio\EdnotifBundle\Shared\Soap\ZipMessageDecoder;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\TestCase;
use RuntimeException;
use ZipArchive;
/**
* @internal
*/
#[CoversClass(ZipMessageDecoder::class)]
final class ZipMessageDecoderTest extends TestCase
{
public function testDecodeReturnsObjectFromZippedXml(): void
{
$xml = '<?xml version="1.0" encoding="UTF-8"?>'
.'<MessageIpBNotifGetInventaire>'
.'<InformationsMessage><DateDebut>2026-01-01</DateDebut></InformationsMessage>'
.'<Bovins><Bovin><IdentiteBovin><Sexe>F</Sexe></IdentiteBovin></Bovin></Bovins>'
.'</MessageIpBNotifGetInventaire>';
$zipBinary = $this->makeZipBinary('message.xml', $xml);
$decoded = new ZipMessageDecoder()->decode($zipBinary);
self::assertIsObject($decoded);
self::assertSame('2026-01-01', (string) $decoded->InformationsMessage->DateDebut);
self::assertSame('F', (string) $decoded->Bovins->Bovin->IdentiteBovin->Sexe);
}
public function testDecodeThrowsOnEmptyBinary(): void
{
$this->expectException(RuntimeException::class);
new ZipMessageDecoder()->decode('');
}
public function testDecodeThrowsOnInvalidZip(): void
{
$this->expectException(RuntimeException::class);
new ZipMessageDecoder()->decode('not a zip');
}
private function makeZipBinary(string $innerFile, string $content): string
{
$tempFile = tempnam(sys_get_temp_dir(), 'test_zip_');
self::assertIsString($tempFile);
$zip = new ZipArchive();
self::assertTrue(true === $zip->open($tempFile, ZipArchive::CREATE | ZipArchive::OVERWRITE));
self::assertTrue($zip->addFromString($innerFile, $content));
self::assertTrue($zip->close());
$binary = file_get_contents($tempFile);
@unlink($tempFile);
self::assertIsString($binary);
return $binary;
}
}