Download the PHP package pushery/legal-consent-for-laravel without Composer

On this page you can find all versions of the php package pushery/legal-consent-for-laravel. 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 legal-consent-for-laravel

Legal Consent for Laravel

Latest Version PHP Version PHPStan Code Style

Court-proof, versioned legal consent for Laravel. It is a document-acceptance ledger: the package renders and proves your legal texts — it does not own them.

Why this exists

A registration does three legally distinct things, and treating them as one (a single "I accept everything" checkbox) is a common — and real — GDPR violation:

Document Legal basis UI Blocking? Withdrawable?
Terms / contract Art. 6(1)(b) — contract "I accept …" checkbox yes no (you cancel, not withdraw)
Privacy notice Art. 13/14 — information "I have read …" — never "I consent" takes notice n/a
Marketing / analytics Art. 6(1)(a) — consent separate, granular opt-in no (Art. 7(4)) yes, any time (Art. 7(3))

This package keeps them separate by design, and proves acceptance the way the law requires (Art. 7(1); EDPB 05/2020 §108): it stores the exact text a user was shown, its version and hash, and the server-side context — not just a timestamp.

Highlights:

Compatibility

Supported
PHP 8.4, 8.5
Laravel 13.x
Databases SQLite · PostgreSQL · MySQL 8.4 LTS

Every database-touching path is tested against real PostgreSQL and real MySQL 8.4 (not just SQLite), so it runs on Laravel Cloud (serverless Postgres + MySQL 8.4 LTS) out of the box. PostgreSQL is primary, but the append-only and one-active-version guarantees are enforced portably in the app layer on every engine.

Installation

The service provider is registered automatically. Publish the config and run the migrations:

Quick start

  1. Write your texts as Markdown with frontmatter at resources/legal/{type}/{locale}.md:

    version drives the ledger and decides what counts as a major change. Two optional keys, announce_at and enforce_at (or effective_at), let the text itself carry its schedule — the publish flags below override them. How a change is classified is never taken from the file: that is a decision you make per publish, at the command line.

  2. Publish a version (freezes it into the ledger; you must classify the change):

    An initial version takes effect at once — there is nothing to give notice of yet. A later material change is a different act: it must be announced ahead of its effective date, with the advance period its regime requires (see Change classes & notice modes).

  3. Give any model a consent ledger with the trait:

  4. Enforce re-consent by adding the middleware to your authenticated routes:

    It redirects to your legal.consent route (or returns 409 legal_consent_required for JSON) when a mandatory document has an outstanding new major version.

Recording consent (three ways)

All three write the same ledger through one recorder and share an idempotency flag, so they never double-write.

Way A — Fortify CreateNewUser trait (strongest proof context):

Way B — the Registered event listener (no Fortify): it is registered automatically; toggle it with legal-consent.registration.listen_to_registered_event.

Way C — the headless JSON API (opt-in via legal-consent.routes.api):

Or use the facade / manager directly:

Objecting and terminating

Two rights need their own record, because a change can be answered without accepting it:

Each appends one immutable ledger row and fires an event — ConsentObjected or ConsentTerminated — because only your app can act on it: the package cannot know which processing an Art. 21 objection must stop, or how your contract ends. Listen and act:

The delivery proof

Every pushed change notice writes an append-only legal_notices row (unless you turn durable_medium.proof off): who was informed, when, on which medium, the exact text sent, its hash, and whether the notice carried its mandatory content. That is the evidence a durable-medium notice actually went out (CJEU C-375/15) — audit it like any model:

The proof is append-only and holds personal data, so legal-consent:prune covers it on the same retention rule as the consent ledger: superseded and orphaned rows past the period go, while the newest notice per subject and document is kept — it is what proves the change behind their current standing was lawfully announced.

Change classes & notice modes

A change to a legal text is not one thing. The package models the four ways a change is communicated and enforced — NoticeMode — so a change gets exactly the notice the law requires and never more:

Notice mode When to use it The subject must… On silence Gates access?
SilentEditorial (--editorial) a typo, a clarification, a purely favourable change nothing bound no
InfoPush (--info) a material change that is information only — a payment-contract change under § 675g, a material privacy-notice update, a reference-rate change nothing (may object or terminate) takes effect regardless no
DeemedConsent (--deemed) a minor/peripheral contract change where silence may bind (Zustimmungsfiktion) object before the deadline, else nothing silence binds (§ 308 Nr. 5 BGB) no
ActiveReconsent (--active, or the legacy --material) a material/core contract change, or a new/expanded real consent actively accept before it applies not bound; the old terms continue yes

legal-consent:dispatch-notices routes each mode to the matching notification — LegalChangeInformational ("no action required"), DeemedConsentNotice (carrying the § 308 Nr. 5 lit. b "silence counts as consent" warning), or ReconsentRequired — and, with durable_medium.proof on, writes an append-only row to legal_notices proving the notice was delivered. Only ActiveReconsent ever blocks access.

The invariants (never violated)

Worked example — an info-only contract change ("no action required")

A payment-contract change your users only need to be told about:

Once the announcement date passes, dispatch-notices emails each affected subject a LegalChangeInformational ("we've updated our contract; no action is required"), records a durable-medium proof row, and the change takes effect on the effective date — no one is blocked. Render the dismissible heads-up banner from ConsentBanner:

Worked example — deemed consent with an objection window

A minor contract change where silence may bind, provided the subject gets an adequate window to object and the § 308 Nr. 5 lit. b warning.

The statutory period is measured to the objection deadline, not to the effective date — the subject must have the full period to actually object — and it is never waived, not even for an immediate change. So the deadline must be at least deemed_consent_min_days after the announcement, and the change takes effect after it:

dispatch-notices sends a DeemedConsentNotice carrying the warning and the free-termination right. A subject who does nothing is bound: once the objection deadline passes, legal-consent:close-objection-windows (hourly, auto-scheduled) records a DeemedAccepted row — silence, made provable. A subject who objects or terminates in time is recorded instead, and the fiction never applies to them.

Active re-consent (a material core change)

A material change to the core of the contract still requires active agreement, with the full grace period and a hard gate at the deadline:

Both dates are validated — you cannot smuggle a short lead by omitting --announce-at, and the minimum period is per regime (§ 675g's two months is hard). From enforce_from, the middleware blocks the subject until they re-accept the new major version. A SHA-256 hash detects any text change; a human classifies it (the notice mode) at publish time; the gate compares major_version only.

Content sources

Each document declares a source in config/legal-consent.php:

Commands

Command What it does
legal-consent:publish {key} {locale?} --editorial\|--info\|--deemed\|--active Freeze the current source into a new active version under a notice mode (--material is the legacy alias of --active). Flags below.
legal-consent:check-drift {key?} {locale?} Non-zero exit when a source has drifted from its published version (CI/cron). Narrow it to one document/locale with the optional arguments.
legal-consent:dispatch-notices Notify subjects of a due legal change, routing by notice mode (hourly, idempotent, auto-scheduled).
legal-consent:close-objection-windows Bind silence to deemed acceptance once a deemed-consent objection window closes (hourly, idempotent, auto-scheduled).
legal-consent:prune Delete records past the retention period (default 3 years); the current standing of an active subject is always kept.
legal-consent:cache-flush {key?} {locale?} Flush cached, rendered documents.
legal-consent:verify-ledger Verify the tamper-evidence hash chain (non-zero exit on a break); only when tamper_evidence is on.

legal-consent:publish flags

Exactly one mode flag per publish; the rest are optional metadata.

Flag What it means
--editorial Silent activation — a typo/formatting fix that changes no obligation. No notice.
--info Actively announced, no action required, takes effect regardless.
--deemed Silence counts as acceptance. Contract/terms only; requires --objection-at.
--active (--material) The subject must actively accept before it applies.
--regime= The legal regime the change falls under: bgb_agb, psd2_675g, dcd_327r, gdpr, p2b, or eecc. It selects the statutory advance period, so an unrecognised value is refused rather than quietly given the generic default.
--announce-at= ISO date the subjects are notified. Defaults to now.
--enforce-at= ISO date enforcement begins. Omit for an immediate publish.
--objection-at= ISO date the objection window closes (--deemed). Must leave the full statutory period after the announcement.
--offers-termination The notice offers a free right to terminate before the effective date (§ 675g / § 327r).
--keeps-unmodified The subject may keep the unmodified version (the DCD / § 327r escape hatch).
--change-class= A free-form classification tag from your legal review (e.g. agb_minor_peripheral), stored with the version for the audit trail.

A major version bump forces its mode. The publisher refuses --info/--deemed on a major bump of a contract — a material core change cannot ride on silence or mere information (BGH XI ZR 26/20) — and refuses anything but --info on a major privacy bump, because a privacy notice is acknowledged, never gated. Publish a change that needs --info/--deemed as a minor or patch bump of the source version.

UI

The core is headless — it renders and proves, and never forces a UI framework on you. Three levels, pick one:

  1. Plain Blade stubs (default, no dependency) — the consent checkboxes, the grace-period banner, and a settings page. Publish and restyle them freely:

  2. Livewire components (opt-in) — reactive, drop-in versions of the interactive screens: <livewire:legal-consent.reconsent-form /> and <livewire:legal-consent.consent-settings /> — one-click accept, withdraw (Art. 7(3)), object, and terminate. They register automatically only if you have livewire/livewire installed, so the package stays dependency-free otherwise.

  3. WireKit-flavored variant — if your app uses WireKit, publish the WireKit-themed stubs to override the plain ones:

    These are a themed starting point; a fully WireKit-native companion package is planned.

Every variant bakes in the non-negotiable anti-dark-pattern rules: checkboxes are never pre-checked (Planet49 C-673/17), a real consent is never required (Kopplungsverbot Art. 7(4)), and the full text is always linked and retrievable (clickwrap, § 305 II BGB).

Bundled translations. Every string the package renders — the grace-period banner, the consent and settings stubs, the re-consent notification, the validation messages, and the acceptance wording — ships translated in seven locales out of the box: German, English, Spanish, French, Italian, Dutch, and Portuguese. Override any of them by publishing the language files:

This is independent of legal-consent.locales, which is the set of locales you publish your own legal documents in — leave it at [de, en] even while the UI is available in all seven.

Configuration

Everything lives in config/legal-consent.php. The keys you are most likely to touch:

Key Default What it does
documents [] The registry: each key maps to its legal_basis (contract / acknowledgement / consent) and source.
default_locale · locales de · [de, en] The primary locale and the allowed set (publishing an unlisted locale is refused).
fallback_locale de When a document is unpublished in the requested locale, fall back to this one instead of failing.
retention_after_end 3 years How long proof is kept before legal-consent:prune removes superseded/orphaned records.
cache.store · cache.ttl app default · 86400 Where/how long rendered documents are cached (self-invalidates on a content change).
notifications.channels [mail, database] Channels for the change notifications.
notice_periods per regime Minimum advance-notice days per regime/mode (active_reconsent_min_days, deemed_consent_min_days, psd2_min_days, dcd_termination_days, p2b_standstill_days, eecc_min_days, privacy_advance_days). A scheduled gating change is measured announcement → effective date; a deemed-consent change is measured announcement → objection deadline (the subject must have the full period to object) and is never exempt. Too short a period is refused. A per-document min_lead_days in documents may raise a period, but never undercut a statutory floor: § 675g's two months is hard — neither an override nor this config can talk it down.
durable_medium proof: true, channels: [mail] Whether the notice dispatch writes an append-only legal_notices proof row, and on which durable-medium channels.
schedule.dispatch_notices · schedule.close_objection_windows true · true Whether the two sweeps are auto-registered on the scheduler.
middleware.allowlist_routes · middleware.allowlist_paths [] · [] Extra route names, and extra URI paths (wildcards allowed, e.g. billing/*), the gate never blocks. The consent route and logout are always allowed.
routes.consent_name · routes.consent_path — · /legal/consent Where to send a subject to act: consent_name is a route name (preferred — it survives a path change), consent_path the fallback URL. Used by the middleware redirect and by the link in every change notice, so a wrong value points the legally-required notice at a dead URL.
routes.api · routes.api_prefix · routes.api_middleware false · legal · [api, auth] Whether the headless JSON API is registered, under which prefix, behind which middleware.
markdown.html_input · markdown.allow_unsafe_links · markdown.max_nesting_level strip · false · 10 CommonMark hardening for rendering document sources. Loosen html_input only for sources you fully control — a legal text is rendered into your users' browsers.

Optional features (each off by default)

Upgrading

0.2.x → 0.3.0

Backward-compatible: existing code, config, and ledger rows keep working. Run the migrations and you are done.

What they do:

Then, optionally:

Testing

Security

Please review the security policy and report vulnerabilities privately rather than opening a public issue.

Built by Pushery

This package is built and maintained by Pushery — a Berlin-based studio building Laravel applications, SaaS products, and open-source tools.

Building a Laravel UI? WireKit, Pushery's open-source Livewire component kit, gives you a polished component library out of the box. Browse the rest of our work at pushery.com.

License

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


All versions of legal-consent-for-laravel with dependencies

PHP Build Version
Package Version
Requires php Version ^8.4
ext-dom Version *
ext-json Version *
ext-libxml Version *
illuminate/auth Version ^13.0
illuminate/bus Version ^13.0
illuminate/cache Version ^13.0
illuminate/collections Version ^13.0
illuminate/console Version ^13.0
illuminate/contracts Version ^13.0
illuminate/database Version ^13.0
illuminate/http Version ^13.0
illuminate/log Version ^13.0
illuminate/notifications Version ^13.0
illuminate/routing Version ^13.0
illuminate/support Version ^13.0
league/commonmark Version ^2.7
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 pushery/legal-consent-for-laravel contains the following files

Loading the files please wait ...