Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Legal Consent Laravel Package

maize-tech/laravel-legal-consent

Laravel package for managing legal consents and compliance. Track user acceptance of terms, privacy policies, and other legal documents, handle versioned agreements, and maintain an auditable consent history in your application.

View on GitHub
Deep Wiki
Context7

Getting Started

Requirements first. As of 3.3.0 the package targets PHP 8.2–8.5 and Laravel 11, 12 and 13. The release is primarily a compatibility + tooling bump (Pest/Pint/Larastan, Laravel 13 support), so if you are still on Laravel 9/10 or PHP 8.1 you must stay pinned to 3.2.x — this is the single most important thing to check before running composer update.

composer require maize-tech/laravel-legal-consent
php artisan vendor:publish --provider="Maize\LegalConsent\LegalConsentServiceProvider"
php artisan migrate

Publish the config and migrations explicitly (tags are usually legal-consent-config / legal-consent-migrations — confirm with php artisan vendor:publish and pick by number if the tag names have drifted). Read the published config/legal-consent.php before migrating: it controls the table names, the route registration (prefix + middleware), and the models used for consent records and consent types.

Then wire the trait into your authenticatable model:

use Maize\LegalConsent\Concerns\HasLegalConsents; // verify exact namespace in src/

class User extends Authenticatable
{
    use HasLegalConsents;
}

Where to look first: config/legal-consent.php → the package migrations (to see exactly what columns are persisted: consent type, document/version, timestamps, IP/user agent) → the trait in src/ (that is the whole public surface you will actually call) → the registered routes in routes/.

First use case: a registration or checkout form where the user must accept Terms & Privacy Policy. Create one consent type per legal document (terms, privacy, marketing, cookie policy), render the checkboxes, and on submit persist the acceptance through the trait. That gives you a queryable audit trail of who accepted which document version, when — which is the actual value of the package versus a boolean column on users.

Implementation Patterns

Consent types are reference data, not enums. Seed them (LegalConsentType / equivalent model) in a dedicated seeder and treat them as slowly-changing rows with slugs you reference in code. Use the slug in your frontend and validation rules (Rule::exists(...)) rather than hard-coded IDs, and give the seeder updateOrCreate semantics so re-running it in every environment is safe.

Versioning drives re-consent. The package's model is document-version aware. When you publish new Terms, insert a new version/row rather than mutating the old one. Your "does this user need to re-accept?" check then becomes: latest version of each required type vs. the user's latest accepted record for that type. Put that behind a single method/Accessor on your User (or a small ConsentStatus service) so views, middleware and API responses all agree.

Form submission / frontend integration. Two viable shapes:

  • Server-rendered: checkboxes post to your own controller, which calls the trait and redirects. Simplest, keeps consent logic in one place.
  • API/SPA: enable the package routes and point the client at them, but override the middleware in config so they sit behind auth:sanctum (and throttle) rather than being public. If you need custom payloads (e.g. extra metadata, tenant ID), publish/override the controller instead of fighting the default validation.

Enforcement pattern. Don't scatter if (! $user->hasAccepted(...)) checks. Use a small middleware (EnsureLegalConsentsAccepted) applied to the route groups that legally require it (checkout, data export, marketing opt-in), redirecting to a re-consent page. Keep marketing consent opt-in and independently revocable — never bundle it into the terms acceptance flow.

Audit / events. Listen for the package's acceptance events to write to your own append-only audit log, fire analytics, or dispatch queued jobs (welcome mail after terms accepted). If the package does not emit an event you need, wrap the trait call in your own action class — one place to add the event, easy to test.

Testing (Pest, matching the package's own migration). With RefreshDatabase, seed the consent types in a shared beforeEach, use factories for accepted/not-accepted states, and assert on the database (assertDatabaseHas on the consents table) rather than on the trait's return value alone. Add one feature test per protected route: no consent → redirect, current consent → 200, stale version → re-consent.

Contribution/workflow note for 3.3.0. The repo now runs Pest + Pint + Larastan. If you fork or send a PR, run composer update in the package, vendor/bin/pint before committing, and expect Larastan to reject untyped arrays — mirror the typing style of the migrated tests.

Gotchas and Tips

  • Upgrade path is a hard floor, not a soft deprecation. 3.3.0 drops pre-8.2 PHP and older Laravel. Check composer why-not maize-tech/laravel-legal-consent 3.3.0 before upgrading; if another dependency pins Laravel 10, you stay on 3.2.0. There are no new migrations and no config-shape changes in this release, so the upgrade itself needs no data backfill.
  • Nothing in 3.3.0 changes runtime behaviour. The diff is dependabot bumps plus test/static-analysis tooling and Laravel 13 support. If you were hoping for a bug fix, it isn't here — don't schedule a QA cycle on the assumption of changed semantics; smoke-test the consent flow and move on.
  • Morph map trap. Consent records are almost certainly stored with a polymorphic consensable/model type. If you introduce Relation::enforceMorphMap() after consents exist, previously stored FQCNs stop resolving and historical consents silently disappear from relations. Introduce the morph map before going to production, or backfill the column in one migration.
  • Route caching. Overriding routes/middleware in config is invisible until php artisan route:clear && php artisan route:cache. Same for config: php artisan config:clear after editing legal-consent.php — a stale cached config is the #1 cause of "the package routes 404 in staging but work locally".
  • Timestamps and timezones. Consent timestamps are a legal artifact. Keep app.timezone at UTC and format at the edges; if you display "accepted on" in a user's timezone, store UTC and convert — never store local time.
  • Don't over-collect. IP and user agent are commonly captured; under GDPR that is personal data with a retention obligation. Add a pruning command/scheduled job for consents belonging to deleted users (foreign_key cascade may not be enabled), and decide your retention window explicitly rather than letting the table grow forever.
  • Soft-deleted / impersonated users. If you use softDeletes or an admin impersonation feature, verify which model key the consent is recorded against — consent captured during impersonation is a compliance problem. Block consent-writing routes for impersonated sessions.
  • Withdrawal ≠ deletion. Revoking marketing consent should insert a new record (or flip an accepted flag with a timestamp), not delete the row. Deleting destroys the audit trail; the package's relational model assumes append-style history.
  • Custom models. If you publish and swap the config's model classes for your own subclasses, re-run the tests in 3.3.0's Pest style; the tooling migration occasionally surfaces previously-untyped property/method mismatches that now fail Larastan in CI but never affected runtime.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast