diff --git a/README.md b/README.md index 6548b2d..2e8ce86 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,6 @@ $event = new CloudEvent( id: uniqid(), subject: 'user-123', time: CloudEvent::now(), - datacontenttype: 'application/json', data: [ 'userId' => '123', 'email' => 'user@example.com', @@ -49,7 +48,7 @@ $event = new CloudEvent( ); ``` -When using the constructor, only `type`, `source` and `id` are required. All other attributes are optional. Arrays passed to `CloudEvent::fromArray()` must also carry an explicit `specversion`. +When using the constructor, only `type`, `source` and `id` are required. All other attributes are optional. `datacontenttype` defaults to `application/json`; pass `null` to leave it unset. Arrays passed to `CloudEvent::fromArray()` must also carry an explicit `specversion`. `CloudEvent::now()` returns the current time as an RFC 3339 UTC timestamp with millisecond precision (e.g., `2025-11-07T10:00:00.123Z`), ready to use as the `time` attribute. @@ -136,7 +135,7 @@ The `CloudEvent` class supports the following context attributes according to th - **source** (required): URI-reference identifying the context in which the event happened (e.g., "https://example.com/user-service") - **specversion** (required): CloudEvents specification version (default: "1.0") - **type** (required): Event type identifier, ideally reverse-DNS prefixed (e.g., "com.example.user.created") -- **datacontenttype** (optional): RFC 2046 content type of the data field (e.g., "application/json") +- **datacontenttype** (optional): RFC 2046 content type of the data field (constructor default: "application/json") - **dataschema** (optional): URI identifying the schema that data adheres to - **subject** (optional): Subject of the event in the context of the source - **time** (optional): Timestamp of when the occurrence happened (RFC 3339 format) diff --git a/src/CloudEvents/CloudEvent.php b/src/CloudEvents/CloudEvent.php index 71bd6b5..7da33da 100644 --- a/src/CloudEvents/CloudEvent.php +++ b/src/CloudEvents/CloudEvent.php @@ -46,7 +46,7 @@ class CloudEvent * @param string $specversion CloudEvents spec version (default: "1.0") * @param string|null $subject Optional subject of the event in the context of the source * @param string|null $time Optional event timestamp in RFC 3339 format - * @param string|null $datacontenttype Optional content type of data (RFC 2046, e.g., "application/json") + * @param string|null $datacontenttype Content type of data (RFC 2046, default: "application/json"); pass null to leave it unset * @param mixed $data Optional event payload of any type * @param string|null $dataschema Optional URI identifying the schema that data adheres to * @param array $extensions Extension attributes (lowercase alphanumeric names, boolean/integer/string values) @@ -58,7 +58,7 @@ public function __construct( public readonly string $specversion = '1.0', public readonly ?string $subject = null, public readonly ?string $time = null, - public readonly ?string $datacontenttype = null, + public readonly ?string $datacontenttype = 'application/json', public readonly mixed $data = null, public readonly ?string $dataschema = null, public readonly array $extensions = [] @@ -81,6 +81,11 @@ public static function now(): string /** * Create CloudEvent from array * + * Unlike the constructor, datacontenttype is not defaulted here: a + * parsed event keeps the wire form, so an absent attribute stays + * absent (per the JSON format, absent datacontenttype already + * implies a JSON payload). + * * @param array $array * @return self * @throws InvalidArgumentException diff --git a/tests/CloudEvents/CloudEventTest.php b/tests/CloudEvents/CloudEventTest.php index cb56aeb..662a49b 100644 --- a/tests/CloudEvents/CloudEventTest.php +++ b/tests/CloudEvents/CloudEventTest.php @@ -45,10 +45,23 @@ public function testConstructorWithDefaults(): void $this->assertNull($event->subject); $this->assertEquals('test-id', $event->id); $this->assertNull($event->time); - $this->assertNull($event->datacontenttype); + $this->assertEquals('application/json', $event->datacontenttype); $this->assertNull($event->data); } + public function testDatacontenttypeAllowsExplicitNull(): void + { + $event = new CloudEvent( + type: 'test.event', + source: 'test-service', + id: 'test-id', + datacontenttype: null + ); + + $this->assertNull($event->datacontenttype); + $this->assertArrayNotHasKey('datacontenttype', $event->toArray()); + } + public function testFromArray(): void { $data = [ @@ -228,11 +241,11 @@ public function testToArrayOmitsAbsentOptionalAttributes(): void 'specversion' => '1.0', 'type' => 'test.event', 'source' => 'test-service', - 'id' => 'test-id' + 'id' => 'test-id', + 'datacontenttype' => 'application/json' ], $array); $this->assertArrayNotHasKey('subject', $array); $this->assertArrayNotHasKey('time', $array); - $this->assertArrayNotHasKey('datacontenttype', $array); $this->assertArrayNotHasKey('data', $array); }