precision-soft/symfony-doctrine-encrypt
A Symfony bundle that adds transparent field-level encryption to Doctrine ORM entities. Protect sensitive database columns at rest with configurable encryption, simple entity mapping, and seamless integration into Symfony applications.
Architecture fit. This release positions the package as a Doctrine DBAL/ORM-oriented encryption and salt-rotation component, not a generic Laravel/Eloquent encryption helper. Its core strengths are versioned salts, deterministic lookup for equality-searchable fields, scope-aware checkpointed batch commands, and online salt rotation with pre/post verification. That fits Laravel applications that already use Doctrine entities or are willing to introduce Doctrine for the encrypted domain. It is a weaker fit for Eloquent-first applications unless a clear integration layer exists, because the release repeatedly references entity managers, DBAL identifier types, inheritance strategies, and command/checkpoint scope tied to the manager.
Integration feasibility. The command surface is operationally useful: database:encrypt, database:rotate, --verify, --dry-run --verify, --from-id, and --batch-size. The new .example/ micro-kernel proves the bundle can be booted outside a full application and exercised against real engines, which lowers proof-of-concept risk. However, that example is export-ignored, so consumers will not receive the runnable harness in vendor/; it is evidence for evaluators, not a shipped integration aid. Laravel teams should confirm whether the package provides a service provider, configuration publishing, Artisan integration, and Eloquent bridging, or whether they must wrap Symfony-style commands and Doctrine mappings themselves.
Technical risk. The main upgrade risk is the checkpoint format change from v1 to v2. Any in-flight checkpointed run started on v4.6.0 must be completed on v4.6.0 or have its checkpoint deleted before upgrading; upgrading mid-run is explicitly unsupported. Public-ish API changes also need review: CheckpointService now takes scope as its first constructor argument, setIdentifierValues() narrows to integer/string values, and castIdentifierValue() may return an object built by the identifier’s DBAL type. These may be internal, but any custom commands or integrations touching checkpoint services should be treated as potentially breaking. The release fixes several serious correctness issues — stale in-process cursors, bigint binding as string, object cursors JSON-encoded incorrectly, non-advancing keyset batches, oversized --batch-size saturation, and short checkpoint writes reported as success — which materially improves production safety but also indicates the operational path was previously fragile.
Key questions. Does the package support Laravel’s native Eloquent models, or only Doctrine entities? Which Laravel, PHP, Doctrine DBAL/ORM, and database engine versions are supported? Where are salts and keys stored, and is KMS/HSM integration available? Can database:rotate and database:encrypt run concurrently against the same table or checkpoint? How are checkpoint files secured, shared, and cleaned up across hosts? Does --verify cover all encrypted fields and inheritance variants, and what is the runtime cost on large tables? Are UUID/ULID, bigint beyond PHP_INT_MAX, composite keys, and date_immutable identifiers fully supported? What is the public API stability policy for CheckpointService and command internals?
Stack fit. Treat this as a strong candidate when the encrypted data lives in Doctrine-managed entities or when the immediate need is a controlled migration of legacy plaintext columns independent of the ORM. For an Eloquent-centric Laravel application, run a short spike before committing: boot the package in the app, map one non-critical entity, encrypt and read a field through the ORM, exercise deterministic lookup, and run --dry-run --verify. If that spike requires parallel Doctrine metadata or custom query paths for every encrypted field, the integration cost is higher than the command surface suggests.
Migration path. Start with a backup and a staging copy that mirrors production identifier types, inheritance mappings, and salt configuration. Inventory encrypted fields, searchable fields, and legacy plaintext tables. Run --dry-run --verify first to confirm the package can read stored columns and report rows still on another salt. Then backfill plaintext with database:encrypt using conservative --batch-size values and checkpoints. After encryption, rotate salts online with database:rotate, using verification before and after. For upgrades, freeze checkpointed runs: either finish an in-flight v4.6.0 run with v4.6.0 or delete the v1 checkpoint, then upgrade. Do not deploy v4.7.0 while a checkpointed run is mid-flight.
Compatibility. Pin the package version and validate against the exact Laravel, PHP, Doctrine, and database versions in use. The checkpoint v1 refusal is a hard operational boundary, not a silent migration. The identifier-type fixes are valuable but imply that staging must include bigint, date_immutable, UUID/ULID, and Stringable identifiers where relevant. The CI quality gate rising to 95% MSI is a positive signal, but it does not replace application-level integration testing. Confirm whether the shipped package includes Laravel configuration, service provider wiring, and migrations, or whether those remain consumer responsibilities.
Sequencing. Recommended order: 1) confirm Laravel/Doctrine fit and ownership of key management; 2) inventory fields, query patterns, and identifier types; 3) run the .example-style proof in a staging micro-kernel or Laravel app; 4) rehearse plaintext encryption and salt rotation on a production-sized copy; 5) define checkpoint storage, permissions, retention, and cleanup; 6) deploy encryption with dry-run verification and bounded batches; 7) rotate salts with online verification; 8) add dashboards and runbooks before broad rollout.
Maintenance. The package is actively maintained and the release shows meaningful investment in correctness and test coverage. The trade-off is that operational artifacts and internals can change: checkpoint format versioning, constructor signatures, identifier casting behavior, and command semantics. A TPM should budget for release-note review before every upgrade and maintain a version pin with an explicit upgrade window.
Support. Error reporting is materially better: failed batches name the entity and cursor, identifier rebuild failures name the type and field, and verification names fields and row counts still on another salt. That reduces mean time to diagnose. Support still requires Doctrine literacy and salt-lifecycle knowledge; this is not a package a general Laravel support team can troubleshoot from application logs alone. The .example/ suite is useful for vendor confidence but is not shipped to consumers, so internal runbooks must carry the operational knowledge.
Scaling. Batch processing, cursor-based resume, and checkpointing are the right primitives for large tables. The fixes around batch-size saturation, non-advancing cursors, and integer binding remove several ways a large migration could stall or overrun. Still, --verify and rotation are scan-heavy operations; plan for read load, batch windows, and database-specific locking behavior. Deterministic lookup across multiple active salt versions is valuable during rotation, but random-column search remains intentionally refused, so product search requirements must be designed around searchable fields rather than retrofitted onto encrypted random data.
Failure modes. The most important operational failure is a checkpoint whose scope no longer matches the command, entity manager, or salt version; the package now refuses rather than resumes incorrectly, which is safer but requires a clean restart path. A v1 checkpoint after upgrade is similarly blocked. Lost or corrupted checkpoint files, concurrent runs sharing a checkpoint path, and rows under salts removed from configuration are the main runbook cases. The release fixes short checkpoint writes and stale in-process cursors, but teams should still treat checkpoint files as stateful operational data with backup and cleanup policies.
Ramp-up. Expect moderate ramp-up for a Laravel team without Doctrine experience. Engineers need to understand entity mappings, DBAL identifier types, deterministic lookup constraints, salt version lifecycle, and checkpoint scope before running production rotations. The best enablement path is a staging rehearsal using the same identifier types and engines as production, followed by a documented runbook covering dry-run verification, checkpoint handling, interrupted-run recovery, and the v4.6.0-to-v4.7.0 upgrade boundary.
How can I help you explore Laravel packages today?