chore: land PRs #7-#10 on main - #17
Conversation
Per the CloudEvents v1.0 spec, data may be of any type (JSON value, plain text, binary), datacontenttype is optional with no default, and null is not a valid attribute value. - Type data as mixed (null when absent) instead of forcing an array - Stop injecting a default datacontenttype in the constructor and fromArray(), so round-tripping no longer fabricates an attribute - Omit absent optional attributes from toArray() instead of emitting null values - Reject empty datacontenttype in validate() Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds the optional dataschema attribute from the CloudEvents v1.0 spec, a URI identifying the schema that data adheres to. It is included in fromArray()/toArray() round-trips, omitted when absent, and rejected by validate() when present but empty. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Implements the CloudEvents v1.0 extension attribute mechanism (traceparent, partitionkey, etc.), previously dropped silently by fromArray(). - withExtension() returns a copy with the extension set, failing fast on names that are not lowercase alphanumeric or that collide with core attribute names - getExtension() reads a single extension, extensions exposes them all - fromArray() collects unknown keys as extension attributes - toArray() serializes extensions alongside core attributes - validate() enforces the spec naming rules and the boolean/integer/ string value types Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds dataschema to the README property reference and notes that absent optional attributes are omitted from toArray(), while present ones must not be empty. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Keeps data in its existing constructor position so the new optional attribute is appended rather than inserted ahead of the payload. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review feedback: a datacontenttype of only whitespace passed the exact-empty-string check while still being an invalid media type. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts: # tests/CloudEvents/CloudEventTest.php
# Conflicts: # src/CloudEvents/CloudEvent.php
Review feedback: fromArray() stored unknown keys without applying the extension name and value-type rules, so a malformed event survived parsing and was re-emitted by toArray(). fromArray() now enforces the same rules as withExtension() and validate(), and drops null-valued extensions, which the JSON format defines as equivalent to absent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Team convention: no getters or withers — with modern PHP the readonly extensions property declared in the constructor is used directly. Extensions are passed at construction time and read via $event->extensions; the name and value rules are still enforced by fromArray() and validate(). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fix: allow any data type and omit absent optional attributes
feat: add dataschema context attribute
feat: add extension attribute support
Implements the CloudEvents v1.0 JSON event format with toJson() and fromJson(), covering what most transports (HTTP structured mode, Kafka, MQs) actually exchange. - toJson() serializes the event, emitting non-UTF-8 string data as the data_base64 member since it cannot be carried in the data member - fromJson() parses and validates the envelope, decodes data_base64 (rejecting invalid Base64 and the presence of both data and data_base64), and surfaces malformed JSON as InvalidArgumentException Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review feedback: associative decoding turned JSON objects inside data
into PHP arrays, so an empty object {} was re-encoded as [] by
toJson(), and a JSON array root slipped past the object check into
fromArray() with a misleading missing-field error.
fromJson() now decodes without assoc mode, requires a stdClass root,
and keeps data as decoded JSON values (objects as stdClass), so object
and array payloads keep their JSON type on re-encode.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
feat: add JSON event format support
Greptile SummaryThis PR expands the CloudEvent model and serialization support.
Confidence Score: 4/5The PR should not merge until JSON serialization rejects invalid constructor extensions and preserves binary payloads that happen to contain valid UTF-8. Constructor-supplied extensions can produce JSON rejected by the library’s own parser, and Files Needing Attention: src/CloudEvents/CloudEvent.php; tests/CloudEvents/CloudEventTest.php Important Files Changed
Prompt To Fix All With AI### Issue 1
src/CloudEvents/CloudEvent.php:143
**Invalid extensions reach serialized output**
When a caller constructs an event with an invalid extension such as `data_base64` and serializes it without calling `validate()`, `toArray()` merges that extension directly into the output. With ordinary `data`, this emits both `data` and `data_base64`, producing JSON that the library's own `fromJson()` rejects.
### Issue 2
src/CloudEvents/CloudEvent.php:190
**Binary representation is discarded**
When `data_base64` decodes to valid UTF-8 bytes, `fromJson()` stores only the decoded string and `toJson()` subsequently emits it as ordinary `data`. For example, `"data_base64":"aGVsbG8="` becomes `"data":"hello"`, causing downstream consumers to interpret an opaque binary payload as text or JSON.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Reviews (1): Last reviewed commit: "fix: update JSON tests for the removed e..." | Re-trigger Greptile |
| $array['data'] = $this->data; | ||
| } | ||
|
|
||
| return $array + $this->extensions; |
There was a problem hiding this comment.
Invalid extensions reach serialized output
When a caller constructs an event with an invalid extension such as data_base64 and serializes it without calling validate(), toArray() merges that extension directly into the output. With ordinary data, this emits both data and data_base64, producing JSON that the library's own fromJson() rejects.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/CloudEvents/CloudEvent.php
Line: 143
Comment:
**Invalid extensions reach serialized output**
When a caller constructs an event with an invalid extension such as `data_base64` and serializes it without calling `validate()`, `toArray()` merges that extension directly into the output. With ordinary `data`, this emits both `data` and `data_base64`, producing JSON that the library's own `fromJson()` rejects.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| } | ||
|
|
||
| unset($decoded['data_base64']); | ||
| $decoded['data'] = $binary; |
There was a problem hiding this comment.
Binary representation is discarded
When data_base64 decodes to valid UTF-8 bytes, fromJson() stores only the decoded string and toJson() subsequently emits it as ordinary data. For example, "data_base64":"aGVsbG8=" becomes "data":"hello", causing downstream consumers to interpret an opaque binary payload as text or JSON.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/CloudEvents/CloudEvent.php
Line: 190
Comment:
**Binary representation is discarded**
When `data_base64` decodes to valid UTF-8 bytes, `fromJson()` stores only the decoded string and `toJson()` subsequently emits it as ordinary `data`. For example, `"data_base64":"aGVsbG8="` becomes `"data":"hello"`, causing downstream consumers to interpret an opaque binary payload as text or JSON.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
PRs #7, #8, #9 and #10 were each merged into
fix-required-attributesrather than intomain, so their changes never reached the default branch. This lands them.Included:
Plus one fix: #9 removed
withExtension()/getExtension()while #10's tests still called them, so the combination left the suite failing. Those two tests now use the readonlyextensionsproperty.composer test,composer lintandcomposer checkall pass.🤖 Generated with Claude Code