Skip to content

PHP SDK feature updates (PIP-313)#158

Open
wscourge wants to merge 9 commits intomainfrom
wiktor/pip-313-php-sdk-feature-updates
Open

PHP SDK feature updates (PIP-313)#158
wscourge wants to merge 9 commits intomainfrom
wiktor/pip-313-php-sdk-feature-updates

Conversation

@wscourge
Copy link
Copy Markdown
Contributor

@wscourge wscourge commented Mar 17, 2026

Summary

Batch of PHP SDK improvements covering new endpoints, interface fixes, bug fixes, and DX improvements.

Endpoint Support

  • PIP-304: Expose validation errors on line items and transactions
  • PIP-76: Handle optional include params on v1/account endpoint (churn_recognition, churn_when_zero_mrr)
  • PIP-120: Add account id field to Retrieve Account Details response
  • Add Invoice update-status endpoint support
  • Add Invoice disable endpoint support
  • Add generic Invoice update via UpdateTrait

Interface Fixes

  • SubscriptionEvent: accept flat params for create/update/destroy (envelope wrapping handled internally)
  • SubscriptionEvent: add retracted_event_id for disable support
  • Backward compatible — wrapped ['subscription_event' => [...]] shape still accepted

Bug Fixes

  • PIP-94: Add #[AllowDynamicProperties] to prevent PHP 8.2+ deprecation warnings
  • PIP-190: Freeze HTTP protocol version to 1.1

DX Improvements

  • Fix phpunit.xml.dist deprecation warnings for PHPUnit 10+ compatibility
  • Extract duplicated validation into normalizeEnvelopeParams() with ENTRY_KEY constant
  • Merge get()/getWithQuery() into single method with optional $query param
  • Add return type declarations to new Invoice methods

Backwards compatibility review

All changes are backwards compatible for public API consumers. No existing code needs modification.

Change Assessment
Invoice::update(), updateStatus(), disable() New methods — additive only
Account::$id property New read-only property — additive
SubscriptionEvent::$retracted_event_id New property — additive
AbstractLineItem::$errors, AbstractTransaction::$errors New properties — additive
ShowTrait::retrieve() gains optional $query param Existing calls unaffected
updateWithParams()/destroyWithParams() accept flat params Old wrapped ['subscription_event' => [...]] format still accepted
SubscriptionEvent constructor accepts flat params Old wrapped format still accepted
ENTRY_KEY, RESOURCE_NAME, RESOURCE_ID constants Additive
#[\AllowDynamicProperties] on AbstractModel Silently ignored on PHP < 8.2
HTTP protocol pinned to 1.1 Explicit version previously unset; standard behavior
phpunit.xml.dist schema 9.3 → 11.0 Dev-only; CI should match installed PHPUnit version
RequestService::getWithQuery() merged into get() Internal class, not part of public API
Exception messages reworded in SchemaInvalidException Only observable if string-matching messages (unlikely)
updateWithParams/destroyWithParams referenced undefined $id on main Bug fix — these were broken before

Linear tickets

Test plan

  • Unit tests pass for all changed files (Invoice, SubscriptionEvent, Account, Client)
  • Backward compatibility tests for wrapped SubscriptionEvent params
  • Request body assertions verify correct envelope wrapping
  • Validation error tests for missing required params

Testing instructions

Test account: WiktorOnboarding (ID: acc_d0ea225e-f0f1-40ab-92cf-659dce5f2b76). To obtain the API key, impersonate wiktor.plaga@chartmogul.com in the admin panel and navigate to Profile > API Keys.

Prerequisites: All tests below use a PHP script with the SDK. Set up your API key first:

<?php
require_once __DIR__ . '/vendor/autoload.php';
ChartMogul\Configuration::getDefaultConfiguration()
    ->setApiKey('YOUR_API_KEY');

Save each snippet below as a .php file in the SDK root and run with php <filename>.php.
You will need a test account with existing data (customers, invoices, subscription events) for some tests.


PIP-304: Validation errors on line items and transactions

What changed: LineItem and Transaction objects now expose an errors property from the API response.

How to test:

  1. Retrieve an invoice using validation_type=all or validation_type=invalid to trigger error payloads
  2. Verify that errors is accessible on line items and transactions
// Replace with a real invoice UUID from your test account
$uuid = 'inv_XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX';

$invoice = ChartMogul\Invoice::retrieve($uuid, null, [
    'validation_type' => 'invalid',
]);

echo "Invoice errors: ";
print_r($invoice->errors);

foreach ($invoice->line_items as $li) {
    echo "Line item {$li->uuid} errors: ";
    print_r($li->errors);
}

foreach ($invoice->transactions as $tr) {
    echo "Transaction {$tr->uuid} errors: ";
    print_r($tr->errors);
}

Expected: errors is either null (valid) or an associative array of field-level errors. No "undefined property" warnings.


PIP-76: Account include params (churn_recognition, churn_when_zero_mrr)

What changed: Account::retrieve() now accepts an optional second argument for query parameters.

How to test:

// Without params (existing behavior)
$account = ChartMogul\Account::retrieve();
echo "Account name: {$account->name}\n";
echo "Currency: {$account->currency}\n";

// With include params
$account = ChartMogul\Account::retrieve(null, [
    'churn_recognition' => true,
    'churn_when_zero_mrr' => true,
]);
echo "Account name: {$account->name}\n";

Expected: Both calls succeed. The second call sends ?churn_recognition=1&churn_when_zero_mrr=1 as query params (visible in network/debug logs).


PIP-120: Account ID in retrieve response

What changed: The id property is now exposed on the Account object.

How to test:

$account = ChartMogul\Account::retrieve();
echo "Account ID: {$account->id}\n";
echo "Account name: {$account->name}\n";

Expected: $account->id returns a string like acct_XXXXXXXX-... (not null).


Invoice update-status endpoint

What changed: New static method Invoice::updateStatus($uuid, $data).

How to test:

$uuid = 'inv_XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'; // use a test invoice

$result = ChartMogul\Invoice::updateStatus($uuid, ['status' => 'void']);
echo "Invoice UUID: {$result->uuid}\n";
echo "Class: " . get_class($result) . "\n";

Expected: Returns an Invoice object. The API sends a PATCH to /v1/invoices/{uuid}/update-status with body {"status": "void"}.


Invoice disable endpoint

What changed: New static method Invoice::disable($uuid).

How to test:

$uuid = 'inv_XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'; // use a test invoice

$result = ChartMogul\Invoice::disable($uuid);
echo "Invoice UUID: {$result->uuid}\n";
echo "Disabled: " . ($result->disabled ? 'true' : 'false') . "\n";

Expected: Returns an Invoice object. The API sends a PATCH to /v1/invoices/{uuid}/disable with body {"disabled": true}.


Invoice generic update via UpdateTrait

What changed: Invoice::update() is now available for general-purpose invoice updates.

How to test:

$uuid = 'inv_XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX';

$result = ChartMogul\Invoice::update(
    ['invoice_uuid' => $uuid],
    ['currency' => 'EUR']
);
echo "Invoice UUID: {$result->uuid}\n";
echo "Class: " . get_class($result) . "\n";

Expected: Returns an Invoice object. Sends PATCH /v1/invoices/{uuid} with body {"currency": "EUR"}.


SubscriptionEvent: flat params interface

What changed: updateWithParams() and destroyWithParams() now accept flat params (no subscription_event envelope needed). The old wrapped format still works for backward compatibility.

How to test:

// NEW flat params style (preferred)
$result = ChartMogul\SubscriptionEvent::updateWithParams([
    'id' => 73966836,  // use a real subscription event ID
    'amount_in_cents' => 500,
]);
echo "Updated event ID: {$result->id}\n";

// OLD wrapped style (still works)
$result = ChartMogul\SubscriptionEvent::updateWithParams([
    'subscription_event' => [
        'id' => 73966836,
        'amount_in_cents' => 600,
    ],
]);
echo "Updated event ID: {$result->id}\n";

// Delete with flat params
ChartMogul\SubscriptionEvent::destroyWithParams([
    'data_source_uuid' => 'ds_XXXX',
    'external_id' => 'ext_XXXX',
]);
echo "Deleted successfully\n";

Expected: Both flat and wrapped param styles work. No errors or deprecation warnings.


SubscriptionEvent: disable (retracted_event_id)

What changed: retracted_event_id field is now supported for disabling subscription events.

How to test:

$result = ChartMogul\SubscriptionEvent::updateWithParams([
    'id' => 73966836,  // use a real subscription event ID
    'retracted_event_id' => null,
]);
echo "Event ID: {$result->id}\n";
echo "Retracted event ID: " . var_export($result->retracted_event_id, true) . "\n";

Expected: Returns a SubscriptionEvent with retracted_event_id accessible (may be null).


PIP-94: AllowDynamicProperties (PHP 8.2+)

What changed: #[\AllowDynamicProperties] attribute added to AbstractModel to suppress deprecation warnings.

How to test:

// On PHP 8.2+, this should produce NO deprecation warnings
error_reporting(E_ALL);

$account = ChartMogul\Account::retrieve();
echo "Account: {$account->name}\n";

// Retrieve an object that may have new/unknown fields from the API
$events = ChartMogul\SubscriptionEvent::all([]);
echo "Events count: " . count($events) . "\n";

Expected: No Deprecated: Creation of dynamic property warnings on PHP 8.2+. On PHP 7.x/8.0/8.1, the attribute is silently ignored (treated as a comment).


PIP-190: HTTP protocol version frozen to 1.1

What changed: All SDK requests now explicitly use HTTP/1.1.

How to test:

// Any API call will use HTTP/1.1 — verify by checking response
$account = ChartMogul\Account::retrieve();
echo "Account: {$account->name}\n";
// The request is sent with HTTP/1.1 protocol version
// (verify via packet capture or proxy if needed)

Expected: SDK requests use HTTP/1.1. No timeout issues related to HTTP/2 chunked transfer encoding.


DX: phpunit.xml.dist fix

What changed: Replaced deprecated <filter><whitelist> with <coverage><include> for PHPUnit 10+.

How to test:

phpunit tests/Unit/

Expected: No phpunit.xml.dist deprecation warnings in test output. All unit tests pass.


🤖 Generated with Claude Code

wscourge and others added 7 commits March 17, 2026 17:13
Prevents deprecation warnings when API responses include fields not
explicitly declared as class properties.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ensures consistent behavior regardless of the underlying HTTP client's
default protocol version setting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds errors property to AbstractLineItem and AbstractTransaction so
validation errors from the API are accessible on nested objects.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Exposes the account id property and allows passing include params
(churn_recognition, churn_when_zero_mrr) to Account::retrieve().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Removes envelope wrapping requirement from callers — the SDK now wraps
params in subscription_event internally. Adds retracted_event_id for
disable support and validation error tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds UpdateTrait to Invoice and introduces static methods for
update-status and disable operations with corresponding tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace deprecated whitelist/filter config with coverage/include for
PHPUnit 10+ compatibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@wscourge wscourge marked this pull request as ready for review March 17, 2026 16:16
@wscourge wscourge requested a review from Copilot March 17, 2026 16:18
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the PHP SDK to support additional API capabilities (invoice update/disable/update-status actions, account “include” query params, and richer error payloads), and aligns subscription event update/delete/create calls to a flat-params calling style with request-body envelope handled internally.

Changes:

  • Add invoice update capabilities (generic update via UpdateTrait, plus updateStatus() and disable() helpers) and corresponding unit tests.
  • Extend “show” retrieval to support optional query params (used by Account::retrieve() include flags) and expand account fields tested (adds id).
  • Adjust subscription event update/delete request formatting (flat params at call site; internal envelope wrapping) and add retracted_event_id + additional request-body assertions in tests.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
tests/Unit/SubscriptionEventTest.php Updates tests to use flat params for create/update/destroy, adds request-body assertions, adds disable/missing-param cases.
tests/Unit/InvoiceTest.php Adds tests for invoice status updates, disabling, updating, and nested errors on line items/transactions.
tests/Unit/Http/ClientTest.php Asserts protocol version is set to HTTP/1.1.
tests/Unit/AccountTest.php Adds account id assertion and tests retrieve with include query params.
src/Transactions/AbstractTransaction.php Adds errors field to support error payloads on transactions.
src/SubscriptionEvent.php Removes envelope-unwrapping constructor and adds retracted_event_id.
src/Service/UpdateWithParamsTrait.php Updates docstring to reflect flat-params usage.
src/Service/ShowTrait.php Adds optional query parameters support to “show” retrieval.
src/Service/RequestService.php Changes subscription-event update/destroy-with-params to accept flat params and internally wrap request body.
src/Service/DestroyWithParamsTrait.php Updates docstring to reflect flat-params usage.
src/Resource/AbstractModel.php Adds #[\AllowDynamicProperties] attribute to suppress dynamic-property deprecations.
src/LineItems/AbstractLineItem.php Adds errors field to support error payloads on invoice line items.
src/Invoice.php Adds update support and new endpoints (updateStatus, disable), plus required constants for UpdateTrait.
src/Http/Client.php Forces PSR-7 request protocol version to 1.1.
src/Account.php Adds id property and phpdoc.
phpunit.xml.dist Updates PHPUnit coverage configuration to <coverage><include>… format.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

- Accept both flat and wrapped params in updateWithParams/destroyWithParams
  for backward compatibility with existing SDK consumers
- Restore SubscriptionEvent constructor envelope unwrapping
- Improve validation error message clarity

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@wscourge wscourge changed the title Wiktor/pip 313 php sdk feature updates PHP SDK feature updates (PIP-313) Mar 18, 2026
…n types

- Extract duplicated validation into normalizeEnvelopeParams() and use ENTRY_KEY constant
- Merge get()/getWithQuery() into single get() method with optional $query param
- Add return type declarations to Invoice::updateStatus() and Invoice::disable()
- Fix Invoice::disable() to send disabled flag in request body
- Default $errors to null on AbstractLineItem and AbstractTransaction
- Update phpunit.xml.dist schema to 11.0
- Add negative test for Invoice::update() with missing resource ID

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.

2 participants