This is an automated email from the ASF dual-hosted git repository.

hubcio pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iggy.git


The following commit(s) were added to refs/heads/master by this push:
     new ff74972d4 feat(php): add PHP message envelope example (#4718)
ff74972d4 is described below

commit ff74972d449752bc5b5d18ecf38eeeb2d90ba152
Author: Abhinav Negi <[email protected]>
AuthorDate: Thu Nov 5 14:59:47 2026 +0530

    feat(php): add PHP message envelope example (#4718)
---
 examples/php/README.md                     |  13 ++++
 examples/php/message-envelope/consumer.php | 108 +++++++++++++++++++++++++++++
 examples/php/message-envelope/producer.php |  78 +++++++++++++++++++++
 3 files changed, 199 insertions(+)

diff --git a/examples/php/README.md b/examples/php/README.md
index b1f2b7f5b..cd2abe716 100644
--- a/examples/php/README.md
+++ b/examples/php/README.md
@@ -34,6 +34,19 @@ php -d 
extension="${PHP_IGGY_EXTENSION:-../../foreign/php/target/debug/libiggy_p
 php -d 
extension="${PHP_IGGY_EXTENSION:-../../foreign/php/target/debug/libiggy_php.so}"
 basic/consumer.php
 ```
 
+### Message Envelopes
+
+The message envelope pattern wraps each payload in a JSON object with a
+`message_type` and a `payload` string, so one topic can carry several kinds of
+messages. The producer sends `OrderCreated`, `OrderConfirmed` and
+`OrderRejected` messages, and the consumer dispatches on `message_type`. A
+message with an unknown type is logged and skipped.
+
+```bash
+php -d 
extension="${PHP_IGGY_EXTENSION:-../../foreign/php/target/debug/libiggy_php.so}"
 message-envelope/producer.php
+php -d 
extension="${PHP_IGGY_EXTENSION:-../../foreign/php/target/debug/libiggy_php.so}"
 message-envelope/consumer.php
+```
+
 The examples use `IGGY_CONNECTION_STRING` when it is set; use a binary 
transport
 with credentials for automatic login. Otherwise they connect over TCP using
 `IGGY_HOST` and `IGGY_PORT`, then log in with `IGGY_USERNAME` and 
`IGGY_PASSWORD`
diff --git a/examples/php/message-envelope/consumer.php 
b/examples/php/message-envelope/consumer.php
new file mode 100644
index 000000000..1a31ae9e4
--- /dev/null
+++ b/examples/php/message-envelope/consumer.php
@@ -0,0 +1,108 @@
+<?php
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+declare(strict_types=1);
+
+require_once __DIR__ . '/../src/common.php';
+
+use Iggy\CommitPolicy;
+use Iggy\PollingStrategy;
+use Iggy\PollOptions;
+
+const ORDER_CREATED_TYPE = 'OrderCreated';
+const ORDER_CONFIRMED_TYPE = 'OrderConfirmed';
+const ORDER_REJECTED_TYPE = 'OrderRejected';
+
+const MESSAGES_PER_POLL = 10;
+
+function log_line(string $message): void
+{
+    echo $message, PHP_EOL;
+}
+
+/**
+ * Decodes the inner payload, which the envelope carries as a JSON string.
+ */
+function decode_payload(string $payload): array
+{
+    $decoded = json_decode($payload, true, 512, JSON_THROW_ON_ERROR);
+    if (!is_array($decoded)) {
+        throw new UnexpectedValueException('Envelope payload is not a JSON 
object');
+    }
+
+    return $decoded;
+}
+
+function handle_message(string $raw): void
+{
+    try {
+        // The message envelope lets one topic carry different message types.
+        $envelope = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);
+        if (
+            !is_array($envelope)
+            || !is_string($envelope['message_type'] ?? null)
+            || !is_string($envelope['payload'] ?? null)
+        ) {
+            throw new UnexpectedValueException('Envelope must contain string 
"message_type" and "payload"');
+        }
+
+        $messageType = $envelope['message_type'];
+        log_line("Handling message type: {$messageType}...");
+
+        match ($messageType) {
+            ORDER_CREATED_TYPE => log_line(
+                'Order Created: ' . 
json_encode(decode_payload($envelope['payload'])),
+            ),
+            ORDER_CONFIRMED_TYPE => log_line(
+                'Order Confirmed: ' . 
json_encode(decode_payload($envelope['payload'])),
+            ),
+            ORDER_REJECTED_TYPE => log_line(
+                'Order Rejected: ' . 
json_encode(decode_payload($envelope['payload'])),
+            ),
+            default => log_line("Received unknown message type: 
{$messageType}, skipping"),
+        };
+    } catch (JsonException | UnexpectedValueException $e) {
+        log_line('Skipping malformed message: ' . $e->getMessage());
+    }
+}
+
+$stream = 'php-message-envelope-stream';
+$topic = 'php-message-envelope-topic';
+$client = iggy_client();
+
+ensure_stream_and_topic($client, $stream, $topic);
+
+$messages = $client->pollMessages(
+    $stream,
+    $topic,
+    0,
+    CONSUMER_ID,
+    PollingStrategy::first(),
+    new PollOptions(count: MESSAGES_PER_POLL, commit: CommitPolicy::onRead()),
+)->messages;
+
+if (count($messages) === 0) {
+    log_line('No messages available. Run producer.php first.');
+    exit(0);
+}
+
+foreach ($messages as $message) {
+    handle_message($message->payload());
+}
+
+log_line('Consumed ' . count($messages) . ' message(s).');
diff --git a/examples/php/message-envelope/producer.php 
b/examples/php/message-envelope/producer.php
new file mode 100644
index 000000000..964c430e5
--- /dev/null
+++ b/examples/php/message-envelope/producer.php
@@ -0,0 +1,78 @@
+<?php
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+declare(strict_types=1);
+
+require_once __DIR__ . '/../src/common.php';
+
+const ORDER_CREATED_TYPE = 'OrderCreated';
+const ORDER_CONFIRMED_TYPE = 'OrderConfirmed';
+const ORDER_REJECTED_TYPE = 'OrderRejected';
+
+const MESSAGES_COUNT = 6;
+
+/**
+ * Wraps a payload in a message envelope. The envelope carries the message type
+ * and the payload as a JSON string, so a single topic can hold several kinds
+ * of messages.
+ */
+function to_json_envelope(string $messageType, array $payload): string
+{
+    return json_encode([
+        'message_type' => $messageType,
+        'payload' => json_encode($payload, JSON_THROW_ON_ERROR),
+    ], JSON_THROW_ON_ERROR);
+}
+
+function generate_envelope(int $orderId): string
+{
+    return match ($orderId % 3) {
+        0 => to_json_envelope(ORDER_CREATED_TYPE, [
+            'orderId' => "order-{$orderId}",
+            'customerId' => 'customer-' . random_int(0, 99),
+            'amount' => random_int(0, 9999),
+        ]),
+        1 => to_json_envelope(ORDER_CONFIRMED_TYPE, [
+            'orderId' => 'order-' . intdiv($orderId, 3),
+            'timestamp' => (int) (microtime(true) * 1000),
+        ]),
+        default => to_json_envelope(ORDER_REJECTED_TYPE, [
+            'orderId' => 'order-' . intdiv($orderId, 3),
+            'reason' => 'Insufficient balance',
+        ]),
+    };
+}
+
+$stream = 'php-message-envelope-stream';
+$topic = 'php-message-envelope-topic';
+$client = iggy_client();
+
+ensure_stream_and_topic($client, $stream, $topic);
+
+$payloads = array_map(
+    static fn (int $orderId): string => generate_envelope($orderId),
+    range(1, MESSAGES_COUNT),
+);
+
+foreach ($payloads as $payload) {
+    echo "Sending envelope: {$payload}", PHP_EOL;
+}
+
+send_payloads($client, $stream, $topic, $payloads);
+
+echo 'Sent ' . MESSAGES_COUNT . ' PHP message envelopes', PHP_EOL;

Reply via email to