From 0a96e6ca438b269a7ba9f71e9632bdc375a0e885 Mon Sep 17 00:00:00 2001 From: Aranya Sen Date: Sat, 11 Jan 2025 13:10:00 +0530 Subject: [PATCH] Use HL7 factory as the primary method of creating Message object --- README.md | 63 ++++++++++++++++++++++++----------------------- UPGRADE.md | 12 +++++++++ src/HL7.php | 8 ++++++ tests/HL7Test.php | 42 +++++++++++++++++++------------ 4 files changed, 78 insertions(+), 47 deletions(-) create mode 100644 UPGRADE.md diff --git a/README.md b/README.md index a245f8a..fb7d151 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,12 @@

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

+ Final releases for old PHP versions:
-> PHP 7.0/7.1 => [1.5.4](https://github.com/senaranya/HL7/tree/1.5.4)
-> PHP 7.2 => [2.0.2](https://github.com/senaranya/HL7/tree/2.0.2)
-> 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)** ## Introduction @@ -35,10 +37,8 @@ use Aranyasen\HL7\Segments\MSH; // If MSH is used ### Parsing ```php // Create a Message object from a HL7 string -$message = HL7::from("MSH|^~\\&|1|")->createMessage(); // Returns Message object - -// Or, using Message class... -$message = new Message("MSH|^~\\&|1|\rPID|||abcd|\r"); // Either \n or \r can be used as segment endings +$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) // Get string form of the message echo $message->toString(true); @@ -52,43 +52,41 @@ $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 = new Message(); +$message = HL7::create(); $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()->createMessage(); // Creates an empty message +$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() ->withComponentSeparator('#') ->withFieldSeparator('-') - ->createMessage(); - -// Or, using Message class... -$message = new Message(); + ->create(); ``` -#### Message constructor parameters +#### Configuring HL7 messages ```php -// When a message is composed using Message class, there are multiple parameters available to define the properties of the HL7. -// Note: All of these properties are available as fluent methods in HL7 factory class (shown above). So it's recommended to use that for readability - // Creating multiple message objects may have an unexpected side effect: segments start with wrong index values (Check tests/MessageTest for explanation)... -// Use 4th argument as true, or call resetSegmentIndices() on $message object to reset segment indices to 1 -$message = new Message("MSH|^~\&|||||||ORM^O01||P|2.3.1|", null, true, true); +// So to reset segment indices to 1: +HL7::from("MSH|^~\&|||||||ORM^O01||P|2.3.1|")->resetIndices()->create(); // Use resetIndices() while creating a new message +$message->resetSegmentIndices(); // or call resetSegmentIndices() on an existing $message object // ... any segments added here will now start index from 1, as expected. ``` ```php // Sometimes you may want to have exact index values, rather than auto-incrementing for each instance of a segment -// Use 5th argument as false... $hl7String = "MSH|^~\&|||||||ORU^R01|00001|P|2.3.1|\n" . "OBX|1||11^AA|\n" . "OBX|1||22^BB|\n"; -$message = new Message($hl7String, null, true, true, false); $// $message contains both OBXs with given indexes in the string +$message = HL7::from($hl7String) + ->autoIncrementIndices(false) + ->create(); +// $message now contains both OBXs with given indexes in the string ``` ```php -// Create a segment with empty sub-fields retained -$message = new Message("MSH|^~\\&|1|\rPV1|1|O|^AAAA1^^^BB|", null, true); // Third argument 'true' forces to keep all sub-fields +// Ensure empty sub-fields are not removed +// Note: We should perhaps _always_ use this while creating a message object, as we don't want empty subfields removed. In future versions, this will be the default +$message = HL7::from("MSH|^~\\&|1|\rPV1|1|O|^AAAA1^^^BB|")->keepEmptySubfields()->create(); $pv1 = $message->getSegmentByIndex(1); $fields = $pv1->getField(3); // $fields is ['', 'AAAA1', '', '', 'BB'] @@ -98,16 +96,19 @@ $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 = new Message("MSH|^~\\&|1|\rPV1|1|O|^AAAA1^^^BB|", ['SEGMENT_SEPARATOR' => '\r\n', 'HL7_VERSION' => '2.3']); +$message = HL7::from("MSH|^~\\&|1|\rPV1|1|O|^AAAA1^^^BB|") + ->withSegmentSeparator('\r\n') + ->withHL7Version('2.3') + ->create(); // Segment with separator character (~) creates sub-arrays containing each sub-segment -$message = new Message("MSH|^~\&|||||||ADT^A01||P|2.3.1|\nPID|||3^0~4^1"); // Creates [[3,0], [4,1]] +$message = HL7::from("MSH|^~\&|||||||ADT^A01||P|2.3.1|\nPID|||3^0~4^1")->create(); // Creates [[3,0], [4,1]] -// To create a single array instead, pass 'true' as 6th argument. This may be used to retain behavior from previous releases -// Notice: Since this leads to a non-standard behavior, it may be removed in future -$message = new Message("MSH|^~\&|||||||ADT^A01||P|2.3.1|\nPID|||3^0~4^1", null, false, false, true, true); // Creates ['3', '0~4', '1'] -// or -$message = new Message("MSH|^~\&|||||||ADT^A01||P|2.3.1|\nPID|||3^0~4^1", doNotSplitRepetition: true); // Creates ['3', '0~4', '1'] +// To create a single array instead, use doNotSplitRepetition() +// Note: Since this leads to a non-standard behavior, it may be removed in future +$message = HL7::from("MSH|^~\&|||||||ADT^A01||P|2.3.1|\nPID|||3^0~4^1") + ->doNotSplitRepetition() + ->create(); // Creates ['3', '0~4', '1'] ``` #### Handling segments and fields @@ -124,7 +125,7 @@ $abc->setField(1, 'xyz'); $abc->setField(2, 0); $abc->setField(4, ['']); // Set an empty field at 4th position. 2nd and 3rd positions will be automatically set to empty $abc->clearField(2); // Clear the value from field 2 -$message->setSegment($abc, 1); // Message is now: "MSH|^~\&|||||20171116140058|||2017111614005840157||2.3|\nABC|xyz|\n" +$message->insertSegment($abc, 1); // Message is now: "MSH|^~\&|||||20171116140058|||2017111614005840157||2.3|\nABC|xyz|\n" // 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 @@ -145,7 +146,7 @@ Side note: In order to run Connection you need to install PHP ext-sockets [https ```php $ip = '127.0.0.1'; // An IP $port = '12001'; // And Port where a HL7 listener is listening -$message = new Message($hl7String); // Create a Message object from your HL7 string +$message = HL7::from($hl7String)->create(); // Create a Message object from your HL7 string. See above for details // Create a Socket and get ready to send message. Optionally add timeout in seconds as 3rd argument (default: 10 sec) $connection = new Connection($ip, $port); @@ -172,12 +173,12 @@ else { ``` Create an ACK response from a given HL7 message: ```php -$msg = new Message("MSH|^~\\&|1|\rABC|1||^AAAA1^^^BB|", null, true); +$msg = HL7::from("MSH|^~\\&|1|\rABC|1||^AAAA1^^^BB|")->keepEmptySubfields()->create(); $ackResponse = new ACK($msg); ``` Options can be passed while creating ACK object: ```php -$msg = new Message("MSH|^~\\&|1|\rABC|1||^AAAA1^^^BB|", null, true); +$msg = HL7::from("MSH|^~\\&|1|\rABC|1||^AAAA1^^^BB|")->keepEmptySubfields()->create(); $ackResponse = new ACK($msg, null, ['SEGMENT_SEPARATOR' => '\r\n', 'HL7_VERSION' => '2.5']); ``` diff --git a/UPGRADE.md b/UPGRADE.md new file mode 100644 index 0000000..9c701dc --- /dev/null +++ b/UPGRADE.md @@ -0,0 +1,12 @@ +## 4.0 +### Breaking changes + - First segment in the Message object can only be MSH. E.g. this will now fail: `(new Message())->addSegment(new Segment('XXX'))`, so it has to be `(new Message("MSH|^~\\&|1|\r"))->addSegment(new Segment('XXX'))` + - 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 +### 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 + - In `insertSegment`, added a replace parameter to replace a current segment in place + - Added `replaceSegment` method + - Added `create` method in HL7 factory that is an alias to `createMessage` diff --git a/src/HL7.php b/src/HL7.php index 7f6a971..606a19d 100644 --- a/src/HL7.php +++ b/src/HL7.php @@ -76,6 +76,14 @@ public function createMessage(): Message ); } + /** + * @throws HL7Exception + */ + public function create(): Message + { + return $this->createMessage(); + } + /** * Create a new MSH segment, using the global HL7 variables as defaults. * @throws Exception diff --git a/tests/HL7Test.php b/tests/HL7Test.php index f0082fd..45c692d 100644 --- a/tests/HL7Test.php +++ b/tests/HL7Test.php @@ -16,7 +16,17 @@ class HL7Test extends TestCase */ #[Test] public function hl7_message_can_be_created_using_factory_class(): void { - $msg = HL7::build()->createMessage(); + $msg = HL7::build()->create(); + self::assertIsObject($msg); + self::assertSame(HL7\Message::class, $msg::class); + } + + /** + * @throws HL7Exception + */ + #[Test] public function hl7_message_can_be_created_using_create_alias_method(): void + { + $msg = HL7::build()->create(); self::assertIsObject($msg); self::assertSame(HL7\Message::class, $msg::class); } @@ -26,7 +36,7 @@ class HL7Test extends TestCase */ #[Test] public function factory_creates_a_msh_segment_with_defaults_when_no_message_string_provided(): void { - $msg = HL7::build()->createMessage(); + $msg = HL7::build()->create(); self::assertStringContainsString('MSH|^~\&|||||', $msg->toString(true)); } @@ -35,7 +45,7 @@ class HL7Test extends TestCase */ #[Test] public function a_message_can_be_built_from_a_provided_hl7_string(): void { - $msg = HL7::from("MSH|^~\\&|1|\rABC|||xxx|\r")->createMessage(); + $msg = HL7::from("MSH|^~\\&|1|\rABC|||xxx|\r")->create(); self::assertSame("MSH|^~\\&|1|\nABC|||xxx|\n", $msg->toString(true)); } @@ -47,7 +57,7 @@ class HL7Test extends TestCase self::markTestSkipped('property cannot be overridden yet in Message() constructor'); $msg = HL7::from("MSH|^~\\&|1|\rABC|||xxx|\r") ->withEscapeCharacter('=') - ->createMessage(); + ->create(); self::assertSame("MSH|^~=&|1|\nABC|||xxx|\n", $msg->toString(true)); } /** @@ -63,13 +73,13 @@ class HL7Test extends TestCase ->withRepetitionSeparator('`') ->withEscapeCharacter('=') ->withHL7Version('555.666') - ->createMessage(); + ->create(); self::assertStringContainsString('MSH#*`=}#', $msg->toString(true)); } #[Test] public function empty_subfields_can_be_retained_if_needed(): void { - $msg = HL7::from("MSH|^~\\&|1|\rPV1|1|O|^AAAA1^^^BB|")->keepEmptySubfields()->createMessage(); + $msg = HL7::from("MSH|^~\\&|1|\rPV1|1|O|^AAAA1^^^BB|")->keepEmptySubfields()->create(); $this->assertSame(['', 'AAAA1', '', '', 'BB'], $msg->getSegmentByIndex(1)->getField(3)); } @@ -79,7 +89,7 @@ class HL7Test extends TestCase #[Test] public function indices_of_each_segment_can_be_reset_when_message_is_composed(): void { // Create a message with a PID segment - $msg1 = HL7::from("MSH|^~\&|||||||ORM^O01||P|2.3.1|")->createMessage(); + $msg1 = HL7::from("MSH|^~\&|||||||ORM^O01||P|2.3.1|")->create(); $msg1->addSegment(new PID()); self::assertSame( "MSH|^~\&|||||||ORM^O01||P|2.3.1|\nPID|1|\n", @@ -88,7 +98,7 @@ class HL7Test extends TestCase ); // Create another message with a PID segment - $msg2 = Hl7::from("MSH|^~\&|||||||ORM^O01||P|2.3.1|")->createMessage(); + $msg2 = Hl7::from("MSH|^~\&|||||||ORM^O01||P|2.3.1|")->create(); $msg2->addSegment(new PID()); self::assertSame( "MSH|^~\&|||||||ORM^O01||P|2.3.1|\nPID|2|\n", @@ -99,12 +109,12 @@ class HL7Test extends TestCase // Create another message with a PID segment, this time with resetIndices() $msg3 = Hl7::from("MSH|^~\&|||||||ORM^O01||P|2.3.1|") ->resetIndices() - ->createMessage(); + ->create(); $msg3->addSegment(new PID()); self::assertSame("MSH|^~\&|||||||ORM^O01||P|2.3.1|\nPID|1|\n", $msg3->toString(true), 'PID index resets to 1'); // Create a message with a PID segment - $msg4 = Hl7::from("MSH|^~\&|||||||ORM^O01||P|2.3.1|")->createMessage(); + $msg4 = Hl7::from("MSH|^~\&|||||||ORM^O01||P|2.3.1|")->create(); $msg4->addSegment(new PID()); self::assertSame( "MSH|^~\&|||||||ORM^O01||P|2.3.1|\nPID|2|\n", @@ -112,7 +122,7 @@ class HL7Test extends TestCase 'PID index gets incremented' ); - $msg5 = Hl7::from("MSH|^~\&|||||||ORM^O01||P|2.3.1|")->createMessage(); + $msg5 = Hl7::from("MSH|^~\&|||||||ORM^O01||P|2.3.1|")->create(); $msg5->resetSegmentIndices(); $msg5->addSegment(new PID()); self::assertSame("MSH|^~\&|||||||ORM^O01||P|2.3.1|\nPID|1|\n", $msg5->toString(true), 'PID index resets to 1'); @@ -126,7 +136,7 @@ class HL7Test extends TestCase $hl7String = "MSH|^~\&|||||||ORU^R01|00001|P|2.3.1|\n" . "OBX|1||11^AA|\n" . "OBX|1||22^BB|\n"; $msg = Hl7::from($hl7String) - ->createMessage(); + ->create(); self::assertSame( "MSH|^~\&|||||||ORU^R01|00001|P|2.3.1|\n" . "OBX|1||11^AA|\n" . "OBX|2||22^BB|\n", $msg->toString(true), @@ -135,7 +145,7 @@ class HL7Test extends TestCase $msg = Hl7::from($hl7String) ->autoIncrementIndices(false) - ->createMessage(); + ->create(); self::assertSame( "MSH|^~\&|||||||ORU^R01|00001|P|2.3.1|\n" . "OBX|1||11^AA|\n" . "OBX|1||22^BB|\n", $msg->toString(true) @@ -143,7 +153,7 @@ class HL7Test extends TestCase $msg = Hl7::from("MSH|^~\&|||||||ORU^R01|00001|P|2.3.1|\n" . "PID|||3^0\n") ->autoIncrementIndices(false) - ->createMessage(); + ->create(); self::assertSame( "MSH|^~\&|||||||ORU^R01|00001|P|2.3.1|\n" . "PID|||3^0|\n", $msg->toString(true), @@ -157,7 +167,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") - ->createMessage(); + ->create(); self::assertIsArray( $message->getSegmentByIndex(1)->getField(3), 'By default repetition should be split into array' @@ -165,7 +175,7 @@ class HL7Test extends TestCase $message = Hl7::from("MSH|^~\&|||||||ADT^A01||P|2.3.1|\nPID|||3^0~4^1") ->doNotSplitRepetition() // Ignore repetition separator character - ->createMessage(); + ->create(); $patientIdentifierList = $message->getSegmentByIndex(1)->getField(3); self::assertIsArray($patientIdentifierList); self::assertSame(['3', '0~4', '1'], $patientIdentifierList);