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

Terms Module Bundle Laravel Package

rich-id/terms-module-bundle

A Laravel/PHP module bundle for adding terms and conditions management to your app. It packages common model, migration, and routing pieces so you can publish reusable terms content and integrate it into existing projects with less boilerplate.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install and register the bundle

    composer require rich-id/terms-module-bundle
    

    Flex should wire it automatically; otherwise add it to config/bundles.php:

    return [
        // ...
        RichId\TermsModuleBundle\RichIdTermsModuleBundle::class => ['all' => true],
    ];
    

    Confirm the actual bundle class name against the README — this is a small, early-stage package (2 stars, 0 dependents), so names in docs may drift from the code.

  2. Look here first, in this order

    • README.md — the only reliable source for the config tree and voter attribute names.
    • src/DependencyInjection/Configuration.php — the canonical list of options (entity class, table prefix, version resolver).
    • src/Security/ — the voter itself. Read it before wiring anything; it defines the attribute string you'll pass to is_granted().
    • src/Entity/ (or a Models/ dir) — the persistence shape for terms versions and user approvals.
  3. Configure the minimum Publish/define the config, point it at your User entity, and choose an approval storage target. Make sure that User class actually implements Symfony\Component\Security\Core\User\UserInterface — as of v3.0.3 the bundle's type hints target the interface rather than a concrete user class, so a custom provider or a legacy user entity that only satisfies an older contract is the most likely thing to blow up first. Then generate and run migrations for whatever tables the bundle ships (terms documents, versions, and a join table to users/approvals).

  4. First use case: gate a route behind acceptance The package exists to answer one question — has this user approved the current terms version? Start by protecting a single controller action rather than the whole app:

    #[IsGranted('TERMS_APPROVED')] // verify exact attribute in the voter
    public function checkout(): Response { /* ... */ }
    

    Render the terms page, post an "accept" action (the bundle should expose a form type or a service to record approval), and verify the grant flips. Once that single flow works end-to-end, broaden to a listener.

Implementation Patterns

Route-level gating (simplest) #[IsGranted] on controllers that legally require acceptance (checkout, publishing, API writes). Keeps the blast radius small and makes the rule visible at the call site.

Global gate via kernel listener For "everyone must accept before using the app," a kernel.request subscriber that checks the voter and redirects to the terms route. Exclude the terms route itself, login/logout, and health checks with a path regex — otherwise you get a redirect loop.

Template-level branching In Twig: {% if is_granted('TERMS_APPROVED') %} to show/hide a banner or nav item. Note that is_granted with an anonymous token returns false, so pair it with an app.user check if you want different behaviour for guests vs. logged-in-but-not-accepted users.

Version-bump workflow The version support is the point of the package. Typical loop:

  1. Author a new terms document/version via the admin surface (or a fixture/console command).
  2. Users who accepted the previous version now fail the voter for the new one.
  3. On accept, store (user, version, acceptedAt) — never overwrite the previous row if you want an audit trail.

Wire this into your deploy process: bump the version as part of a release, and expect a wave of re-acceptance traffic the first day.

Post-acceptance hook If the bundle dispatches an event on approval (check src/Event/), subscribe to it for side effects — sending a confirmation email, stamping user->setTermsAcceptedAt(), or recording an audit log entry. Prefer the event over duplicating logic in the controller.

Testing Instantiate the voter directly in a unit test with a mocked token and user; assert on the expected attribute name and on the version comparison boundary (same version → granted, older version → denied). Mock the user against UserInterface rather than your concrete entity — that mirrors how the bundle resolves the user post-3.0.3 and keeps the test honest about the contract it depends on. End-to-end, use a functional test that logs in, POSTs the acceptance form, and asserts the previously forbidden route now returns 200.

Gotchas and Tips

  • UserInterface compatibility is version-sensitive. v3.0.3 is explicitly a fix for UserInterface compatibility, which means earlier 3.0.x builds had a mismatch worth knowing about. If you're pinned below 3.0.3, expect type errors or silently-failed voter checks with custom user classes, UUID identifiers, or a user provider that returns a non-Doctrine object. Upgrade before debugging anything else.
  • The attribute string is the contract. Voter attributes are case-sensitive and easy to typo; a wrong string returns false silently rather than throwing. Grep the voter source for supports() and copy the literal.
  • is_granted() returns false, not an exception. In dev this looks like a broken login. Check var/log/dev.log and confirm the token is actually authenticated before blaming the bundle.
  • Voter caching / short-circuiting. Symfony skips the voter when there's no token, and your own AbstractVoter may memoize decisions per request. If you record acceptance mid-request and immediately check the grant, you may get a stale answer — redirect after acceptance rather than re-checking inline.
  • Version comparison semantics. Whether "current version" is an integer, a semver string, or the latest row in a table is defined by the bundle's resolver. If you ever change how versions are formatted, previously accepted users can be forced to re-accept (or, worse, silently pass). Pin the format and add a test for it.
  • Migration ordering. The bundle's tables must exist before the voter runs. On a fresh deploy, run doctrine:migrations:migrate before warming the cache, or you'll get table-not-found errors from a console command that touches the voter.
  • Config quirks. Symfony bundles of this size often hardcode a table prefix or assume a specific user identifier (getId() vs. getUserIdentifier()). The 3.0.3 UserInterface fix narrows this, but still verify the join column type matches your user ID type (integer vs. UUID) before running migrations.
  • Debugging tools. bin/console debug:container | grep -i terms, bin/console debug:config rich_id_terms (adjust the alias from Configuration.php), and bin/console debug:event-dispatcher will tell you what's actually registered far faster than reading the README.
  • Extension points, in order of safety: override the voter service in services.yaml (decorates:), decorate the approval storage with your own class, or replace the version resolver via config. Avoid forking the bundle — at this maturity the API may change under you, and a fork cuts you off from upstream fixes.
  • Maturity caveat. Two stars and zero dependents means you are, effectively, the QA team. Pin the version in composer.json, watch for breaking changes in patch releases (3.0.3 is a patch that changes a type contract — read the diff), and re-run your voter unit tests on every bump.
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.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo