Skip to content

chore: land PRs #7-#10 on main - #17

Merged
Meldiron merged 17 commits into
mainfrom
fix-required-attributes
Jul 31, 2026
Merged

Meldiron merged 17 commits into
mainfrom
fix-required-attributes

Conversation

@Meldiron

Copy link
Copy Markdown
Contributor

PRs #7, #8, #9 and #10 were each merged into fix-required-attributes rather than into main, 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 readonly extensions property.

composer test, composer lint and composer check all pass.

🤖 Generated with Claude Code

Meldiron and others added 17 commits July 30, 2026 11:52
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
PR #9 dropped withExtension()/getExtension(), but PR #10's tests were
written before that and still called them, so the merge of both left
the suite failing. Use the readonly extensions property instead.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Meldiron
Meldiron merged commit 0964ac2 into main Jul 31, 2026
3 checks passed
@greptile-apps

greptile-apps Bot commented Jul 31, 2026

Copy link
Copy Markdown

Greptile Summary

This PR expands the CloudEvent model and serialization support.

  • Allows arbitrary event data and omits absent optional attributes.
  • Adds dataschema and extension attributes.
  • Adds CloudEvents JSON-format parsing, serialization, and binary payload handling.
  • Extends README documentation and unit coverage.

Confidence Score: 4/5

The 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 data_base64 payloads are reclassified as ordinary data whenever their decoded bytes are valid UTF-8.

Files Needing Attention: src/CloudEvents/CloudEvent.php; tests/CloudEvents/CloudEventTest.php

Important Files Changed

Filename Overview
src/CloudEvents/CloudEvent.php Adds optional attributes, extensions, and JSON-format support, but permits invalid constructor extensions to be serialized and loses binary representation for Base64 payloads containing valid UTF-8.
tests/CloudEvents/CloudEventTest.php Adds broad coverage for the new model and JSON behavior, but binary round-trip coverage omits Base64 payloads whose decoded bytes are valid UTF-8.
README.md Documents dataschema and omission of absent optional attributes without introducing an independently actionable issue.

Fix All in Claude Code Fix All in Codex

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;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 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.

Fix in Claude Code Fix in Codex

}

unset($decoded['data_base64']);
$decoded['data'] = $binary;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 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.

Fix in Claude Code Fix in Codex

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant