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

Config Writer Laravel Package

larapack/config-writer

Larapack Config Writer lets Laravel apps persist configuration changes at runtime, updating, adding, or removing config keys in files. Useful for editable settings in admin panels without manual file edits.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and pin. composer require larapack/config-writer:^1.0. Before writing any code, check the install actually resolves against your framework version — this package was last released in April 2016 and is archived. Its composer.json targets the Laravel 4/5 era (illuminate/support, illuminate/filesystem), so on Laravel 9+ you will likely need --ignore-platform-reqs, a caret bump in a fork, or an override in the replace/repositories block. Budget 30 minutes for that check before planning any feature around it.

Where to look first. The package is tiny — read the whole vendor/larapack/config-writer/src directory, not just the README. There are two layers worth understanding:

  • Repository — you construct it with a config file name (no .php, no path), e.g. new Repository('app') for config/app.php.
  • ArrayFile (the base) — decodes the PHP file into an array, gives you dot-notation get() / set(), and save() re-serialises the array back over the original file.

Everything surprising about this package lives in that last step (see Gotchas), so read the serialiser before you trust it.

First use case — a single settings toggle. Don't start with a general-purpose admin. Start with one screen that flips one boolean in a file you control:

use Larapack\ConfigWriter\Repository;

$config = new Repository('features');   // config/features.php
$config->set('beta.enabled', true);     // dot notation → nested array
$config->save();

config()->set('features.beta.enabled', true); // make it live in this request

Create config/features.php yourself as a plain, comment-free array of scalars — that file is now a data file, not a normal config file, and it must be shaped for round-tripping. Confirm the file on disk still looks like valid PHP, hit the page twice, and confirm the value survives a fresh request. That is the entire success criterion for this package; everything else is scaffolding around it.

Implementation Patterns

Wrap it, don't sprinkle it. Never call new Repository(...) from a controller. Put a thin service behind an interface so you can swap it for a DB-backed store later (you probably will):

interface SettingsStore {
    public function get(string $group, string $key, $default = null);
    public function put(string $group, string $key, $value): void;
}

A ConfigFileStore implementation owns the Repository construction, the write lock, the config()->set() mirror, and the logging. Callers just talk about settings.

Always mirror into the live config repository. The package writes to disk; it does not touch the already-booted config() repository. Any read in the same request returns the stale value unless you call config()->set() (or Config::set()) after save(). Make this a single line inside your put() so nobody can forget it.

Settings-screen flow. Validate → normalise types (the writer stores whatever you give it; a checkbox post gives you "1", you want true) → acquire lock → write → mirror → log the change with actor and old/new values → redirect. Logging matters more than usual here because the file is the only record of the change and it has no timestamps or history.

Dot notation for structure, not for everything. set('mail.from.address', ...) creates intermediate arrays automatically, which is convenient for namespacing a settings file (features.*, limits.*). But it also means a typo silently creates a new branch instead of failing — validate keys against an allowlist of known setting paths before writing.

Installer pattern. The canonical use is a setup wizard writing config/database.php or config/mail.php from form input. If you do this, read the Gotchas first: those files almost certainly contain env() calls, which the round-trip will destroy. The safe version is to have the wizard write .env (or a dedicated config/installer.php that you own) rather than rewriting Laravel's stock config files.

Atomic, locked writes. Wrap every save in an application-level lock and keep a backup:

Cache::lock("config-write:{$group}", 5)->block(3, function () use ($config, $path) {
    copy($path, $path.'.bak');   // cheap rollback
    $config->save();
});

Because the serialiser writes in place, a crash or a concurrent write mid-save leaves a half-written PHP file — which is a parse error on every subsequent request. The backup plus copy() is not paranoia; it's the difference between a broken setting and a downed site.

Testing. Never point tests at config/. Build a fixture directory of throwaway config files, and if the package resolves paths through Laravel's config path, override it in the test case ($app->useConfigPath($fixturePath) on modern Laravel, or bind a fake Repository behind your SettingsStore interface). Assert on the resulting file contents with require, not just on a return value.

Gotchas and Tips

The serialiser is lossy — this is the headline risk. Round-tripping a PHP array through the writer strips comments, rewrites formatting, and evaluates and inlines every expression. A file containing 'debug' => env('APP_DEBUG', false) comes back as 'debug' => false. Same for storage_path(), base_path(), class constants, closures, and objects (var_export will produce \SomeClass::__set_state(...), which fails at runtime). Rule: only point this package at files you own, containing only scalars and arrays. Never at stock config/app.php or config/database.php.

config:cache makes your writes invisible. If the app is deployed with a cached config, editing the file changes nothing until you re-run php artisan config:cache. On a cached-config production box, this package is effectively a no-op. Either drop config caching for the affected environment or have your store re-cache after writing — and decide that explicitly, because "the setting didn't save" reports are almost always this.

Opcache. After a write, the next process may serve the old array if opcache.validate_timestamps is off (common in tuned production PHP). Either invalidate with opcache_invalidate($path, true) after save, or accept that changes land on the next deploy/restart.

Filesystem assumptions break in containers. The file must be writable by the PHP user (and ownership must match, not just mode), and in Docker/Kubernetes the config directory is typically baked into the image or mounted read-only — writes vanish on redeploy or fail silently. If you can't guarantee a persistent writable volume, this package is the wrong tool and a DB-backed settings table is the right one.

Deploys clobber runtime writes. If config/ is tracked in git, the next deploy overwrites every setting a user saved. Either gitignore the writable config files and seed them from a .example, or store overrides in a directory outside the deploy artifact.

Concurrency has no protection of its own. There's no locking, no temp-file-and-rename, no fsync. Two admin users saving different settings simultaneously can lose one update or, worse, interleave into a corrupt file. The Cache::lock + .bak pattern above is mandatory for any multi-user surface. Prefer a queue job for writes if the surface is busy.

Debugging a bad write. Symptoms of a half-written or malformed file: blank page, ParseError, or Undefined index from a config key that used to exist. Recovery: restore .bak, run php -l config/yourfile.php to confirm it parses, then php artisan config:clear. Add the php -l check as a post-write assertion in your service if the setting is business-critical.

Maintenance posture. Archived since 2016, 39 stars, no security response, no PHP 8.1+ deprecation work. Treat it as vendored code: fork it into your own namespace, add the Laravel version constraints yourself, and keep the surface you use to the two methods (set, save). If you only need persistence of small settings, spatie/laravel-settings or a plain settings table with a cached accessor will cost you half a day and remove the "PHP file as a database" category of failure entirely — the honest recommendation for anything beyond an installer script.

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.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource