feat(resources): agnostic resource transformer registry - #285
Merged
Merged
Conversation
Rewrite ResourceTransformerRegistry as a container singleton that any extension can
register against without modifying the resource or model. Transformers target a
resource class, model class, interface or '*' (subclasses match), chain in ascending
priority, and can be scoped by channel (http, webhook, broadcast) and audience
(internal, public). Closures and instances are accepted alongside classes.
FleetbaseResource::resolve() applies registered transformers to every resource,
nested resource and collection item, re-filtering conditional values and honouring
without(). FleetbaseResourceCollection shares one context per collection so the new
PreparesResourceTransformation::prepare() hook can batch-load once and avoid N+1
queries. ResourceLifecycleEvent, chat participant broadcasts, Utils::serializeJsonResource
and the cached internal user payload serialize through resolve(), so transformers reach
webhook and broadcast payloads and conditional MissingValues are no longer emitted as {}.
CoreServiceProvider binds the registry, adds a $transformers property, and
registerTransformers() / registerTransformersFrom() mirroring expansion discovery.
Find::httpResourceForModel caches internal and public resolutions separately, consulting
the request only when a model has a dedicated Internal resource.
Removes the legacy duck-typed transformer API ($target + static output()), the
transform(Model) entry point, resolveByTarget(), fixClassName() and the static
$transformers array. The User resource no longer calls the registry directly.
…erage CI enforces 100% line and method coverage. Covers the remaining branches: the registry's empty-registration short circuits, invokable objects and array callables as transformers (and their generated ids), rejecting non-callable objects, collections wrapping items in non-resource classes, collections with no resolvable item resource class, and resolving without a bound request. Two defensive throws that normalize() makes unreachable are marked @codeCoverageIgnore with an explanation, and callableId() drops a branch that could never run because string transformers are always treated as classes.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## release/v1.6.68 #285 +/- ##
====================================================
Coverage 100.00% 100.00%
- Complexity 7772 7931 +159
====================================================
Files 436 438 +2
Lines 25334 25665 +331
====================================================
+ Hits 25334 25665 +331
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
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.
Summary
ResourceTransformerRegistryonly worked when a resource opted in (theUserresource was the single call site), matched by re-resolving the resource class by naming convention, allowed one transformer per target, and was a copy ofNotificationRegistry's static array. This rewrites it so any extension can register a transformer and have it applied without modifying the resource or model.FleetbaseResource::resolve()applies transformers to every resource, nested resource and collection item. Laravel routes responses, nestedjsonSerialize()and paginated responses throughresolve(), so hand-builttoArray()methods are covered. Output is byte-identical when nothing is registered.'*'(subclasses match). Transformers chain in ascendingpriority;contexts(http,webhook,broadcast) andonly(internal,public) scope them. Classes, instances, closures and batch forms are accepted; re-registering a class replaces it.PreparesResourceTransformation::prepare()runs once per collection (or once per singular resolve) with every model about to be serialized, with a sharedResourceTransformerContextto hand data totransform().ResourceLifecycleEvent::getEventData()/broadcastWith(), chat participant broadcasts,Utils::serializeJsonResource()and the cached internal user payload serialize throughresolve(). The cached user payload stops emitting"company": {}from an unfilteredMissingValue.CoreServiceProvider::$transformers,registerTransformers()andregisterTransformersFrom()mirror expansion discovery. Extensions call$this->registerTransformersFrom(__DIR__ . '/../Http/Transformers')inboot().Find::httpResourceForModelcaches internal and public resolutions separately. It consults the request only when a model has a dedicatedInternalresource, so explicit-resource models never touch the request (aUserControllerTestroute stub builds a controller inside its route resolver and recurses otherwise).Breaking changes
$targetproperty + staticoutput($model, $data)),ResourceTransformerRegistry::transform(Model, array),resolveByTarget(),fixClassName()and the static$transformersarray are removed. The only consumer was the deprecated aws-marketplace extension, which is not updated.FleetbaseResourceCollectionresolves items instead of callingtoArray(); a hand-built collection with a manually setpreserveKeysnow filters item arrays with the item's flag.See the README "Resource transformers" section and CHANGELOG for usage.
Testing
vendor/bin/pest: 1947 passed at the default 512M limit.tests/Unit/Support/ResourceTransformerRegistryTest.php,tests/Unit/Http/FleetbaseResourceTransformersTest.php,tests/Unit/Providers/CoreProviderTransformersTest.php,tests/Unit/Support/FindHttpResourceForModelTest.php; extendedEventsAndExceptionsTestandFleetbaseResourceCollectionTest.