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 Settings Kit Laravel Package

metalinked/laravel-settings-kit

A Laravel settings kit for storing and managing application configuration in the database. Provides a simple API to define, retrieve, and update settings, making it easy to add admin-editable options and runtime configuration to Laravel apps.

View on GitHub
Deep Wiki
Context7

Getting Started

This is the release that makes laravel-settings-kit safe to expose. v2.0.1 turns encrypted settings into write-only values at every boundary the package owns — panel(), the JSON endpoints, settings:export, settings:list — while get() in your own PHP code still returns the decrypted plaintext. If you are picking the package up now, start here:

  1. Read the README "when to use / when not to use" section first. It was rewritten in this release and will save you from adopting the package for a use case it does not target (it is a per-model settings store with global inheritance and a panel/JSON layer, not a general config or feature-flag service).
  2. Skim the new settings screens guide before you write any UI. It covers Blade, Livewire and a JS SPA, which is exactly the surface this release changed. Building a screen without reading it is how you end up rendering secrets.
  3. Look at the publishable config and migration first. Decide which settings are encrypted up front — retrofitting encryption onto an existing stored value is the one migration that is genuinely painful.
  4. First use case: one encrypted per-user credential (an API key for a third-party service) plus one non-encrypted preference (a locale or a notification toggle). This exercises inheritance, the panel payload, the JSON endpoints, and the export command in a single feature, which is where all the sharp edges in this release live.

The mental model to hold: a setting has a value and a default, and the default can be inherited from a global scope. A user row overrides the global row; if the user has no row, they inherit. Encrypted settings follow the same inheritance rule — but as of v2.0.1, an inherited encrypted default is null outside your code.

Implementation Patterns

Write-only secrets, read-only flags in the UI. The core pattern the release pushes you toward: never bind a form field to a secret's value. Drive the UI from the two new panel flags:

  • filled — whether any value exists (own or inherited). Use this for "configured / not configured" badges, the placeholder text ("•••••••• saved"), and empty-state logic.
  • encrypted — whether the value is a secret. Use this to switch the input type, disable autocomplete, and hide the value entirely.

The rule from the upgrade notes is worth repeating verbatim in your code review checklist: display filled, and only send a new value when the user actually types one. An untouched field must submit nothing — not null, not "".

Null is now a no-op, not a write. The JSON endpoints ignore null and empty values for encrypted settings, so round-tripping a panel payload back to the server no longer wipes a stored secret. This makes the naïve "serialize the whole panel, PATCH it back" SPA pattern survivable, but do not lean on it as your only protection — a client that sends a stale non-empty value will still overwrite. Treat the ignore-null behaviour as a safety net, not a design.

Deletion is explicit. Removing a secret is a deliberate DELETE /settings/me/{key}. Wire a "Clear" / "Remove" action next to the secret field, confirm it, and refresh the panel afterwards so filled flips back. Do not offer "clear the textbox and save" as a deletion path — it is silently a no-op, and your user will believe the secret is gone.

Keep decryption inside your own code. get() still returns plaintext, so the pattern is: resolve the setting server-side in a service or action, hand it to the HTTP client, and never let it reach a view, an API resource, a JSON column, a log line, or an exception message. The package has now drawn the line at its own boundary; everything past that line is yours.

Export and list are for humans, not pipelines. settings:export skips encrypted settings unless --with-secrets is passed. Default to the safe form in any backup or diff script, and treat --with-secrets as an incident-response tool that writes to a file you delete afterwards. settings:list printing (encrypted) is the sanity check you run first when someone claims a setting is "missing" — it is usually present and simply not printable.

Inheritance-aware tests. Assert the three states that matter for each encrypted setting: unset and inheriting from the global row, explicitly set on the model, and explicitly deleted (DELETE) falling back to inherited. Write one test that hits the JSON endpoint and asserts value and default are both null for an encrypted key — it is a one-line regression guard against exactly the class of bug this release fixes.

Gotchas and Tips

  • This is a patch version carrying a behaviour change. Anyone who was rendering an encrypted value from panel() or a JSON payload will now see null — including, as the notes call out, an inherited global secret surfacing as a model's default. That is the fix, not a bug, but it will look like one in a UI that was quietly leaking. Audit every view, Livewire component and SPA route that touches an encrypted key before you ship the upgrade.
  • settings:export output changes shape. If a backup job, diff, or fixture compares export output, dropping encrypted rows will break it. Either add --with-secrets deliberately (and secure the artifact) or update the comparison to tolerate the absence.
  • Empty string vs. null vs. absent. The endpoints ignore null and empty values; your form should still send neither. A "save" that writes "" into a non-encrypted field behaves normally, so the bug hides until someone applies the same form logic to a secret. Use distinct request shapes for "unchanged" and "set".
  • A null default is ambiguous. For encrypted settings, default: null means "hidden", not "no default configured". If your UI distinguishes inherited from explicit values, use filled plus your own knowledge of which keys are encrypted — do not infer it from the payload.
  • Debugging tip: when a value "disappears", check in this order — is it encrypted in the config, was --with-secrets omitted, is the row present (via settings:list showing (encrypted)), and did the client actually send a non-empty value. Four distinct causes producing one identical symptom.
  • The extension point is panel(). It is the single place that assembles what the UI sees, so any new derived flag, label, or grouping belongs there rather than in three separate Blade templates and a SPA. Read its implementation before adding a field — you are working against a documented contract now that filled and encrypted are part of it.
  • Do not cache decrypted values in a panel-shaped structure. It is tempting to memoise the panel payload for the SPA; that reintroduces exactly the leak the release removed. Cache the plaintext server-side keyed by model if you must, and rebuild the panel from filled/encrypted.
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.
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle