- How do I migrate existing settings from .env or config files to spatie/laravel-settings?
- Start by defining a `Settings` class for each group (e.g., `AppSettings`). Use the `make:settings-migration` Artisan command to scaffold a migration, then manually populate the database with existing values. For dynamic values, consider a one-time import script or middleware to sync changes. Always test in staging first to avoid production downtime.
- Can I use Redis for settings storage instead of the database?
- Yes, the package supports Redis out of the box. Bind the `SettingsRepository` to a Redis-backed implementation in your `AppServiceProvider` using `app()->bind(SettingsRepository::class, RedisSettingsRepository::class)`. Redis is ideal for high-read scenarios, but ensure you handle persistence (e.g., fallback to DB) if Redis fails.
- Will this work with Laravel 11 and PHP 8.2+?
- The package is actively maintained and supports Laravel 10+ and PHP 8.1+. For Laravel 11, verify compatibility by checking the [GitHub releases](https://github.com/spatie/laravel-settings/releases) or running `composer require spatie/laravel-settings`—it will auto-resolve dependencies. PHP 8.2 features like read-only properties are fully supported in the latest version.
- How do I validate settings updates before saving?
- Use Laravel’s FormRequest validation. Create a request class (e.g., `GeneralSettingsRequest`) extending `FormRequest` and define rules in the `rules()` method. Inject the validated request into your controller alongside the `Settings` class, then update and save. Example: `public function update(GeneralSettingsRequest $request, GeneralSettings $settings)`.
- What’s the best way to cache settings for performance?
- Enable caching by configuring the `SettingsRepository` to use Laravel’s cache driver. Set a TTL (e.g., 1 hour) in the repository’s constructor: `new SettingsRepository(new CacheSettingsStore(app('cache.store'), 3600))`. Use Redis or Memcached for distributed caching. Always test cache invalidation logic—e.g., clear cache after `save()` if using manual updates.
- How do I handle multi-tenancy with tenant-specific settings?
- Override the default `SettingsRepository` to scope settings by tenant. Use middleware to inject the tenant ID into the repository or extend the `Settings` class to include a `tenant_id` field. Example: `class TenantSettings extends Settings { public string $tenant_id; }`. Ensure migrations include the tenant column and queries filter by it.
- Are there any security risks with database-backed settings?
- The package mitigates risks by validating updates via FormRequests and supporting encrypted fields. Avoid storing sensitive data (e.g., API keys) in plaintext—use Laravel’s `encrypt` cast or a dedicated secrets manager. For auditability, log changes via Laravel’s `Logging` facade or a package like `spatie/laravel-logging`.
- How do I test settings in Laravel’s testing environment?
- Use Laravel’s testing helpers. For database-backed settings, refresh the database before tests: `public function test_settings(): void { $this->refreshDatabase(); ... }`. Mock the repository for unit tests: `$this->mock(SettingsRepository::class)->shouldReceive('get')...`. Test migrations separately with `Artisan::call('migrate')` in a test case.
- What alternatives exist for Laravel settings management?
- Alternatives include `beberlei/attributes` for runtime configs, `laravel-env-config` for `.env`-driven settings, or `spatie/laravel-activitylog` for audit trails. For complex needs, consider `laravel-config` or `laravel-env-config` for environment-based settings. `spatie/laravel-settings` stands out for its type safety, repository pattern, and Laravel-native integration.
- How do I handle default values for nullable vs. required settings?
- Define defaults in your `Settings` class properties (e.g., `public ?string $optional_setting = null;`). For required fields, omit the default and validate in a FormRequest. Migrations should match the class structure—use `make:settings-migration` to auto-generate columns. Test edge cases like `NULL` values in production to ensure graceful fallbacks.