Skip to content

Commit

Permalink
withSegmentSeparator should accept CRLF (\r\n)
Browse files Browse the repository at this point in the history
  • Loading branch information
senaranya committed Jan 11, 2025
1 parent 0a96e6c commit d3bfb59
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 32 deletions.
54 changes: 26 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
<a href="https://packagist.org/packages/aranyasen/hl7"><img src="https://poser.pugx.org/aranyasen/hl7/license" alt="License"></a>
</p>

**Important: "new Message()" is deprecated and could be removed in a future release. Use HL7 factory class instead. See documents below <br><br>
**Important: "new Message()" is deprecated and could be removed in a future release. Use HL7 factory class instead. See documents below** <br><br>

Final releases for old PHP versions: <br>
-> PHP 7.0/7.1 => [1.5.4](https://github.com/senaranya/HL7/tree/1.5.4)<br>
-> PHP 7.2 => [2.0.2](https://github.com/senaranya/HL7/tree/2.0.2)<br>
-> PHP 7.4 => [2.1.7](https://github.com/senaranya/HL7/tree/2.1.7)**
-> PHP 8.1 => [3.1.7](https://github.com/senaranya/HL7/tree/3.1.7)**
-> PHP 7.4 => [2.1.7](https://github.com/senaranya/HL7/tree/2.1.7)<br>
-> PHP 8.1 => [3.1.7](https://github.com/senaranya/HL7/tree/3.1.7)

## Introduction

Expand All @@ -24,19 +24,11 @@ composer require aranyasen/hl7
```

## Usage
### Import library
```php
// First, import classes from the library as needed...
use Aranyasen\HL7; // HL7 factory class
use Aranyasen\HL7\Message; // If Message is used
use Aranyasen\HL7\Segment; // If Segment is used
use Aranyasen\HL7\Segments\MSH; // If MSH is used
// ... and so on
```

### Parsing
```php
// Create a Message object from a HL7 string
use Aranyasen\HL7;
$message = HL7::from("MSH|^~\\&|1|")->create();
$message = HL7::from("MSH|^~\\&|1|\rPID|||abcd|\r")->create(); // Creates Message object with two segments with \r as segment ending (\n can also be used)

Expand All @@ -52,22 +44,27 @@ $message->getFirstSegmentInstance('ABC'); // Returns the first ABC segment. Same
$message->hasSegment('ABC'); // return true or false based on whether PID is present in the $message object

// Check if a message is empty
$message = HL7::create();
$message->isempty(); // Returns true
$message = HL7::build()->create();
$message->removeSegmentsByName('MSH')
$message->isEmpty(); // Returns true
```

### Composing new messages
```php
// The class `HL7` can be used to build HL7 object. It is a factory class with various helper methods to help build a hl7.
$message = HL7::build()->create(); // Creates an empty message

// The HL7 factory class provides methods that can be chained together in a fluent fashion
$message = HL7::build()->create(); // Creates a Message containing MSH segment with default separators, version etc.
```
#### Configuring HL7 messages
```php
// The HL7 factory class provides methods that can be chained together in a fluent fashion. These can be used to
// override the defaults
$message = HL7::build()
->withComponentSeparator('#')
->withFieldSeparator('-')
->withComponentSeparator('#') // Use # as the component separator instead of the default ^
->withFieldSeparator('-') // Use - as the field separator instead of the default |
->withSegmentSeparator('\r\n') // Override segment separator
->withHL7Version('2.3') // Use HL7 version 2.3
->create();
```
#### Configuring HL7 messages
```php
// Creating multiple message objects may have an unexpected side effect: segments start with wrong index values (Check tests/MessageTest for explanation)...
// So to reset segment indices to 1:
Expand All @@ -81,7 +78,7 @@ $hl7String = "MSH|^~\&|||||||ORU^R01|00001|P|2.3.1|\n" . "OBX|1||11^AA|\n" . "OB
$message = HL7::from($hl7String)
->autoIncrementIndices(false)
->create();
// $message now contains both OBXs with given indexes in the string
// $message now contains both OBXs with 1 as the index, instead of 1 and 2
```
```php
// Ensure empty sub-fields are not removed
Expand All @@ -91,16 +88,12 @@ $pv1 = $message->getSegmentByIndex(1);
$fields = $pv1->getField(3); // $fields is ['', 'AAAA1', '', '', 'BB']

// Create/send message with segment-ending bar character (|) removed
use Aranyasen\HL7\Message;
$message = new Message("MSH|^~\\&|1|\nABC|||xxx\n", ['SEGMENT_ENDING_BAR' => false]);
$message->toString(true); // Returns "MSH|^~\&|1\nABC|||xxx\n"
(new Connection($ip, $port))->send($message); // Sends the message without ending bar-characters (details on Connection below)

// Specify custom values for separators, HL7 version etc.
$message = HL7::from("MSH|^~\\&|1|\rPV1|1|O|^AAAA1^^^BB|")
->withSegmentSeparator('\r\n')
->withHL7Version('2.3')
->create();

```
```php
// Segment with separator character (~) creates sub-arrays containing each sub-segment
$message = HL7::from("MSH|^~\&|||||||ADT^A01||P|2.3.1|\nPID|||3^0~4^1")->create(); // Creates [[3,0], [4,1]]

Expand All @@ -116,10 +109,12 @@ $message = HL7::from("MSH|^~\&|||||||ADT^A01||P|2.3.1|\nPID|||3^0~4^1")
// Once a message object is created, we can now add, insert, set segments and fields.

// Create a MSH segment and add to message object
use Aranyasen\HL7\Segments\MSH;
$msh = new MSH();
$message->addSegment($msh); // Message is: "MSH|^~\&|||||20171116140058|||2017111614005840157||2.3|\n"

// Create a custom segment
use Aranyasen\HL7\Segment;
$abc = new Segment('ABC');
$abc->setField(1, 'xyz');
$abc->setField(2, 0);
Expand All @@ -129,6 +124,7 @@ $message->insertSegment($abc, 1); // Message is now: "MSH|^~\&|||||2017111614005

// Create a defined segment (To know which segments are defined in this package, look into Segments/ directory)
// Advantages of defined segments over custom ones (shown above) are 1) Helpful setter methods, 2) Auto-incrementing segment index
use Aranyasen\HL7\Segments\PID;
$pid = new PID(); // Automatically creates PID segment, and adds segment index at PID.1
$pid->setPatientName([$lastname, $firstname, $middlename, $suffix]); // Use a setter method to add patient's name at standard position (PID.5)
$pid->setField('abcd', 5); // Apart from standard setter methods, you can manually set a value at any position too
Expand Down Expand Up @@ -156,6 +152,7 @@ echo $response->toString(true); // Prints ACK from the listener
### ACK
Handle ACK message returned from a remote HL7 listener...
```php
use Aranyasen\HL7\Connection;
$ack = (new Connection($ip, $port))->send($message); // Send a HL7 to remote listener
$returnString = $ack->toString(true);
if (strpos($returnString, 'MSH') === false) {
Expand All @@ -173,6 +170,7 @@ else {
```
Create an ACK response from a given HL7 message:
```php
use Aranyasen\HL7\Messages\ACK;
$msg = HL7::from("MSH|^~\\&|1|\rABC|1||^AAAA1^^^BB|")->keepEmptySubfields()->create();
$ackResponse = new ACK($msg);
```
Expand Down
1 change: 1 addition & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- In `insertSegment()` method, only MSH can be inserted now in the 0th index
- Replaced all `InvalidArgumentException` with `HL7Exception`, so update the catches accordingly
- Dropped support for PHP 8.1. Minimum version required is now 8.2. So if your project can not be upgraded to 8.2, you'll need to continue using 3.x version
- `withSegmentSeparator` in HL7 accepts CRLF (\r\n) as argument. Any other multi-character separator will continue to throw exception
### Non-breaking changes
- Using `new Message()` is deprecated, and might be removed in a future version. Use HL7 factory to create a new HL7 object instead. See readme on how to use it
- `setSegment` method is deprecated. Use `insertSegment` instead
Expand Down
5 changes: 4 additions & 1 deletion src/HL7.php
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,10 @@ public function withFieldSeparator(string $value): self
*/
public function withSegmentSeparator(string $value): self
{
$this->checkIfSingleCharacter($value);
$value = str_replace(['\r', '\n'], ["\r", "\n"], $value);
if ($value !== "\r\n") {
$this->checkIfSingleCharacter($value);
}

return $this->setGlobal('SEGMENT_SEPARATOR', $value);
}
Expand Down
29 changes: 26 additions & 3 deletions tests/HL7Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,7 @@ class HL7Test extends TestCase
*/
#[Test] public function repetition_separation_character_can_be_ignored(): void
{
$message = Hl7::from("MSH|^~\&|||||||ADT^A01||P|2.3.1|\nPID|||3^0~4^1")
->create();
$message = Hl7::from("MSH|^~\&|||||||ADT^A01||P|2.3.1|\nPID|||3^0~4^1")->create();
self::assertIsArray(
$message->getSegmentByIndex(1)->getField(3),
'By default repetition should be split into array'
Expand All @@ -185,6 +184,30 @@ class HL7Test extends TestCase
{
$this->expectException(HL7Exception::class);
$this->expectExceptionMessage("Parameter should be a single character. Received: 'aa'");
HL7::build()->withSegmentSeparator('aa');
HL7::build()->withEscapeCharacter('aa')->create();
}

/** @throws HL7Exception */
#[Test] public function it_accepts_crlf_as_segment_separator(): void
{
$message = HL7::from("MSH|^~\\&|1|")
->withSegmentSeparator("\r\n") // With double-quotes
->create();
$this->assertSame($message->toString(true), "MSH|^~\\&|1|\r\n");

$message = HL7::from("MSH|^~\\&|1|")
->withSegmentSeparator('\r\n') // With single-quotes
->create();
$this->assertSame($message->toString(true), "MSH|^~\\&|1|\r\n");
}

/** @throws HL7Exception */
#[Test] public function any_other_multi_char_segment_separator_throws_exception(): void
{
$this->expectException(HL7Exception::class);
$this->expectExceptionMessage("Parameter should be a single character. Received: 'aa'");
HL7::from("MSH|^~\\&|1|")
->withSegmentSeparator('aa')
->create();
}
}

0 comments on commit d3bfb59

Please sign in to comment.