Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,26 +58,26 @@ final class DownloadFileMessage extends Message
public readonly string $destinationPath,
) {}

public static function fromData(string $type, bool|int|float|string|array|null $data): static
public static function fromPayload(string $type, bool|int|float|string|array|null $payload): static
{
if ($type !== self::TYPE) {
throw new \InvalidArgumentException("Expected type \"" . self::TYPE . "\", got \"$type\".");
}
if (!is_array($data)
|| !is_string($data['url'] ?? null)
|| !is_string($data['destinationPath'] ?? null)
if (!is_array($payload)
|| !is_string($payload['url'] ?? null)
|| !is_string($payload['destinationPath'] ?? null)
) {
throw new \InvalidArgumentException('Invalid data for ' . self::class . '.');
}
return new self($data['url'], $data['destinationPath']);
return new self($payload['url'], $payload['destinationPath']);
}

public function getType(): string
{
return self::TYPE;
}

public function getData(): array
public function getPayload(): array
{
return ['url' => $this->url, 'destinationPath' => $this->destinationPath];
}
Expand Down
34 changes: 17 additions & 17 deletions docs/guide/en/best-practices.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ final class ProcessPaymentHandler implements MessageHandlerInterface
{
public function handle(MessageInterface $message): void
{
$paymentId = $message->getData()['paymentId'];
$paymentId = $message->getPayload()['paymentId'];

// Always processes payment, even if already done
$this->paymentService->process($paymentId);
Expand All @@ -28,7 +28,7 @@ final class ProcessPaymentHandler implements MessageHandlerInterface
{
public function handle(MessageInterface $message): void
{
$paymentId = $message->getData()['paymentId'];
$paymentId = $message->getPayload()['paymentId'];

// Check if already processed
if ($this->paymentRepository->isProcessed($paymentId)) {
Expand Down Expand Up @@ -64,7 +64,7 @@ final class ProcessPaymentHandler implements MessageHandlerInterface

public function handle(MessageInterface $message): void
{
$paymentId = $message->getData()['paymentId'];
$paymentId = $message->getPayload()['paymentId'];

// State leaks between messages and grows over time
if (isset($this->processedIds[$paymentId])) {
Expand All @@ -84,7 +84,7 @@ final class ProcessPaymentHandler implements MessageHandlerInterface
{
public function handle(MessageInterface $message): void
{
$paymentId = $message->getData()['paymentId'];
$paymentId = $message->getPayload()['paymentId'];

// Use persistent storage for deduplication/idempotency
if ($this->paymentRepository->isProcessed($paymentId)) {
Expand Down Expand Up @@ -113,7 +113,7 @@ final class ProcessPaymentHandler implements MessageHandlerInterface
public function handle(MessageInterface $message): void
{
try {
$this->service->process($message->getData());
$this->service->process($message->getPayload());
} catch (\Throwable $e) {
// Message is marked as processed but actually failed
}
Expand All @@ -125,7 +125,7 @@ public function handle(MessageInterface $message): void
```php
public function handle(MessageInterface $message): void
{
$this->service->process($message->getData());
$this->service->process($message->getPayload());
// Exception will trigger failure handling
}
```
Expand Down Expand Up @@ -278,7 +278,7 @@ final class EmailHandler implements MessageHandlerInterface
public function handle(MessageInterface $message): void
{
$start = microtime(true);
$this->sendEmail($message->getData());
$this->sendEmail($message->getPayload());
$this->metrics->timing('email.duration', microtime(true) - $start);
}
}
Expand Down Expand Up @@ -522,10 +522,10 @@ final class ProcessPaymentHandlerTest extends TestCase
```php
public function handle(MessageInterface $message): void
{
$data = $message->getData();
$payload = $message->getPayload();

// No validation - trusts all input
$this->processUser($data['userId']);
$this->processUser($payload['userId']);
}
```

Expand All @@ -534,13 +534,13 @@ public function handle(MessageInterface $message): void
```php
public function handle(MessageInterface $message): void
{
$data = $message->getData();
$payload = $message->getPayload();

if (!isset($data['userId']) || !is_int($data['userId'])) {
if (!isset($payload['userId']) || !is_int($payload['userId'])) {
throw new InvalidArgumentException('Invalid userId');
}

$this->processUser($data['userId']);
$this->processUser($payload['userId']);
}
```

Expand All @@ -558,10 +558,10 @@ public function handle(MessageInterface $message): void
```php
public function handle(MessageInterface $message): void
{
$data = $message->getData();
$payload = $message->getPayload();

// Directly using external data in SQL
$this->db->query("DELETE FROM users WHERE id = {$data['userId']}");
$this->db->query("DELETE FROM users WHERE id = {$payload['userId']}");
}
```

Expand All @@ -570,15 +570,15 @@ public function handle(MessageInterface $message): void
```php
public function handle(MessageInterface $message): void
{
$data = $message->getData();
$payload = $message->getPayload();

// Validate and sanitize
if (!isset($data['userId']) || !is_int($data['userId']) || $data['userId'] <= 0) {
if (!isset($payload['userId']) || !is_int($payload['userId']) || $payload['userId'] <= 0) {
throw new InvalidArgumentException('Invalid userId');
}

// Use parameterized query
$this->db->query('DELETE FROM users WHERE id = :id', ['id' => $data['userId']]);
$this->db->query('DELETE FROM users WHERE id = :id', ['id' => $payload['userId']]);
}
```

Expand Down
14 changes: 7 additions & 7 deletions docs/guide/en/consuming-messages-from-external-systems.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ External producer then always publishes `"type": "file-download"`.
`Yiisoft\Queue\Message\Serializer\MessageSerializer` expects the decoded payload to be an object with these keys (with the default `JsonMessageEncoder`, the message is a JSON string):

- `type` (string, required)
- `data` (any JSON value, optional; defaults to `null`)
- `payload` (any JSON value, optional; defaults to `null`)
- `meta` (object, optional; defaults to `{}`)

Minimal example:

```json
{
"type": "file-download",
"data": {
"payload": {
"url": "https://example.com/file.pdf",
"destinationFile": "/tmp/file.pdf"
}
Expand All @@ -58,7 +58,7 @@ Full example:
```json
{
"type": "file-download",
"data": {
"payload": {
"url": "https://example.com/file.pdf",
"destinationFile": "/tmp/file.pdf"
},
Expand All @@ -76,7 +76,7 @@ The `meta` key is a general-purpose metadata container (for example, tracing, co
## 3. Data encoding rules

- The payload must be UTF-8 JSON.
- `data` and `meta` must contain only JSON-encodable values:
- `payload` and `meta` must contain only JSON-encodable values:
- strings, numbers, booleans, null
- arrays
- objects (maps)
Expand Down Expand Up @@ -106,7 +106,7 @@ import json

payload = {
"type": "file-download",
"data": {"url": "https://example.com/file.pdf"}
"payload": {"url": "https://example.com/file.pdf"}
}

body = json.dumps(payload, ensure_ascii=False).encode("utf-8")
Expand All @@ -117,7 +117,7 @@ body = json.dumps(payload, ensure_ascii=False).encode("utf-8")
```js
const payload = {
type: 'file-download',
data: { url: 'https://example.com/file.pdf' },
payload: { url: 'https://example.com/file.pdf' },
};

const body = Buffer.from(JSON.stringify(payload), 'utf8');
Expand All @@ -128,6 +128,6 @@ const body = Buffer.from(JSON.stringify(payload), 'utf8');
```sh
curl -X POST \
-H 'Content-Type: application/json' \
--data '{"type":"file-download","data":{"url":"https://example.com/file.pdf"}}' \
--data '{"type":"file-download","payload":{"url":"https://example.com/file.pdf"}}' \
https://your-broker-gateway.example.com/publish
```
4 changes: 2 additions & 2 deletions docs/guide/en/envelopes.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ An envelope implements `Yiisoft\Queue\Message\EnvelopeInterface`, which itself e
An envelope is transparent to callers: it delegates the wrapped message type and data unchanged.

- `getType()` is delegated to the wrapped message.
- `getData()` is delegated to the wrapped message.
- `getPayload()` is delegated to the wrapped message.

Envelopes modify the metadata returned by `getMetadata()` and may provide convenience methods for accessing specific metadata entries (for example, `getId()` in an ID envelope).

Expand All @@ -21,7 +21,7 @@ To wrap a message into an envelope, envelope classes provide:

and, via `MessageInterface` inheritance, also support:

- `Envelope::fromData(string $type, mixed $data, array $metadata = []): static`
- `Envelope::fromPayload(string $type, mixed $payload): static`

## Built-in envelopes

Expand Down
14 changes: 7 additions & 7 deletions docs/guide/en/message-handler-advanced.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,27 +30,27 @@ final class SendEmailMessage extends Message
public readonly string $body,
) {}

public static function fromData(string $type, bool|int|float|string|array|null $data): static
public static function fromPayload(string $type, bool|int|float|string|array|null $payload): static
{
if ($type !== self::TYPE) {
throw new \InvalidArgumentException("Expected type \"" . self::TYPE . "\", got \"$type\".");
}
if (!is_array($data)
|| !is_string($data['to'] ?? null)
|| !is_string($data['subject'] ?? null)
|| !is_string($data['body'] ?? null)
if (!is_array($payload)
|| !is_string($payload['to'] ?? null)
|| !is_string($payload['subject'] ?? null)
|| !is_string($payload['body'] ?? null)
) {
throw new \InvalidArgumentException('Invalid data for ' . self::class . '.');
}
return new self($data['to'], $data['subject'], $data['body']);
return new self($payload['to'], $payload['subject'], $payload['body']);
}

public function getType(): string
{
return self::TYPE;
}

public function getData(): array
public function getPayload(): array
{
return ['to' => $this->to, 'subject' => $this->subject, 'body' => $this->body];
}
Expand Down
8 changes: 4 additions & 4 deletions docs/guide/en/message-handler.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,20 @@ final class RemoteFileMessage extends Message
{
public function __construct(public readonly string $url) {}

public static function fromData(string $type, bool|int|float|string|array|null $data): static
public static function fromPayload(string $type, bool|int|float|string|array|null $payload): static
{
if (!is_array($data) || !is_string($data['url'] ?? null)) {
if (!is_array($payload) || !is_string($payload['url'] ?? null)) {
throw new \InvalidArgumentException('Invalid data for ' . self::class . '.');
}
return new self($data['url']);
return new self($payload['url']);
}

public function getType(): string
{
return \App\Queue\RemoteFileHandler::class;
}

public function getData(): array
public function getPayload(): array
{
return ['url' => $this->url];
}
Expand Down
18 changes: 9 additions & 9 deletions docs/guide/en/messages-and-handlers.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,27 +54,27 @@ final class SendEmailMessage extends Message
public readonly string $body,
) {}

public static function fromData(string $type, bool|int|float|string|array|null $data): static
public static function fromPayload(string $type, bool|int|float|string|array|null $payload): static
{
if ($type !== self::TYPE) {
throw new \InvalidArgumentException("Expected type \"" . self::TYPE . "\", got \"$type\".");
}
if (!is_array($data)
|| !is_string($data['to'] ?? null)
|| !is_string($data['subject'] ?? null)
|| !is_string($data['body'] ?? null)
if (!is_array($payload)
|| !is_string($payload['to'] ?? null)
|| !is_string($payload['subject'] ?? null)
|| !is_string($payload['body'] ?? null)
) {
throw new \InvalidArgumentException('Invalid data for ' . self::class . '.');
}
return new self($data['to'], $data['subject'], $data['body']);
return new self($payload['to'], $payload['subject'], $payload['body']);
}

public function getType(): string
{
return self::TYPE;
}

public function getData(): array
public function getPayload(): array
{
return ['to' => $this->to, 'subject' => $this->subject, 'body' => $this->body];
}
Expand All @@ -90,7 +90,7 @@ new SendEmailMessage('user@example.com', 'Welcome', 'Thank you for registering.'
The message has:

- A **message type** — a string used by the worker to look up the correct handler.
- A **data payload** — typed properties serialized via `getData()`. Must contain only `null`, scalars (`bool`, `int`, `float`, `string`), or arrays composed of the same types recursively.
- A **data payload** — typed properties serialized via `getPayload()`. Must contain only `null`, scalars (`bool`, `int`, `float`, `string`), or arrays composed of the same types recursively.

The message has no business logic, no dependencies. It is a value object — a typed data wrapper.

Expand Down Expand Up @@ -125,7 +125,7 @@ When the producer and consumer live in different applications (or even different

### Cross-language interoperability

Because the payload is just data, any language can produce or consume it. A Python service or a Node.js microservice can push a `{"type":"send-email","data":{…}}` JSON object and `yiisoft/queue` will process it correctly. No PHP class names appear in the serialized payload.
Because the payload is just data, any language can produce or consume it. A Python service or a Node.js microservice can push a `{"type":"send-email","payload":{…}}` JSON object and `yiisoft/queue` will process it correctly. No PHP class names appear in the serialized payload.

## Why JSON is the default serialization

Expand Down
4 changes: 2 additions & 2 deletions docs/guide/en/migrating-from-yii2-queue.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ being consumed. In the new package, it is divided into two different concepts: a

- A `Message` is a class implementing `MessageInterface`. It contains two types of data:
- Type. The worker uses it to find the right handler for a message.
- Data. Any serializable data that should be used by the message handler.
- Payload. Any serializable data that should be used by the message handler.

All the message data is fully serializable (that means message `data` must be serializable too). It allows you to
All the message payload is fully serializable (that means message `payload` must be serializable too). It allows you to
freely choose where and how to send and process messages. Both can be implemented in a single application, or
separated into multiple applications, or you can do sending/processing only, leaving part of the work to another
system including non-PHP ones (for example, a Go service handling CPU-intensive jobs).
Expand Down
Loading
Loading