superbrave/gdpr-bundle
Symfony bundle for GDPR compliance that helps anonymize personal data in Doctrine entities and automate right-to-be-forgotten workflows. Configure fields, run console commands, and keep user records compliant without custom cleanup code.
This is a Symfony bundle, not a Laravel package, so as a Laravel developer the honest first step is a decision: adopt it in a Symfony service/legacy app, or port the pattern (attribute-tagged personal fields + an anonymize/export service) into Laravel. The bundle's whole value is metadata-driven: you annotate Doctrine entities, and it walks those annotations to export or anonymize.
Minimal path in a Symfony host:
composer require superbrave/gdpr-bundleSuperbrave\GdprBundle\SuperbraveGdprBundle in config/bundles.php.First use case to prove out: a "right to be forgotten" command that takes a user ID, anonymizes that record, and prints what changed. If that round-trips cleanly on one entity, the rest is annotation coverage.
Where to look first: the bundle's annotation/attribute classes (they define what can be marked and how), then the service that reads Doctrine metadata, then its test fixtures — the tests are the most reliable documentation for a 2020-era, 11-star package.
Annotation-as-schema. Treat the annotations as your personal-data inventory. Every field that is PII gets marked; everything unmarked is implicitly "safe." This is the same mental model as a Laravel $fillable/$casts contract, except it drives compliance behavior rather than mass assignment. Keep the marking exhaustive and reviewed, because the anonymizer will silently skip anything you forgot to annotate.
Anonymize, don't delete. Typical flow: soft-delete the account, then anonymize the PII columns in place so foreign keys and audit history survive. The bundle's per-field strategies (null out, replace with a placeholder, mask) map naturally onto that. For Laravel, this is exactly a queued job invoked from an account-deletion flow:
AccountDeletionRequested -> dispatch(AnonymizeUser::class) -> anonymizer->anonymize($user)
Export for subject access requests (SAR). Wire the exporter behind an authenticated, authorized endpoint — the requesting user can only export their own record. Return a stable JSON shape and store the export artifact with a timestamp; regulators care about "what was disclosed and when," not just the payload.
Batch backfills. When you add a new annotated field, existing rows are already un-anonymized. Write a one-off command that re-runs anonymization over records already marked deleted, and make the anonymizer idempotent so re-runs are safe.
Integration seam with Doctrine. If the bundle hooks Doctrine lifecycle events, be deliberate about ordering: anonymize after the soft-delete flush, not inside a pre-remove listener where the entity may still be dirty. In Laravel terms, think deleting vs deleted model events — pick the post-commit side.
Cover relations. Decide explicitly whether anonymization cascades into related entities (orders, addresses, messages). The bundle works per-entity; the policy of "what counts as the user's footprint" is yours to encode in a service that orchestrates multiple anonymize calls in one transaction.
config/gdpr.php, and bundles.php means nothing to Laravel. You will not composer require this and call it a day in a Laravel app. Realistic options: (a) run it in a Symfony sidecar/queue worker, (b) extract the annotation-reading + anonymization logic into a small internal package, (c) implement the same metadata pattern natively with PHP 8 attributes on Eloquent models. Option (c) is usually cheapest.@Gdpr\...) unless the source shows attributes. On PHP 8.1+ with doctrine/annotations removed from many stacks, the annotation reader may simply not load. Check the composer constraints against your PHP/Symfony version before committing.anonymization_log table or a dedicated log channel — never the same row you just scrubbed.How can I help you explore Laravel packages today?