stillat/proteus
Utilities for parsing, updating, and writing Laravel-style PHP config files. Use the ConfigWriter facade to write or preview single or multiple keys, guard namespaces from mutation, and optionally rewrite function calls like env while preserving structure.
## Getting Started
### Minimal Setup
1. **Installation**
```bash
composer require stillat/proteus
No service provider or facade needed—use the Proteus class directly.
First Use Case: Reading Config
use Stillat\Proteus\Proteus;
$config = Proteus::read(config_path('app.php'));
// Returns an array of the parsed config
Where to Look First
src/Proteus.php for core logic.config() helper and config.php structure.Proteus.$appConfig = Proteus::read(config_path('app.php'));
$customConfig = Proteus::read(base_path('config/custom.php'));
require or include.require config_path('app.php'); in custom config loaders.Proteus’ expectations (e.g., return []; format).$config = Proteus::read(config_path('app.php'));
$config['debug'] = env('APP_DEBUG', false);
Proteus::write(config_path('app.php'), $config);
Proteus::validate() (if extended).config() caching system, clear the cache post-write:
Proteus::write($path, $config);
config()->clear();
$base = Proteus::read(config_path('app.php'));
$override = Proteus::read(config_path('app-override.php'));
$merged = array_replace_recursive($base, $override); // Prefer array_replace_recursive for deeper overrides
Proteus::write(config_path('app.php'), $merged);
config() merging for consistency.// In a custom Artisan command
public function handle() {
$config = Proteus::read(config_path('app.php'));
$config['timezone'] = 'America/New_York';
Proteus::write(config_path('app.php'), $config);
$this->info('Config updated!');
}
Artisan::command() syntax if creating custom commands.$env = app()->environment();
$configPath = config_path("app-{$env}.php");
if (file_exists($configPath)) {
$config = Proteus::read($configPath);
} else {
$config = Proteus::read(config_path('app.php'));
}
app-local.php, app-production.php)..env system remains unchanged, so this pattern is still valid.Proteus for non-standard config files (e.g., third-party or dynamic configs).Proteus::write($path, $config);
config()->clear(); // Laravel 13+ method
config/package-name.php:
$defaults = Proteus::read(__DIR__.'/config.php');
$userConfig = config_path('package-name.php');
if (file_exists($userConfig)) {
$defaults = array_replace_recursive($defaults, Proteus::read($userConfig));
}
$testConfig = Proteus::read(base_path("tests/config/test.php"));
Testing facade for cleaner test setups:
use Laravel\Lumen\Testing\TestCase;
public function testConfig() {
$this->app->instance('config', ['test' => true]);
}
File Permissions
storage/ or config/ has 755 permissions or use storage_path('app/config-custom.php').Syntax Errors
Proteus::read() throws exceptions on invalid PHP syntax (unlike Laravel’s require).Proteus::validate($config) (if implemented) or wrap in a try-catch.Recursive Merging Quirks
array_merge_recursive may not behave as expected with nested arrays.array_replace_recursive for deeper overrides:
$merged = array_replace_recursive($base, $override);
Caching Interactions
config()->clear() (Laravel 13+) or use Artisan::call('config:clear').Non-Standard Config Files
Proteus assumes PHP files with return []; structure.Proteus for custom formats.Laravel 13 Breaking Changes
Proteus writes are followed by config()->clear().Proteus in service providers, ensure compatibility with Laravel 13’s container changes.Inspect Raw Config
$raw = file_get_contents(config_path('app.php'));
var_dump($raw); // Check for syntax issues
Validate Before Writing
$config = Proteus::read($path);
if (isset($config['invalid_key'])) {
throw new \RuntimeException('Invalid config detected!');
}
Log Changes
$old = Proteus::read($path);
Proteus::write($path, $new);
\Log::info('Config updated', ['old' => $old, 'new' => $new]);
Laravel 13 Debugging
php artisan config:cache to test caching behavior.tail -f storage/logs/laravel.log
Custom Parsers
Proteus to support non-PHP config files (e.g., JSON, YAML):
class JsonProteus extends Proteus {
public static function read(string $path) {
return json_decode(file_get_contents($path), true);
}
}
Validation Rules
use Stillat\Proteus\Contracts\Validatable;
class ValidatedProteus implements Validatable {
public function validate(array $config): bool {
return isset($config['required_key']);
}
}
Event Dispatching
How can I help you explore Laravel packages today?