Skip to content

Commit 749c2e9

Browse files
committed
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.
1 parent fe5d6b6 commit 749c2e9

File tree

4 files changed

+117
-14
lines changed

4 files changed

+117
-14
lines changed

src/EDI/Reader.php

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,9 @@ public function readEdiDataValueReq($filter, int $l1, $l2 = false)
174174
* @param bool $required if required, but no exist, register error
175175
* @return string|null
176176
*/
177-
public function readEdiDataValue($filter, int $l1, $l2 = false, bool $required = false)
177+
public function readEdiDataValue($filter, int $l1, $l2 = false, bool $required = false, int $offset = null)
178178
{
179-
$segment = false;
180-
$segment_count = 0;
179+
$found_segments = [];
181180
$segment_name = $filter;
182181
$filter_elements = false;
183182
if (\is_array($filter)) {
@@ -221,24 +220,23 @@ public function readEdiDataValue($filter, int $l1, $l2 = false, bool $required =
221220
continue;
222221
}
223222
}
224-
$segment = $edi_row;
225-
$segment_count++;
223+
$found_segments[] = $edi_row;
226224
}
227225
}
228226

229-
// no segment found
230-
if (! $segment) {
231-
if ($required) {
232-
$this->errors[] = 'Segment "'.$segment_name.'" no exist';
227+
try {
228+
if ($offset !== null) {
229+
$segment = $this->getOffsetSegmentFromResult($found_segments, $offset, $required, $segment_name);
230+
} else {
231+
$segment = $this->getSegmentFromResult($found_segments, $required, $segment_name);
233232
}
233+
} catch (ReaderException $e) {
234+
$this->errors[] = $e->getMessage();
234235

235236
return null;
236237
}
237238

238-
// found more than one segment - error
239-
if ($segment_count > 1) {
240-
$this->errors[] = 'Segment "'.$segment_name.'" is ambiguous';
241-
239+
if ($segment === false) {
242240
return null;
243241
}
244242

@@ -561,4 +559,45 @@ private static function unwrap($string)
561559
}
562560
}
563561
}
562+
563+
/**
564+
* @param array $matchingSegments
565+
* @param int $offset
566+
* @param bool $required
567+
* @param mixed $segment_name
568+
*
569+
* @return false|mixed
570+
*/
571+
private function getOffsetSegmentFromResult(array $matchingSegments, int $offset, bool $required, mixed $segment_name): mixed
572+
{
573+
if (isset($matchingSegments[$offset])) {
574+
return $matchingSegments[$offset];
575+
}
576+
577+
if ($required) {
578+
throw new ReaderException('Segment "' . $segment_name . '" does not exist at offset "' . $offset . '"');
579+
}
580+
581+
return false;
582+
}
583+
584+
/**
585+
* @param array $matchingSegments
586+
* @param mixed $segment_name
587+
*
588+
* @return false|mixed
589+
*/
590+
private function getSegmentFromResult(array $matchingSegments, bool $required, mixed $segment_name): mixed
591+
{
592+
// found more than one segment - error
593+
if (count($matchingSegments) > 1) {
594+
throw new ReaderException('Segment "' . $segment_name . '" is ambiguous');
595+
}
596+
597+
if ($required && !isset($matchingSegments[0])) {
598+
throw new ReaderException('Segment "' . $segment_name . '" no exist');
599+
}
600+
601+
return $matchingSegments[0] ?? false;
602+
}
564603
}

src/EDI/ReaderException.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace EDI;
6+
7+
use RuntimeException;
8+
9+
class ReaderException extends RuntimeException
10+
{
11+
}

tests/EDITest/ReaderTest.php

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
namespace EDITest;
66

7-
use EDI\Reader;
87
use EDI\Parser;
8+
use EDI\Reader;
99

1010
/**
1111
* @internal
@@ -102,4 +102,47 @@ public function testSplitMultiMessage()
102102
$messageType = $r->readUNHmessageType();
103103
static::assertSame('PAORES', $messageType);
104104
}
105+
106+
public function testReadsMultiSegmentsByOffset()
107+
{
108+
$p = new Parser();
109+
$p->setStrict(true);
110+
$p->load(__DIR__ . '/../files/example_multiline.edi');
111+
$r = new Reader($p);
112+
113+
$lines = [];
114+
for ($i = 0; $i < 10; $i++) {
115+
$line = $r->readEdiDataValue(['FTX', [1 => 'AAI']], 4, false, false, $i);
116+
if ($line !== null) {
117+
$lines[] = $line;
118+
}
119+
}
120+
121+
self::assertSame(
122+
[
123+
0 => [
124+
0 => 'PLS ENSURE TO TAKE OUR APPROVAL PRIOR STUFFING ANY NON HAZ CHEMICA',
125+
1 => 'LS',
126+
],
127+
1 => [
128+
0 => 'THE SHIPPER SHALL NOT BE RESPONSIBLE FOR ANY COSTS/DELAYS OCCUR',
129+
1 => 'DUE TO INTERVENTION OF CUSTOMS.',
130+
],
131+
132+
],
133+
$lines
134+
);
135+
}
136+
137+
public function testAddsErrorOnMissingRequiredOffest()
138+
{
139+
$p = new Parser();
140+
$p->setStrict(true);
141+
$p->load(__DIR__ . '/../files/example_multiline.edi');
142+
$r = new Reader($p);
143+
$line = $r->readEdiDataValue(['FTX', [1 => 'AAI']], 4, false, true, 99);
144+
self::assertSame(['Segment "FTX" does not exist at offset "99"'], $r->errors());
145+
self::assertNull($line);
146+
}
147+
105148
}

tests/files/example_multiline.edi

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
UNB+UNOB:2+CARRIER+RECEIVER-ID+999818:999+251'
2+
UNH+0001+IFTMBC:D:00B:UN'
3+
BGM+770+AAA99970929+9'
4+
TSR+30+2:::2'
5+
FTX+AAI+++PLS ENSURE TO TAKE OUR APPROVAL PRIOR STUFFING ANY NON HAZ CHEMICA:LS'
6+
FTX+ABV+++THIS BOOKING CONFIRMATION IS SUBJECT TO SEALING'
7+
FTX+AAI+++THE SHIPPER SHALL NOT BE RESPONSIBLE FOR ANY COSTS/DELAYS OCCUR
8+
:DUE TO INTERVENTION OF CUSTOMS.'
9+
UNT+10+0001'
10+
UNZ+1+251'

0 commit comments

Comments
 (0)