Installation
composer require damian972/options-bundle
php artisan vendor:publish --provider="Damian972\OptionsBundle\OptionsBundle" --tag="config"
options.yaml config file to config/packages/options.yaml.Database Migration
Run the bundle’s migration to create the options table:
php artisan migrate
vendor/damian972/options-bundle/src/Resources/migrations/.First Use Case
Inject the OptionsInterface into a controller/service and use it to store/retrieve values:
use Damian972\OptionsBundle\Contracts\OptionsInterface;
public function index(OptionsInterface $options) {
$options->set(Option::make('site_name', 'MyApp'));
$name = $options->get('site_name')?->getValue() ?? 'Default';
return response()->json(['name' => $name]);
}
Storing Options
Option::make(key, value, parent) for basic storage.setName(), setDescription()).$options->set(Option::make('theme', 'dark')->setName('UI Theme'));
Retrieving Options
options.cache_all: false).options.cache_all: true).$globalTheme = $options->get('theme', 'global');
Conditional Logic
$timeout = $options->get('api_timeout')?->getValue() ?? 30;
Bulk Operations
Option::make() in loops or factories to batch-insert options.OptionsInterface implementations for testing:
$this->app->bind(OptionsInterface::class, function () {
return new MockOptionsService();
});
OptionStored/OptionUpdated events (if supported).$value = Cache::remember("option_{$key}", now()->addHours(1), function () use ($options, $key) {
return $options->get($key)?->getValue();
});
Database Locking
DB::transaction(function () use ($options) {
$options->set(Option::make('critical_setting', 'value'));
});
Parent Key Ambiguity
$options->get('key')) returns the first match. Always specify parents explicitly if multiple exist:
// Avoid ambiguity
$options->get('key', 'parent_scope');
Lazy Loading Overhead
cache_all (default) triggers a query per get(). Enable cache_all in options.yaml for read-heavy apps:
options:
cache_all: true
Migration Conflicts
options table already exists, the bundle’s migration may fail. Manually check the schema or disable migrations in config/packages/options.yaml:
options:
run_migrations: false
options table exists and contains data:
php artisan tinker
>> \DB::table('options')->get();
OptionsInterface is properly bound in the container. Check for typos in the service ID.Custom Option Classes
Extend Option to add metadata (e.g., EncryptedOption):
class EncryptedOption extends Option {
public function getValue() {
return decrypt(parent::getValue());
}
}
Query Scoping Override the repository to filter options by scope (e.g., tenant ID):
$options->get('key', 'tenant_123'); // Custom logic in repository
Validation
Add validation rules to Option via a trait or decorator:
Option::make('email', 'test@example.com')->validate(fn ($value) => filter_var($value, FILTER_VALIDATE_EMAIL));
How can I help you explore Laravel packages today?