mirror of
https://github.com/flarum/framework.git
synced 2025-01-28 03:35:49 +08:00
feat: Allow registering settings as Less
config vars through Settings Extender (#3011)
Co-authored-by: Alexander Skvortsov <38059171+askvortsov1@users.noreply.github.com>
This commit is contained in:
parent
62b92ba02e
commit
e8ffdead39
|
@ -21,6 +21,7 @@ class Settings implements ExtenderInterface
|
||||||
{
|
{
|
||||||
private $settings = [];
|
private $settings = [];
|
||||||
private $defaults = [];
|
private $defaults = [];
|
||||||
|
private $lessConfigs = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serialize a setting value to the ForumSerializer attributes.
|
* Serialize a setting value to the ForumSerializer attributes.
|
||||||
|
@ -61,6 +62,28 @@ class Settings implements ExtenderInterface
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a setting as a LESS configuration variable.
|
||||||
|
*
|
||||||
|
* @param string $configName: The name of the configuration variable, in hyphen case.
|
||||||
|
* @param string $key: The key of the setting.
|
||||||
|
* @param string|callable|null $callback: Optional callback to modify the value.
|
||||||
|
*
|
||||||
|
* The callback can be a closure or an invokable class, and should accept:
|
||||||
|
* - mixed $value: The value of the setting.
|
||||||
|
*
|
||||||
|
* The callable should return:
|
||||||
|
* - mixed $value: The modified value.
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function registerLessConfigVar(string $configName, string $key, $callback = null): self
|
||||||
|
{
|
||||||
|
$this->lessConfigs[$configName] = compact('key', 'callback');
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function extend(Container $container, Extension $extension = null)
|
public function extend(Container $container, Extension $extension = null)
|
||||||
{
|
{
|
||||||
if (! empty($this->defaults)) {
|
if (! empty($this->defaults)) {
|
||||||
|
@ -97,5 +120,19 @@ class Settings implements ExtenderInterface
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (! empty($this->lessConfigs)) {
|
||||||
|
$container->extend('flarum.less.config', function (array $existingConfig, Container $container) {
|
||||||
|
$config = $this->lessConfigs;
|
||||||
|
|
||||||
|
foreach ($config as $var => $data) {
|
||||||
|
if (isset($data['callback'])) {
|
||||||
|
$config[$var]['callback'] = ContainerUtil::wrapCallback($data['callback'], $container);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_merge($existingConfig, $config);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,7 +163,8 @@ class ForumServiceProvider extends AbstractServiceProvider
|
||||||
$validator = new ValidateCustomLess(
|
$validator = new ValidateCustomLess(
|
||||||
$container->make('flarum.assets.forum'),
|
$container->make('flarum.assets.forum'),
|
||||||
$container->make('flarum.locales'),
|
$container->make('flarum.locales'),
|
||||||
$container
|
$container,
|
||||||
|
$container->make('flarum.less.config')
|
||||||
);
|
);
|
||||||
$validator->whenSettingsSaved($event);
|
$validator->whenSettingsSaved($event);
|
||||||
}
|
}
|
||||||
|
@ -175,7 +176,8 @@ class ForumServiceProvider extends AbstractServiceProvider
|
||||||
$validator = new ValidateCustomLess(
|
$validator = new ValidateCustomLess(
|
||||||
$container->make('flarum.assets.forum'),
|
$container->make('flarum.assets.forum'),
|
||||||
$container->make('flarum.locales'),
|
$container->make('flarum.locales'),
|
||||||
$container
|
$container,
|
||||||
|
$container->make('flarum.less.config')
|
||||||
);
|
);
|
||||||
$validator->whenSettingsSaving($event);
|
$validator->whenSettingsSaving($event);
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,20 +43,21 @@ class ValidateCustomLess
|
||||||
protected $container;
|
protected $container;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Assets $assets
|
* @var array
|
||||||
* @param LocaleManager $locales
|
|
||||||
* @param Container $container
|
|
||||||
*/
|
*/
|
||||||
public function __construct(Assets $assets, LocaleManager $locales, Container $container)
|
protected $customLessSettings;
|
||||||
|
|
||||||
|
public function __construct(Assets $assets, LocaleManager $locales, Container $container, array $customLessSettings = [])
|
||||||
{
|
{
|
||||||
$this->assets = $assets;
|
$this->assets = $assets;
|
||||||
$this->locales = $locales;
|
$this->locales = $locales;
|
||||||
$this->container = $container;
|
$this->container = $container;
|
||||||
|
$this->customLessSettings = $customLessSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function whenSettingsSaving(Saving $event)
|
public function whenSettingsSaving(Saving $event)
|
||||||
{
|
{
|
||||||
if (! isset($event->settings['custom_less'])) {
|
if (! isset($event->settings['custom_less']) && ! $this->hasDirtyCustomLessSettings($event)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +96,7 @@ class ValidateCustomLess
|
||||||
|
|
||||||
public function whenSettingsSaved(Saved $event)
|
public function whenSettingsSaved(Saved $event)
|
||||||
{
|
{
|
||||||
if (! isset($event->settings['custom_less'])) {
|
if (! isset($event->settings['custom_less']) && ! $this->hasDirtyCustomLessSettings($event)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,4 +106,24 @@ class ValidateCustomLess
|
||||||
$this->assets->makeLocaleCss($locale)->flush();
|
$this->assets->makeLocaleCss($locale)->flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Saved|Saving $event
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function hasDirtyCustomLessSettings($event): bool
|
||||||
|
{
|
||||||
|
if (empty($this->customLessSettings)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$dirtySettings = array_intersect(
|
||||||
|
array_keys($event->settings),
|
||||||
|
array_map(function ($setting) {
|
||||||
|
return $setting['key'];
|
||||||
|
}, $this->customLessSettings)
|
||||||
|
);
|
||||||
|
|
||||||
|
return ! empty($dirtySettings);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,6 +106,29 @@ class FrontendServiceProvider extends AbstractServiceProvider
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$this->container->singleton('flarum.less.config', function (Container $container) {
|
||||||
|
return [
|
||||||
|
'config-primary-color' => [
|
||||||
|
'key' => 'theme_primary_color',
|
||||||
|
],
|
||||||
|
'config-secondary-color' => [
|
||||||
|
'key' => 'theme_secondary_color',
|
||||||
|
],
|
||||||
|
'config-dark-mode' => [
|
||||||
|
'key' => 'theme_dark_mode',
|
||||||
|
'callback' => function ($value) {
|
||||||
|
return $value ? 'true' : 'false';
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'config-colored-header' => [
|
||||||
|
'key' => 'theme_colored_header',
|
||||||
|
'callback' => function ($value) {
|
||||||
|
return $value ? 'true' : 'false';
|
||||||
|
},
|
||||||
|
],
|
||||||
|
];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -132,17 +155,18 @@ class FrontendServiceProvider extends AbstractServiceProvider
|
||||||
private function addLessVariables(SourceCollector $sources)
|
private function addLessVariables(SourceCollector $sources)
|
||||||
{
|
{
|
||||||
$sources->addString(function () {
|
$sources->addString(function () {
|
||||||
|
$vars = $this->container->make('flarum.less.config');
|
||||||
$settings = $this->container->make(SettingsRepositoryInterface::class);
|
$settings = $this->container->make(SettingsRepositoryInterface::class);
|
||||||
|
|
||||||
$vars = [
|
return array_reduce(array_keys($vars), function ($string, $name) use ($vars, $settings) {
|
||||||
'config-primary-color' => $settings->get('theme_primary_color', '#000'),
|
$var = $vars[$name];
|
||||||
'config-secondary-color' => $settings->get('theme_secondary_color', '#000'),
|
$value = $settings->get($var['key'], $var['default'] ?? null);
|
||||||
'config-dark-mode' => $settings->get('theme_dark_mode') ? 'true' : 'false',
|
|
||||||
'config-colored-header' => $settings->get('theme_colored_header') ? 'true' : 'false'
|
|
||||||
];
|
|
||||||
|
|
||||||
return array_reduce(array_keys($vars), function ($string, $name) use ($vars) {
|
if (isset($var['callback'])) {
|
||||||
return $string."@$name: {$vars[$name]};";
|
$value = $var['callback']($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $string."@$name: {$value};";
|
||||||
}, '');
|
}, '');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ class RecompileFrontendAssets
|
||||||
|
|
||||||
public function whenSettingsSaved(Saved $event)
|
public function whenSettingsSaved(Saved $event)
|
||||||
{
|
{
|
||||||
|
// @deprecated 'theme_' check, to be removed in 2.0
|
||||||
if (preg_grep('/^theme_/i', array_keys($event->settings))) {
|
if (preg_grep('/^theme_/i', array_keys($event->settings))) {
|
||||||
$this->flushCss();
|
$this->flushCss();
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,10 @@ class SettingsServiceProvider extends AbstractServiceProvider
|
||||||
public function register()
|
public function register()
|
||||||
{
|
{
|
||||||
$this->container->singleton('flarum.settings.default', function () {
|
$this->container->singleton('flarum.settings.default', function () {
|
||||||
return new Collection();
|
return new Collection([
|
||||||
|
'theme_primary_color' => '#4D698E',
|
||||||
|
'theme_secondary_color' => '#4D698E',
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->container->singleton(SettingsRepositoryInterface::class, function (Container $container) {
|
$this->container->singleton(SettingsRepositoryInterface::class, function (Container $container) {
|
||||||
|
|
3
framework/core/tests/fixtures/less/config.less
vendored
Normal file
3
framework/core/tests/fixtures/less/config.less
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
body {
|
||||||
|
--custom-config-setting: @custom-config-setting;
|
||||||
|
}
|
|
@ -220,6 +220,61 @@ class SettingsTest extends TestCase
|
||||||
|
|
||||||
$this->assertEquals(null, $value);
|
$this->assertEquals(null, $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function custom_less_var_does_not_work_by_default()
|
||||||
|
{
|
||||||
|
$this->extend(
|
||||||
|
(new Extend\Frontend('forum'))
|
||||||
|
->css(__DIR__.'/../../fixtures/less/config.less'),
|
||||||
|
);
|
||||||
|
|
||||||
|
$response = $this->send($this->request('GET', '/'));
|
||||||
|
|
||||||
|
$this->assertEquals(500, $response->getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function custom_less_var_works_if_registered()
|
||||||
|
{
|
||||||
|
$this->extend(
|
||||||
|
(new Extend\Frontend('forum'))
|
||||||
|
->css(__DIR__.'/../../fixtures/less/config.less'),
|
||||||
|
(new Extend\Settings())
|
||||||
|
->registerLessConfigVar('custom-config-setting', 'custom-prefix.custom_setting')
|
||||||
|
);
|
||||||
|
|
||||||
|
$response = $this->send($this->request('GET', '/'));
|
||||||
|
|
||||||
|
$cssFilePath = $this->app()->getContainer()->make('filesystem')->disk('flarum-assets')->path('forum.css');
|
||||||
|
$this->assertStringContainsString('--custom-config-setting:customValue', file_get_contents($cssFilePath));
|
||||||
|
|
||||||
|
$this->assertEquals(200, $response->getStatusCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function cant_save_setting_if_invalid_less_var()
|
||||||
|
{
|
||||||
|
$this->extend(
|
||||||
|
(new Extend\Settings())
|
||||||
|
->registerLessConfigVar('custom-config-setting2', 'custom-prefix.custom_setting2')
|
||||||
|
);
|
||||||
|
|
||||||
|
$response = $this->send($this->request('POST', '/api/settings', [
|
||||||
|
'authenticatedAs' => 1,
|
||||||
|
'json' => [
|
||||||
|
'custom-prefix.custom_setting2' => '@muralf'
|
||||||
|
],
|
||||||
|
]));
|
||||||
|
|
||||||
|
$this->assertEquals(422, $response->getStatusCode());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CustomInvokableClass
|
class CustomInvokableClass
|
||||||
|
|
Loading…
Reference in New Issue
Block a user