patchlevel/hydrator
67.4
Adequate · 21 September 2026
3.4k
lines of production code
PHP
primary language
4
measurements over time
What this system is
This system is a PHP library for seamless object hydration and extraction, structured around a configurable middleware stack. It provides capabilities for automatic type resolution, transparent field encryption, and lifecycle hooks, while supporting lazy loading and metadata caching. The library is designed to handle complex data mapping scenarios with a focus on performance and extensibility.
How it got here
2023 — Hydrator rebranding and architecture overhaul
11 changes.
The project rebranded from Event Sourcing to Hydrator, replacing the core engine with a middleware-based StackHydrator and overhauling the metadata and normalizer systems for better performance and flexibility. This period involved significant API changes, including context passing and type inference, alongside a dependency update to PHP 8.5 and the introduction of comprehensive benchmarking and unit tests.
2025–2026 — Middleware architecture and extensions
14 changes.
The project refactored its core hydration process to adopt a modular middleware stack pattern, replacing the legacy implementation. This architectural shift enabled the development of several new extensions, including automatic normalizer guessing, transparent field encryption, lifecycle hooks, and data upcasting, all integrated into the new pipeline.
Features
Introduce Guesser component for automatic normalizer resolution
A new Guesser component has been added to automatically determine the appropriate normalizer for a given type. This includes a \BuiltInGuesser\ that handles standard PHP types like \DateTime\, \DateInterval\, and enums, a \MappedGuesser\ for explicit class-to-normalizer mappings, and a \ChainGuesser\ to combine multiple guessers. This allows the hydrator to resolve normalizers without manual configuration for common scenarios.
src/Guesser · high confidence
Introduce Upcast extension for data transformation
The upcast functionality has been moved from the core Hydrator namespace to a new Extension/Upcast location, introducing an UpcastExtension that allows users to register middleware for transforming data before encoding or before object transformation. A new CallbackUpcaster implementation enables custom callbacks to modify raw data payloads, providing a flexible way to handle data schema changes or legacy format adaptations without modifying the core hydrator logic.
src/Extension/Upcast · high confidence
Introduce extensible cipher key storage with PSR-16/PSR-6 caching support
The cryptography extension now provides a dedicated store layer for managing encryption keys, allowing applications to persist and retrieve cipher keys via a standardized interface. This includes an in-memory implementation for development or simple use cases, and decorators that wrap any existing store with PSR-16 or PSR-6 cache backends to improve performance through key caching. A new \CipherKeyNotExists\ exception is introduced to handle cases where a requested key is missing, ensuring clearer error reporting during decryption or key rotation operations.
src/Extension/Cryptography/Store · high confidence
Lifecycle extension for pre/post hydrate and extract hooks
Users can now attach static lifecycle methods to their classes using the new \#\[PreHydrate\], \#\[PostHydrate\], \#\[PreExtract\], and \#\[PostExtract\] attributes. The LifecycleExtension integrates a middleware and metadata enricher that automatically invoke these methods at the appropriate stages of the hydration and extraction process, allowing for data transformation or side effects before and after the core mapping logic.
src/Extension/Lifecycle · high confidence
New cryptography extension for transparent field encryption
The \src/Extension/Cryptography\ directory now contains a new extension that enables transparent encryption and decryption of sensitive object properties. Users can mark properties with the \SensitiveData\ attribute (optionally specifying a \subjectIdName\ and a fallback value) and identify the corresponding subject identifier field with the \DataSubjectId\ attribute. The extension uses a \CryptographyMiddleware\ to intercept hydration and extraction, encrypting values on write and decrypting them on read using the \BaseCryptographer\. The default implementation relies on OpenSSL (AES-128-GCM by default) and manages cipher keys via a \CipherKeyStore\. This change introduces a new behavioral capability for data protection within the hydrator pipeline.
src/Extension/Cryptography · high confidence
New documentation processing scripts for PHP code extraction and injection
Added two new executable scripts in the bin directory to automate the handling of PHP code examples within Markdown documentation. The \docs-extract-php-code\ script scans Markdown files in the docs directory, extracts fenced code blocks tagged as 'php', and saves them as separate PHP files in a \docs\_php\ directory. The \docs-inject-php-code\ script performs the reverse operation: it reads the extracted PHP files, injects their content back into the corresponding Markdown code blocks, and updates the documentation files, ensuring that the documentation always reflects the latest code examples.
bin · high confidence
Removals
Removal of MetadataHydrator class
The \MetadataHydrator\ class has been removed from the \src/Hydrator\ directory. This class previously handled object hydration and extraction by leveraging a \MetadataFactory\ to iterate over property metadata, applying normalizers and handling type mismatches. Its removal indicates a shift in how metadata-driven hydration is implemented or consumed within the library.
src/Hydrator · high confidence
Behavioural changes
Hydrator restructured with StackHydrator and explicit exception hierarchy
The core hydration engine has been replaced by a new \StackHydrator\ that processes data through a configurable stack of middlewares, supporting lazy object instantiation via PHP 8.4 proxies. The exception system has been restructured: all error classes (such as \ArrayDataRequired\, \CircularReference\, \ClassNotSupported\, \DenormalizationFailure\, \NormalizationFailure\, \ObjectRequired\, and \TypeMismatch\) now extend \RuntimeException\ and implement the \HydratorException\ interface, replacing the previous inheritance from \HydratorException\. The builder API (\StackHydratorBuilder\) now uses an \Extension\ interface to configure middlewares, guessers, and metadata enrichers with priority-based ordering.
src · high confidence
Introduction of middleware-based hydration architecture
The hydration process has been refactored to use a middleware stack pattern, replacing the previous legacy implementation. This change introduces a new \Middleware\ interface and a \Stack\ class that manages the execution chain, allowing for modular processing during object hydration and extraction. The default \TransformMiddleware\ handles the core logic, including property mapping, normalizer integration, and circular reference detection, while a new \NoMoreMiddleware\ exception provides clearer debugging information when the middleware chain is exhausted.
src/Middleware · high confidence
Library rebranded from Event Sourcing to Hydrator with new documentation and benchmarking tools
The package has been renamed from \patchlevel/event-sourcing\ to \patchlevel/hydrator\, shifting its focus to a library for seamless object hydration. This change is accompanied by the removal of the Psalm static analysis tool in favor of PHPStan, the addition of a \phpbench.json\ configuration for performance benchmarking, and the introduction of an \UPGRADE-2.0.md\ file directing users to the new documentation. The README has been updated to reflect the new package name, features, and installation instructions.
(repo-wide) · high confidence
Metadata system overhaul with caching, inheritance support, and new attributes
The metadata layer has been significantly restructured to improve performance and flexibility. Users can now cache metadata using PSR-6 or PSR-16 implementations via new factory wrappers, and metadata objects are fully serializable for persistence. The system now supports class inheritance, automatically merging child metadata with parent metadata while throwing errors for duplicated field names. New attributes allow users to ignore properties (\\#\[Ignore\]\) or mark classes for lazy loading (\\#\[Lazy\]\). Additionally, the factory now detects property types using Symfony TypeInfo, skips static properties, and provides a mechanism to enrich metadata via the \MetadataEnricher\ interface.
src/Metadata · high confidence
Normalizers now support context passing, type inference, and hydration awareness
The normalizer API has been updated to pass a context array to normalize and denormalize methods, enabling richer data exchange during serialization. Several normalizers (Object, Enum, Array, ArrayShape) now support automatic type inference via the new TypeAwareNormalizer interface, allowing them to deduce target classes or types from PHP type hints when not explicitly configured. Additionally, normalizers can now implement HydratorAwareNormalizer to receive the parent Hydrator instance, which is required for ObjectMapNormalizer and ObjectNormalizer to perform nested hydration. New normalizers have been added for DateInterval and inline closures, while existing ones like DateTime and ArrayNormalizer have been refactored to be readonly and attribute-based.
src/Normalizer · high confidence
Test coverage
Added architecture tests for exception hierarchy and class finality; Added benchmark fixtures and updated normalizer interface; Added benchmark tests for Hydrator configurations; Added test fixtures for the Cryptography extension; Added unit tests for Guesser components; Added unit tests for StackHydrator and StackHydratorBuilder; Added unit tests for cryptography key store implementations; Added unit tests for metadata classes and factories; Added unit tests for middleware stack and transformer middleware; Added unit tests for the Cryptography extension; Expanded test fixtures for normalizer and hydration features; Expanded unit test coverage for normalizer components.
Dependencies
PHP 8.5 support and dependency overhaul
The library now supports PHP 8.5 (dropping 8.1) and requires the ext-openssl extension. Core dependencies have been updated to include psr/cache, psr/simple-cache, and symfony/type-info, while dev tools like PHPUnit, PHPStan, and Infection have been upgraded to their latest major versions. The backward-compatibility check tool in the tools directory has also been updated to PHP 8.5 and roave/backward-compatibility-check v8.
(dependencies) · high confidence
Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.
How this codebase got here
This is the PUBLIC form of this artifact. Findings are listed in full, but the details of SECURITY findings — which rule fired, in which file, on which line, and how to fix it — are deliberately withheld, and any secret-scanner results are excluded entirely. Where detail is absent here it was REMOVED FOR PUBLICATION; it is not missing from the analysis. The complete artifact is available from the repository owner.
Score
- CAI 65 → 67 (+2.5)
- Rubric changed (rubric-2026.08.19 → rubric-2026.09.15) — scores are not directly comparable.
Lenses
- Code Health 96 → 97 (+1.5)
- Architecture 98 → 100 (+1.7)
- Maturity 57 → 59 (+2.4)
- Readiness 81 → 67 (-13.4)
- Security 56 → 69 (+12.4)
Resolved (39)
- Change coupling: EnumNormalizer.php ↔ ObjectNormalizer.php (src/Normalizer/EnumNormalizer.php)
- Coverage not included — suite not readable by the collector
- Dependency hygiene not measured — dependency manifest found but not parsed for hygiene
- Duplicated block (12 lines × 2) (src/Extension/Cryptography/CryptographyMiddleware.php)
- Duplicated block (15 lines × 2) (src/Metadata/AttributeMetadataFactory.php)
- Duplicated block (15 lines × 2) (src/Normalizer/ArrayShapeNormalizer.php)
- High: security finding (details withheld)
- High: security finding (details withheld)
- High: security finding (details withheld)
- High: security finding (details withheld)
- High: security finding (details withheld)
- High: security finding (details withheld)
- High: security finding (details withheld)
- High: security finding (details withheld)
- High: security finding (details withheld)
- High: security finding (details withheld)
- High: security finding (details withheld)
- High: security finding (details withheld)
- High: security finding (details withheld)
- High: security finding (details withheld)
- …and 19 more
New (90)
- Documentation: no installation or build instructions (README.md)
- Documentation: no installation or build instructions (docs/caching.md)
- Documentation: no installation or build instructions (docs/cryptography.md)
- Documentation: no usage examples (README.md)
- Duplicated block (11 lines × 2) (src/Extension/Cryptography/Cipher/DecryptionFailed.php)
- Duplicated block (12 lines × 2) (src/Extension/Cryptography/CryptographyMiddleware.php)
- Duplicated block (13 lines × 2) (src/Metadata/AttributeMetadataFactory.php)
- Duplicated block (14 lines × 2) (src/Normalizer/ArrayShapeNormalizer.php)
- Duplicated block (9 lines × 3) (src/Normalizer/DateIntervalNormalizer.php)
- High CVE: [GHSA redacted] (composer.lock)
- High CVE: [GHSA redacted] (tools/composer.lock)
- High: security finding (details withheld)
- High: security finding (details withheld)
- High: security finding (details withheld)
- High: security finding (details withheld)
- High: security finding (details withheld)
- High: security finding (details withheld)
- High: security finding (details withheld)
- High: security finding (details withheld)
- High: security finding (details withheld)
- …and 70 more
Changes since last survey
- 8 commits — 6 feature/other, 2 fixes
By area
- (repo) — 4 commits
- (root) — 3 commits
- .github/workflows — 1 commit
Notable commits
- fix: Fix ArrayNormalizer mutating the source array
- fix: Merge pull request #202 from patchlevel/fix-array-normalizer
- change: Add missing docs check
- change: Improve docs deployement to minimise CI times. * on versioned branches only trigger deploy if a changed landed in the docs * on release always trigger deploy
- change: Lock file maintenance
- change: Merge branch '1.24.x' into 2.0.x
- change: Merge pull request #204 from patchlevel/2.0.x-merge-up-into-2.1.x_AZZUHwqF
- change: Merge pull request #205 from patchlevel/improve-deploy
Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.
Survey your own repository
patchlevel/hydrator was measured the same way every project in this corpus was: the same rubric, at a pinned commit, with the result published in full. Point a surveyor at a repository you know and see whether you agree with it.
About this page
- The score is its most recent published measurement, taken on 21 September 2026 at a pinned commit. It is not a live figure and does not change until the project is measured again.
- Measured at commit 97d5c560545ef751b082838a7acaeb0767464877 — the exact code this score is about.
- Scored under rubric-2026.09.15 — the same rubric and the same method as every other entry in this index.
- Measured by watchdog.canine.dev using codehealth-analyzer preprod-fa71c66cabd8.