Download the PHP package graystackit/laravel-gdpr-compliance without Composer

On this page you can find all versions of the php package graystackit/laravel-gdpr-compliance. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package laravel-gdpr-compliance

Laravel GDPR Compliance

A comprehensive GDPR/DSGVO compliance toolkit for Laravel applications. Declare personal data on your Eloquent models, manage consent, export subject data, schedule erasure with grace periods and legal hold, and maintain a tamper-evident audit trail — all through a fluent PHP API.

Features

Requirements

Installation

Publish the config and migrations:

Optionally publish translations for customization:

Quick Start

1. Declare personal data on your models

Every model that holds personal data implements PersonalData and uses one or more GDPR traits:

Related models (that are NOT subjects) use HasPersonalData and define a scope:

2. Register models in config

In config/gdpr.php, list every model that contains personal data:

3. Use the API

Trait Reference

Trait Who uses it What it provides
HasPersonalData Any model with PII (User, Order, Address, ...) Marker trait. No runtime behavior — the package reads personalData() via the registry.
IsPersonalDataSubject Only subjects (User, Customer, ...) requestDeletion(), deleteImmediately(), cancelDeletion(), requestExport(), isDeletionPending(), scopeWhereDeletionPending(), scopeWhereNotDeletionPending()
HasConsentRecords Subjects that need consent tracking grantConsent(), withdrawConsent(), hasConsent(), consentStatus(), consents() relationship

Per-Field DSL

Both behaviors are opt-in per field:

Call Effect
->field('x')->anonymizeWith('alias') Anonymize only
->field('x')->exportable() Export only
->field('x')->anonymizeWith('alias')->exportable() Both
->field('x') (nothing further) Throws on build() — the field is functionless

Built-in anonymizer aliases

Alias Class Behavior
name NameAnonymizer Replaces with "Anonymous User" (configurable via placeholder)
email EmailAnonymizer Replaces with anonymized_<random>@example.invalid (configurable domain)
phone PhoneAnonymizer Replaces with +00 000 0000000 (configurable placeholder)
ip_address IpAddressAnonymizer IPv4: masks last octet by default (octet), or half or full. IPv6: keeps first 4 groups.
address AddressAnonymizer Strings → [REDACTED ADDRESS]. Arrays → each value [REDACTED].
free_text FreeTextAnonymizer Full replacement by default. Set replace_email, replace_phone, replace_urls to selectively replace patterns.
static_text StaticTextAnonymizer Returns config.value (default [REDACTED]).

Register custom anonymizers in config/gdpr.php:

Your class must implement GraystackIt\Gdpr\Contracts\Anonymizer.

Retention Modes

Configured per model via ->retention():

Mode After grace Terminal state
delete Row is hard-deleted erased
anonymize Fields wiped via anonymizers, row stays anonymized
legal_hold Fields wiped, row retained until hold_until pending_legal_holderased after expiry

Processing order

->processOrder(int) controls the sequence when multiple models are processed for the same subject. Lower numbers go first. Convention:

Range Use
1–99 Pivot/junction tables
100–199 Direct children (Order, Address, Comment)
200–299 Indirect children (LoginAttempt, Metrics)
1000 The subject itself

This prevents FK constraint violations when children reference the subject with NOT NULL foreign keys.

Deletion Lifecycle

During the grace period, nothing is modified on host model rows. The entire grace state lives in the gdpr_deletions table. This means:

Auth during grace

The package does not lock users out during grace. Use these helpers to implement your preferred UX:

Consent Management

Database consent (authenticated users)

The consents table is append-only. Each grant and withdraw is a new row. The current state is the latest row per (subject, purpose).

ConsentPurpose::Necessary always returns true without any database check.

Cookie consent (anonymous visitors)

The ConsentCookieManager reads/writes a JSON cookie (gdpr_consent) with per-purpose booleans:

Consent middleware

Audit Log

The gdpr_audits table records deletion/export pipeline events only. It never stores:

After a subject is hard-deleted, their audit entries survive as orphans — the subject_id FK points nowhere, which means no re-identification is possible. This is by design.

Logged events: deletion_requested, deletion_scheduled, deletion_cancelled, anonymization_completed, deletion_completed, legal_hold_started, legal_hold_expired, export_requested, export_completed.

Events

The package fires these events for external system integration (e.g., deleting Stripe customers, removing Mailchimp subscribers):

Event Payload When
PersonalDataDeletionRequested GdprRequest requestDeletion() called
PersonalDataDeletionCancelled GdprRequest cancelDeletion() called
PersonalDataAnonymized GdprDeletion After fields wiped on a model
PersonalDataErased GdprDeletion After row hard-deleted
LegalHoldStarted GdprDeletion Row enters legal hold
LegalHoldExpired GdprDeletion Row exits legal hold (force-deleted)
PersonalDataExported GdprRequest Export job completed

Notifications

Four mail notifications are sent automatically (when config('gdpr.notifications.enabled') is true):

Notification When Final?
PersonalDataDeletionRequestedNotification On requestDeletion() No
PersonalDataDeletionCancelledNotification On cancelDeletion() Yes (email wiped)
PersonalDataDeletionCompletedNotification After processing Yes (email wiped)
PersonalDataExportReadyNotification After export job Yes (email wiped)

The recipient email is snapshotted into gdpr_requests.notification_email at request time, so notifications work even after the subject's data has been anonymized or deleted. After the final notification, the email is wiped.

Customizing notifications

Text only: publish translations with php artisan vendor:publish --tag=gdpr-lang and edit lang/vendor/gdpr/en/gdpr.php.

Deep customization: override the class in config/gdpr.php:

Artisan Commands

Command Purpose
gdpr:process-deletions Run daily via scheduler. Processes grace-expired and legal-hold-expired rows.
gdpr:export {subject} {id} Create an export request and dispatch the export job.
gdpr:erase {subject} {id} [--now] Request deletion. --now skips grace.
gdpr:audit [--subject=] [--id=] [--event=] Show recent audit entries with filters.
gdpr:report Summary of requests, deletions, consent counts, audit counts.
gdpr:packages-scan Scan composer.lock + package-lock.json and write inventory JSON.
gdpr:cleanup-exports [--disk=local] Delete expired export files from storage.
gdpr:prune [--dry-run] [--table=] Time-based pruning of audits, consents, policy acceptances, and stale notification emails.

Scheduling

Add to your routes/console.php or scheduler:

Package inventory

Wire the scanner into your host app's composer.json:

Access the inventory programmatically:

Pruning & Retention

The gdpr:prune command handles time-based cleanup:

Table Default retention Special rules
gdpr_audits 3 years (1095 days)
consents 3 years Latest row per (subject, purpose) is always preserved
gdpr_policy_acceptances 3 years
gdpr_requests.notification_email 7 days after terminal status Wiped to NULL, row itself retained for 3 years

Configure in config/gdpr.php:

Database Tables

Table Purpose
consents Append-only consent records (grant/withdraw) per subject and purpose
gdpr_requests Top-level request lifecycle (export/delete), email snapshot
gdpr_deletions One row per (request x affected model), retention snapshot, state machine, process_order
gdpr_audits Event-driven audit log for the deletion/export pipeline
gdpr_policy_versions Policy version definitions (privacy, imprint, ToS)
gdpr_policy_acceptances Subject acceptance records per policy version

GDPR Compliance Notes

Anonymization vs. pseudonymization

The anonymize mode replaces personal field values with non-identifying placeholders. Whether the result qualifies as true anonymization (GDPR no longer applies) or pseudonymization (GDPR still applies) depends on which fields you configure.

To achieve proper anonymization, ensure you mark all identifying fields — including quasi-identifiers:

The package gives you the tooling. Field selection is your responsibility.

Grace period

Legal hold

Backups

The package cannot reach into backup files. If you restore from a backup, pending deletion requests should be re-applied. Document your backup retention in your privacy policy and ensure backups rotate within a documented window.

Subject-to-subject references

When processing Subject A, the package never modifies Subject B — even if B has a foreign key to A. Use onDelete('set null') on FK migrations or listen to the PersonalDataErased event to handle cross-subject cleanup in your app code.

Publishing Reference

Tag What it publishes Required?
gdpr-config config/gdpr.php Yes
gdpr-migrations database/migrations/*.php Yes
gdpr-lang lang/vendor/gdpr/en/gdpr.php No — for text customization
gdpr-notifications app/Notifications/*.php No — for deep notification customization
gdpr All of the above Convenience

Testing

License

The MIT License (MIT). See LICENSE for details.


All versions of laravel-gdpr-compliance with dependencies

PHP Build Version
Package Version
Requires php Version ^8.3
illuminate/contracts Version ^11.0|^12.0|^13.0
illuminate/database Version ^11.0|^12.0|^13.0
illuminate/http Version ^11.0|^12.0|^13.0
illuminate/notifications Version ^11.0|^12.0|^13.0
illuminate/queue Version ^11.0|^12.0|^13.0
illuminate/support Version ^11.0|^12.0|^13.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package graystackit/laravel-gdpr-compliance contains the following files

Loading the files please wait ...