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

Forget Db Laravel Package

owenmelbz/forget-db

Forget DB is a Laravel safeguard that blocks accidental database writes. It intercepts INSERT, UPDATE, DELETE and schema queries, letting you run your app in a read-only mode on production or staging while logging anything that would have modified your data.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install the package

    composer require owenmelbz/forget-db
    

    The service provider is auto-discovered on Laravel 5.5+. On older Laravel versions, register OwenMelbz\ForgetDb\ForgetDbServiceProvider in config/app.php.

  2. Publish the config

    php artisan vendor:publish --provider="OwenMelbz\ForgetDb\ForgetDbServiceProvider"
    

    This drops a config/forget-db.php file. Open it — this is the single source of truth for what gets anonymized and how.

  3. Define your anonymization map. The config maps table => [column => faker_formatter]:

    return [
        'users' => [
            'name'     => 'name',
            'email'    => 'safeEmail',
            'phone'    => 'phoneNumber',
            'password' => 'password', // see gotchas — prefer hashing
        ],
        'orders' => [
            'billing_address' => 'address',
            'card_last_four'  => 'creditCardNumber',
        ],
    ];
    

    The values are Faker formatter method names (e.g. firstName, safeEmail, address). The package calls Faker for each column on each row.

  4. First use case. The classic one: you have a production dump you want to load into staging or a demo environment. Restore the dump locally, point .env at it, then run the anonymization command:

    php artisan forget-db
    

    Every configured column is overwritten in place. The schema and row count stay the same, but PII is replaced with believable fake data — so your app still works and your designers still see realistic screens.

  5. Where to look first. Read config/forget-db.php in full before touching it. If your schema has dozens of PII columns, start with the highest-risk tables (users, customers, leads, anything with email, phone, first_name, last_name, address). Run against a throwaway copy first, not production.

Implementation Patterns

In-place anonymization of a restored dump (most common pattern). Script it so it's repeatable. A typical staging refresh pipeline:

# 1. pull prod dump
pg_dump ... | pg_restore ... staging_db
# 2. anonymize
php artisan forget-db
# 3. (optional) re-seed known accounts for testing
php artisan db:seed --class=DemoAccountsSeeder

Wire this into a CI job or a small shell script (bin/refresh-staging.sh). Because the config is committed, every developer gets the same anonymized reality.

Pair with a seeder for known test accounts. Anonymization is random. If QA needs a stable login ([email protected] / password), run a seeder after forget-db that recreates the canonical accounts. Document this ordering — doing it backwards means your fixture accounts get scrambled.

Scheduled auto-scrub for long-lived non-prod environments. If you keep a shared "demo" DB alive and it periodically receives synced data, add a scheduled command:

// app/Console/Kernel.php
$schedule->command('forget-db')->weekly()->sundays()->at('03:00');

This keeps stale PII from lingering on a server that shouldn't be able to hold it (a mild GDPR/tolerance argument).

Config-driven scope control. Exclude tables you don't own (migrations, jobs, telescope entries) simply by not listing them. Keep a comment block in the config enumerating deliberately excluded PII tables so a reviewer can spot gaps — e.g. // audit_logs.ip_address intentionally NOT scrubbed — used by support.

Extend with custom Faker providers. Since the config values are formatter names, you can register your own Faker provider for domain-specific data:

$faker->addProvider(new \App\Faker\UkCompanyProvider($faker));

Then reference 'company_name' => 'ukCompanyName' in config. This is the cleanest extension point for anything not covered by stock Faker (national ID formats, internal codes, realistic-but-fake account numbers).

Use closures / custom logic where the formatter list is too rigid. For columns that need derivation (e.g. email must be [email protected]), either add a custom provider method or run a follow-up DB::table(...)->update(...) in a custom command after forget-db. Keeping bespoke logic in your own command avoids fighting the package.

Anonymize consistently across related tables. If users.id is stable but users.name and orders.customer_name are independent, the two will disagree. Either (a) only anonymize the authoritative table and leave denormalized copies, or (b) write your own post-pass that updates children from a hashed/pseudonymized key. There's no built-in cross-table consistency guarantee — plan for it.

Gotchas and Tips

  • The package is old. Last tagged release is 2020. It was written for Laravel ~5.x–7.x. If you're on Laravel 10/11, test in a throwaway branch before relying on it — service provider signatures, Faker namespaces (Faker\Generator vs the newer FakerPHP\Faker\Generator), and config publishing can all break. If it fails, a two-file custom Artisan command that reads a config array and calls DB::table($t)->update([$c => $faker->{$f}()]) reproduces 90% of the functionality.

  • Unique constraints bite immediately. safeEmail / email return values that are not unique. If users.email has a unique index, you'll get a SQLSTATE[23000] midway through the run, potentially leaving the table half-anonymized. Options: use $faker->unique()->safeEmail, chunk the update, or drop the unique index during the run and re-add it. Test against a schema with real constraints.

  • Passwords. Mapping password => 'password' writes a plaintext-looking string (still a "password" faker value), not a hash. Any login using that account will fail — which is often the intent, but be explicit. If you need working logins, use a known hash: Hash::make('password') via a custom provider, or overwrite after the run.

  • Config caching. Laravel caches config/*.php. After editing forget-db.php in a deployed environment, run php artisan config:clear (or config:cache again) or your changes won't apply. This is the #1 "why isn't my table being scrubbed?" cause.

  • Table prefixes. If your connection uses a table prefix (db_prefix), the config keys must match what the package sees. Verify by dumping one anonymized row and checking whether the update actually landed.

  • Irreversible — no dry-run. Assume there is no built-in preview. Back up first (mysqldump/pg_dump of the target DB) or run against a disposable schema, then diff. If you need a dry-run, run against a scratch copy of the DB and check a few rows.

  • Large tables. Row-by-row updates mean a full-table rewrite and heavy transaction/WAL load. On tables above ~1M rows, run off-peak, or do it in chunks with your own command rather than the single-shot artisan call. Watch lock contention on users if anything else is connected.

  • JSON / array / encrypted columns. Faker produces scalar strings. Casts like json and array will throw or silently corrupt if the package assigns a string where an array is expected. For those, either skip them in forget-db and handle in a custom post-pass (DB::table(...)->update(['meta' => json_encode([...])])), or add a custom provider. Encrypted columns are worse — you must write via the model with the cast set, not raw SQL, or the app will fail to decrypt.

  • Foreign keys. Overwriting a key column (not just a payload column) will orphan children or violate FK constraints. Never put an id or FK column in the config. For denormalized copies, see the consistency pattern above.

  • Debugging. The most useful check is: after running, SELECT the configured columns for a handful of rows and confirm the values changed. If nothing changed, it's almost always a config cache or table-name mismatch, not the package itself. Turn on query logging in a local run (DB::listen(...)) to see exactly which tables it touched.

  • Where to extend. The config map is the primary surface. Beyond that, the realistic extension points are (1) custom Faker providers, and (2) a wrapper command that calls the package then applies your own logic. Don't fork the package for a small tweak — 140 stars and a 2020 last-release means you're on your own for maintenance; a thin wrapper is cheaper.

  • Treat it as one layer, not the whole compliance story. It scrubs data in a database you've already restored. It does not help with backups, dumps in S3, logs, or exports. The GDPR-flavoured value is real, but pair it with a scoped staging access policy and a documented inventory of what is and isn't scrubbed.

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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin