86 lines
2.6 KiB
PHP
86 lines
2.6 KiB
PHP
<?php
|
|
|
|
namespace App\BusProNet\XmlParser;
|
|
|
|
use App\BusProNet\Model\File;
|
|
use Symfony\Component\DomCrawler\Crawler;
|
|
use ZipStream\Exception as ZipException;
|
|
use ZipStream\ZipStream;
|
|
|
|
class DocumentsParser
|
|
{
|
|
public function parseConfirmation(Crawler $result): ?File
|
|
{
|
|
$pdfData = $this->decode($result->filterXPath('//bestaetigungpdf'));
|
|
|
|
return new File('bestaetigung.pdf', $pdfData, 'application/pdf');
|
|
}
|
|
|
|
public function parseDocuments(Crawler $result): ?File
|
|
{
|
|
$documents = $result->filterXPath('//reisedokumente/reisedokument');
|
|
|
|
if (1 === $documents->count()) {
|
|
$node = $documents->first();
|
|
[$filename, $pdfData] = $this->getFileInfo($node);
|
|
|
|
return new File($filename.'.pdf', $pdfData, 'application/pdf');
|
|
}
|
|
|
|
// In case of multiple documents create ZIP file
|
|
$stream = fopen('php://temp', 'w+b');
|
|
try {
|
|
// Zero headers trip up some unzip clients, and the data is in memory anyway
|
|
$zip = new ZipStream(
|
|
outputStream: $stream,
|
|
defaultEnableZeroHeader: false,
|
|
sendHttpHeaders: false,
|
|
);
|
|
|
|
$documents->each(function (Crawler $node) use ($zip) {
|
|
[$filename, $pdfData] = $this->getFileInfo($node);
|
|
$zip->addFile($filename.'.pdf', $pdfData);
|
|
});
|
|
|
|
$zip->finish();
|
|
rewind($stream);
|
|
|
|
return new File('reisedokumente.zip', stream_get_contents($stream), 'application/zip');
|
|
} catch (ZipException $e) {
|
|
return null;
|
|
} finally {
|
|
fclose($stream);
|
|
}
|
|
}
|
|
|
|
private function decode(Crawler $node): string
|
|
{
|
|
if (0 === $node->count()) {
|
|
throw new \InvalidArgumentException('Missing PDF node in document response.');
|
|
}
|
|
|
|
$parts = explode(',', $node->text(), 2);
|
|
if (2 !== count($parts)) {
|
|
throw new \InvalidArgumentException('Invalid PDF payload in document response.');
|
|
}
|
|
|
|
[, $pdfData] = $parts;
|
|
|
|
return base64_decode($pdfData);
|
|
}
|
|
|
|
/** @return array{string, string} */
|
|
private function getFileInfo(Crawler $node): array
|
|
{
|
|
$pdfData = $this->decode($node->filterXPath('.//pdf'));
|
|
$filenameNode = $node->filterXPath('.//datei');
|
|
if (0 === $filenameNode->count()) {
|
|
throw new \InvalidArgumentException('Missing filename node in document response.');
|
|
}
|
|
|
|
$filename = $filenameNode->text();
|
|
|
|
return [$filename, $pdfData];
|
|
}
|
|
}
|