diff --git a/src/Database/Migration.php b/src/Database/Migration.php index 410e05671e..1fb0bcb2f8 100644 --- a/src/Database/Migration.php +++ b/src/Database/Migration.php @@ -9,6 +9,7 @@ namespace Flarum\Database; +use Flarum\Extend\Settings; use Flarum\Settings\DatabaseSettingsRepository; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Builder; @@ -120,6 +121,9 @@ public static function renameColumns($tableName, array $columnNames) /** * Add default values for config values. + * + * @deprecated Use the Settings extender's `default` method instead to register settings. + * @see Settings::default() */ public static function addSettings(array $defaults) { diff --git a/src/Extend/Settings.php b/src/Extend/Settings.php index e100e94b0a..24e1689a1a 100644 --- a/src/Extend/Settings.php +++ b/src/Extend/Settings.php @@ -15,10 +15,12 @@ use Flarum\Foundation\ContainerUtil; use Flarum\Settings\SettingsRepositoryInterface; use Illuminate\Contracts\Container\Container; +use Illuminate\Support\Collection; class Settings implements ExtenderInterface { private $settings = []; + private $defaults = []; /** * Serialize a setting value to the ForumSerializer attributes. @@ -33,7 +35,8 @@ class Settings implements ExtenderInterface * The callable should return: * - mixed $value: The modified value. * - * @param mixed $default: Optional default serialized value. Will be run through the optional callback. + * @todo remove $default in 2.0 + * @param mixed $default: Deprecated optional default serialized value. Will be run through the optional callback. * @return self */ public function serializeToForum(string $attributeName, string $key, $callback = null, $default = null): self @@ -43,8 +46,35 @@ public function serializeToForum(string $attributeName, string $key, $callback = return $this; } + /** + * Set a default value for a setting. + * Replaces inserting the default value with a migration. + * + * @param string $key: The setting key, must be unique. Namespace it with the extension ID (example: 'my-extension-id.setting_key'). + * @param mixed $value: The setting value. + * @return self + */ + public function default(string $key, $value): self + { + $this->defaults[$key] = $value; + + return $this; + } + public function extend(Container $container, Extension $extension = null) { + if (! empty($this->defaults)) { + $container->extend('flarum.settings.default', function (Collection $defaults) { + foreach ($this->defaults as $key => $value) { + if ($defaults->has($key)) { + throw new \RuntimeException("Cannot modify immutable default setting $key."); + } + + $defaults->put($key, $value); + } + }); + } + if (! empty($this->settings)) { AbstractSerializer::addAttributeMutator( ForumSerializer::class, diff --git a/src/Settings/DefaultSettingsRepository.php b/src/Settings/DefaultSettingsRepository.php new file mode 100644 index 0000000000..ad5300cf01 --- /dev/null +++ b/src/Settings/DefaultSettingsRepository.php @@ -0,0 +1,47 @@ +inner = $inner; + $this->defaults = $defaults; + } + + public function get($key, $default = null) + { + // Global default overrules local default because local default is deprecated, + // and will be removed in 2.0 + return $this->inner->get($key, $this->defaults->get($key, $default)); + } + + public function set($key, $value) + { + $this->inner->set($key, $value); + } + + public function delete($keyLike) + { + $this->inner->delete($keyLike); + } + + public function all(): array + { + return array_merge($this->defaults->toArray(), $this->inner->all()); + } +} diff --git a/src/Settings/SettingsRepositoryInterface.php b/src/Settings/SettingsRepositoryInterface.php index 8bb3d7ab2b..b96a95cdeb 100644 --- a/src/Settings/SettingsRepositoryInterface.php +++ b/src/Settings/SettingsRepositoryInterface.php @@ -13,6 +13,13 @@ interface SettingsRepositoryInterface { public function all(): array; + /** + * @todo remove $default in 2.0 + * + * @param $key + * @param mixed $default: Deprecated + * @return mixed + */ public function get($key, $default = null); public function set($key, $value); diff --git a/src/Settings/SettingsServiceProvider.php b/src/Settings/SettingsServiceProvider.php index 4bfb8f466a..bb2090b037 100644 --- a/src/Settings/SettingsServiceProvider.php +++ b/src/Settings/SettingsServiceProvider.php @@ -12,6 +12,7 @@ use Flarum\Foundation\AbstractServiceProvider; use Illuminate\Contracts\Container\Container; use Illuminate\Database\ConnectionInterface; +use Illuminate\Support\Collection; class SettingsServiceProvider extends AbstractServiceProvider { @@ -20,11 +21,18 @@ class SettingsServiceProvider extends AbstractServiceProvider */ public function register() { + $this->container->singleton('flarum.settings.default', function () { + return new Collection(); + }); + $this->container->singleton(SettingsRepositoryInterface::class, function (Container $container) { - return new MemoryCacheSettingsRepository( - new DatabaseSettingsRepository( - $container->make(ConnectionInterface::class) - ) + return new DefaultSettingsRepository( + new MemoryCacheSettingsRepository( + new DatabaseSettingsRepository( + $container->make(ConnectionInterface::class) + ) + ), + $container->make('flarum.settings.default') ); }); diff --git a/tests/integration/extenders/SettingsTest.php b/tests/integration/extenders/SettingsTest.php index 437707f9f4..454fd370f6 100644 --- a/tests/integration/extenders/SettingsTest.php +++ b/tests/integration/extenders/SettingsTest.php @@ -163,6 +163,63 @@ public function custom_setting_default_passed_to_callback() $this->assertArrayHasKey('customPrefix.noCustomSetting', $payload['data']['attributes']); $this->assertEquals('customDefaultModified2', $payload['data']['attributes']['customPrefix.noCustomSetting']); } + + /** + * @test + */ + public function custom_setting_default_prioritizes_extender() + { + $this->extend( + (new Extend\Settings()) + ->serializeToForum('customPrefix.unavailableCustomSetting3', 'custom-prefix.unavailable_custom_setting3') + ->default('custom-prefix.unavailable_custom_setting3', 'extenderDefault') + ); + + $value = $this->app() + ->getContainer() + ->make('flarum.settings') + ->get('custom-prefix.unavailable_custom_setting3', 'defaultParameterValue'); + + $this->assertEquals('extenderDefault', $value); + } + + /** + * @test + */ + public function custom_setting_default_falls_back_to_parameter() + { + $this->extend( + (new Extend\Settings()) + ->serializeToForum('customPrefix.unavailableCustomSetting4', 'custom-prefix.unavailable_custom_setting4') + ); + + $value = $this->app() + ->getContainer() + ->make('flarum.settings') + ->get('custom-prefix.unavailable_custom_setting4', 'defaultParameterValue'); + + $this->assertEquals('defaultParameterValue', $value); + } + + /** + * @test + */ + public function null_custom_setting_returns_null() + { + $this->setting('custom-prefix.custom_null_setting', null); + + $this->extend( + (new Extend\Settings()) + ->default('custom-prefix.custom_null_setting', 'extenderDefault') + ); + + $value = $this->app() + ->getContainer() + ->make('flarum.settings') + ->get('custom-prefix.custom_null_setting'); + + $this->assertEquals(null, $value); + } } class CustomInvokableClass