From 46f99a4243ac935b63891fe5978760df77f7767e Mon Sep 17 00:00:00 2001 From: tristan Date: Tue, 21 Apr 2026 08:18:50 +0200 Subject: [PATCH] =?UTF-8?q?feat=20:=20d=C3=A9codeur=20ZIP+XML=20partag?= =?UTF-8?q?=C3=A9=20pour=20les=20r=C3=A9ponses=20Get*=20bovin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Shared/Soap/ZipMessageDecoder.php | 82 +++++++++++++++++++ .../Shared/Soap/ZipMessageDecoderTest.php | 61 ++++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 src/Shared/Soap/ZipMessageDecoder.php create mode 100644 tests/Unit/Shared/Soap/ZipMessageDecoderTest.php diff --git a/src/Shared/Soap/ZipMessageDecoder.php b/src/Shared/Soap/ZipMessageDecoder.php new file mode 100644 index 0000000..ff258f3 --- /dev/null +++ b/src/Shared/Soap/ZipMessageDecoder.php @@ -0,0 +1,82 @@ +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; + } +} diff --git a/tests/Unit/Shared/Soap/ZipMessageDecoderTest.php b/tests/Unit/Shared/Soap/ZipMessageDecoderTest.php new file mode 100644 index 0000000..e371b30 --- /dev/null +++ b/tests/Unit/Shared/Soap/ZipMessageDecoderTest.php @@ -0,0 +1,61 @@ +' + .'' + .'2026-01-01' + .'F' + .''; + + $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; + } +}