From 749c2e95ce77578bcfd31d9a27f5b1f31c52d09f Mon Sep 17 00:00:00 2001 From: Johan Kromhout Date: Thu, 2 May 2024 15:48:04 +0200 Subject: [PATCH] Add support for parsing duplicated segments Prior to this change, mulitple identical segments could not be read. The parser would always return null if duplicated segments were found. This changes allows an offset to be passed, to specify reading a repeated segment. --- src/EDI/Reader.php | 65 ++++++++++++++++++++++++------- src/EDI/ReaderException.php | 11 ++++++ tests/EDITest/ReaderTest.php | 45 ++++++++++++++++++++- tests/files/example_multiline.edi | 10 +++++ 4 files changed, 117 insertions(+), 14 deletions(-) create mode 100644 src/EDI/ReaderException.php create mode 100644 tests/files/example_multiline.edi diff --git a/src/EDI/Reader.php b/src/EDI/Reader.php index 369e6af..6114b58 100644 --- a/src/EDI/Reader.php +++ b/src/EDI/Reader.php @@ -174,10 +174,9 @@ public function readEdiDataValueReq($filter, int $l1, $l2 = false) * @param bool $required if required, but no exist, register error * @return string|null */ - public function readEdiDataValue($filter, int $l1, $l2 = false, bool $required = false) + public function readEdiDataValue($filter, int $l1, $l2 = false, bool $required = false, int $offset = null) { - $segment = false; - $segment_count = 0; + $found_segments = []; $segment_name = $filter; $filter_elements = false; if (\is_array($filter)) { @@ -221,24 +220,23 @@ public function readEdiDataValue($filter, int $l1, $l2 = false, bool $required = continue; } } - $segment = $edi_row; - $segment_count++; + $found_segments[] = $edi_row; } } - // no segment found - if (! $segment) { - if ($required) { - $this->errors[] = 'Segment "'.$segment_name.'" no exist'; + try { + if ($offset !== null) { + $segment = $this->getOffsetSegmentFromResult($found_segments, $offset, $required, $segment_name); + } else { + $segment = $this->getSegmentFromResult($found_segments, $required, $segment_name); } + } catch (ReaderException $e) { + $this->errors[] = $e->getMessage(); return null; } - // found more than one segment - error - if ($segment_count > 1) { - $this->errors[] = 'Segment "'.$segment_name.'" is ambiguous'; - + if ($segment === false) { return null; } @@ -561,4 +559,45 @@ private static function unwrap($string) } } } + + /** + * @param array $matchingSegments + * @param int $offset + * @param bool $required + * @param mixed $segment_name + * + * @return false|mixed + */ + private function getOffsetSegmentFromResult(array $matchingSegments, int $offset, bool $required, mixed $segment_name): mixed + { + if (isset($matchingSegments[$offset])) { + return $matchingSegments[$offset]; + } + + if ($required) { + throw new ReaderException('Segment "' . $segment_name . '" does not exist at offset "' . $offset . '"'); + } + + return false; + } + + /** + * @param array $matchingSegments + * @param mixed $segment_name + * + * @return false|mixed + */ + private function getSegmentFromResult(array $matchingSegments, bool $required, mixed $segment_name): mixed + { + // found more than one segment - error + if (count($matchingSegments) > 1) { + throw new ReaderException('Segment "' . $segment_name . '" is ambiguous'); + } + + if ($required && !isset($matchingSegments[0])) { + throw new ReaderException('Segment "' . $segment_name . '" no exist'); + } + + return $matchingSegments[0] ?? false; + } } diff --git a/src/EDI/ReaderException.php b/src/EDI/ReaderException.php new file mode 100644 index 0000000..5a69051 --- /dev/null +++ b/src/EDI/ReaderException.php @@ -0,0 +1,11 @@ +readUNHmessageType(); static::assertSame('PAORES', $messageType); } + + public function testReadsMultiSegmentsByOffset() + { + $p = new Parser(); + $p->setStrict(true); + $p->load(__DIR__ . '/../files/example_multiline.edi'); + $r = new Reader($p); + + $lines = []; + for ($i = 0; $i < 10; $i++) { + $line = $r->readEdiDataValue(['FTX', [1 => 'AAI']], 4, false, false, $i); + if ($line !== null) { + $lines[] = $line; + } + } + + self::assertSame( + [ + 0 => [ + 0 => 'PLS ENSURE TO TAKE OUR APPROVAL PRIOR STUFFING ANY NON HAZ CHEMICA', + 1 => 'LS', + ], + 1 => [ + 0 => 'THE SHIPPER SHALL NOT BE RESPONSIBLE FOR ANY COSTS/DELAYS OCCUR', + 1 => 'DUE TO INTERVENTION OF CUSTOMS.', + ], + + ], + $lines + ); + } + + public function testAddsErrorOnMissingRequiredOffest() + { + $p = new Parser(); + $p->setStrict(true); + $p->load(__DIR__ . '/../files/example_multiline.edi'); + $r = new Reader($p); + $line = $r->readEdiDataValue(['FTX', [1 => 'AAI']], 4, false, true, 99); + self::assertSame(['Segment "FTX" does not exist at offset "99"'], $r->errors()); + self::assertNull($line); + } + } diff --git a/tests/files/example_multiline.edi b/tests/files/example_multiline.edi new file mode 100644 index 0000000..f308f50 --- /dev/null +++ b/tests/files/example_multiline.edi @@ -0,0 +1,10 @@ +UNB+UNOB:2+CARRIER+RECEIVER-ID+999818:999+251' +UNH+0001+IFTMBC:D:00B:UN' +BGM+770+AAA99970929+9' +TSR+30+2:::2' +FTX+AAI+++PLS ENSURE TO TAKE OUR APPROVAL PRIOR STUFFING ANY NON HAZ CHEMICA:LS' +FTX+ABV+++THIS BOOKING CONFIRMATION IS SUBJECT TO SEALING' +FTX+AAI+++THE SHIPPER SHALL NOT BE RESPONSIBLE FOR ANY COSTS/DELAYS OCCUR +:DUE TO INTERVENTION OF CUSTOMS.' +UNT+10+0001' +UNZ+1+251' \ No newline at end of file