Repository navigation
fix: skip malformed list entries and coerce account bodies instead of throwing TypeError - #21
Merged
Merged
Conversation
Two response-shape TypeErrors left over from the 2.1.1 sweep: - every paginated list model mapped $data['results'] through a closure typed fn (array $x); one non-object entry made the whole call a TypeError. Six models now filter to arrays before mapping (and keep their existing null-vs-[] semantics for a missing/invalid results key). - AccountResource::balance()/turnover() round-tripped the response through json_encode/json_decode and returned it under an array type; a non-object body produced 'Return value must be of type array, string returned'. Both now coerce to [] instead. Tests cover a mixed results list, an all-invalid list, and both account methods against a string body; all four fail with the original TypeError on the previous code.
LiyanaAmil
approved these changes
Oct 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Two
TypeErrorshapes were left over from the v2.1.1 sweep — the same class as #18 (a decoded response value reaching a typed parameter or return), just at different call sites. Both are reachable only if the gateway (or a proxy in front of it) answers with a shape the schema does not describe, which is exactly what happened withGET /public_key/.1. A list entry that is not an object. Every paginated list model maps
resultsthrough a closure typedfn (array $x):{"results": ["x"]}→TypeError: WebhookList::{closure}(): Argument #1 ($w) must be of type array, string given. One bad entry fails the whole page, including the entries that were fine.2. A non-object body from the account endpoints.
A string body round-trips to a string →
TypeError: AccountResource::balance(): Return value must be of type array, string returned.Changes
lib/Model/{WebhookList,CompanyStatementList,ClientList,ClientRecurringTokenList}.php— filterresultsto arrays before mapping (array_filter($results, 'is_array')+array_values()); a missing/invalidresultskey still yields[]as before.lib/Model/Billing/{BillingTemplateList,BillingTemplateClientList}.php— same item filtering, keeping their existingnullfor an absent/invalidresultskey.lib/Resource/AccountResource.php—balance()andturnover()coerce a non-array decode to[].tests/ResponseShapeTest.php— four cases: a mixed list (one string + one valid object, asserts the valid entry still comes through), an all-invalid list, and both account methods against a string body.CHANGELOG.md— two### Fixedentries under[Unreleased].Verification
composer test— 131 tests, 381 assertions, OK.composer phpstan— no errors (level 8 + bleedingEdge).composer cs-check— clean.lib/reverted, all four fail with exactlyWebhookList::{closure}(): Argument #1 ($w) must be of type array, string given,BillingTemplateList::{closure}(): Argument #1 ($r) must be of type array, string given,and
AccountResource::balance()/turnover(): Return value must be of type array, string returned.Potential Risks & Review Items
resultsstill carries every valid entry, andnext/previousare untouched.nullfor an absent/invalidresultskey in the two billing models,[]in the rest). I preserved each model's existing behaviour rather than normalising them in this PR — worth a follow-up decision, but changing it here would be a silent API change.array_values()re-indexes the filtered results; previously the map preserved keys fromresults(which is always a JSON array, so indexes were already sequential).[Unreleased]section (adds### AddedforNetworkException). Whichever merges second will need a trivial rebase — flagging so it does not read as a surprise conflict.[Unreleased].