From 21ac4621c3230f9868bf6c6dc98f6e6b700ad596 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=2E=20Nagy=20Gerg=C5=91?= <hello@iamgergo.com> Date: Sun, 13 Oct 2024 15:53:53 +0200 Subject: [PATCH] settings --- database/factories/SettingFactory.php | 3 +- routes/web.php | 5 -- src/Interfaces/Settings/Registry.php | 5 +- src/Interfaces/Settings/Repository.php | 57 ++++++++++++++++++++- src/Models/Setting.php | 10 ++-- src/Settings/Registry.php | 8 +++ src/Settings/Repository.php | 33 +++++++++--- tests/Settings/SettingsTest.php | 70 ++++++++++++++++++++++++++ 8 files changed, 171 insertions(+), 20 deletions(-) create mode 100644 tests/Settings/SettingsTest.php diff --git a/database/factories/SettingFactory.php b/database/factories/SettingFactory.php index 2f60e75f..69db050a 100644 --- a/database/factories/SettingFactory.php +++ b/database/factories/SettingFactory.php @@ -20,7 +20,8 @@ class SettingFactory extends Factory public function definition(): array { return [ - // + 'key' => $this->faker->slug(1), + 'value' => mt_rand(10, 1000), ]; } } diff --git a/routes/web.php b/routes/web.php index 53c9c9ce..9c884374 100644 --- a/routes/web.php +++ b/routes/web.php @@ -3,7 +3,6 @@ use Cone\Root\Http\Controllers\DashboardController; use Cone\Root\Http\Controllers\DownloadController; use Cone\Root\Http\Controllers\ResourceController; -use Cone\Root\Http\Controllers\SettingController; use Illuminate\Support\Facades\Route; // Dashboard @@ -12,10 +11,6 @@ // Download Route::get('/download/{medium:uuid}', DownloadController::class)->name('download'); -// Settings -Route::get('/settings/{group}', [SettingController::class, 'show'])->name('settings.show'); -Route::patch('/settings/{group}', [SettingController::class, 'update'])->name('settings.update'); - // Resource Route::get('/{resource}', [ResourceController::class, 'index'])->name('resource.index'); Route::get('/{resource}/create', [ResourceController::class, 'create'])->name('resource.create'); diff --git a/src/Interfaces/Settings/Registry.php b/src/Interfaces/Settings/Registry.php index 33b3ab10..ac10d0fc 100644 --- a/src/Interfaces/Settings/Registry.php +++ b/src/Interfaces/Settings/Registry.php @@ -4,5 +4,8 @@ interface Registry { - // + /** + * Get the repository instance. + */ + public function getRepository(): Repository; } diff --git a/src/Interfaces/Settings/Repository.php b/src/Interfaces/Settings/Repository.php index 2ece89dd..f616d6e3 100644 --- a/src/Interfaces/Settings/Repository.php +++ b/src/Interfaces/Settings/Repository.php @@ -2,7 +2,62 @@ namespace Cone\Root\Interfaces\Settings; +use Cone\Root\Models\Setting; + interface Repository { - // + /** + * Get the setting model. + */ + public function model(): Setting; + + /** + * Set the value cast. + */ + public function cast(string $key, string $type): void; + + /** + * Merge the casts. + */ + public function mergeCasts(array $casts): void; + + /** + * Remove the given casts. + */ + public function removeCasts(string|array $keys): void; + + /** + * Remove the given casts. + */ + public function clearCasts(): void; + + /** + * Get the value casts. + */ + public function getCasts(): array; + + /** + * Get the value for the given key. + */ + public function get(string $key, mixed $default = null, bool $fresh = false): mixed; + + /** + * Set the value for the given key. + */ + public function set(string $key, mixed $value): mixed; + + /** + * Delete the given keys. + */ + public function delete(string|array $keys): void; + + /** + * Flush the cache. + */ + public function flush(): void; + + /** + * Get all the settings. + */ + public function all(): array; } diff --git a/src/Models/Setting.php b/src/Models/Setting.php index d6cd7fc5..9d852f5f 100644 --- a/src/Models/Setting.php +++ b/src/Models/Setting.php @@ -49,12 +49,14 @@ protected static function newFactory(): SettingFactory /** * Cast the value attribute to the given type. */ - public function castValue(?string $type = null): void + public function castValue(?string $type = null): static { - if (is_null($type)) { - unset($this->casts['value']); - } else { + if (! is_null($type)) { $this->casts['value'] = $type; + } else { + unset($this->casts['value']); } + + return $this; } } diff --git a/src/Settings/Registry.php b/src/Settings/Registry.php index 63600bd6..39db241a 100644 --- a/src/Settings/Registry.php +++ b/src/Settings/Registry.php @@ -20,6 +20,14 @@ public function __construct(Repository $repository) $this->repository = $repository; } + /** + * Get the repository instance. + */ + public function getRepository(): Repository + { + return $this->repository; + } + /** * Dynamically call the given method. */ diff --git a/src/Settings/Repository.php b/src/Settings/Repository.php index fea0572f..018011b8 100644 --- a/src/Settings/Repository.php +++ b/src/Settings/Repository.php @@ -6,6 +6,7 @@ use Cone\Root\Interfaces\Settings\Repository as Contract; use Cone\Root\Models\Setting; use Illuminate\Contracts\Support\Arrayable; +use Illuminate\Database\Eloquent\Builder; class Repository implements Arrayable, ArrayAccess, Contract { @@ -27,6 +28,14 @@ public function model(): Setting return Setting::proxy(); } + /** + * Get the base query for the repository. + */ + public function query(): Builder + { + return $this->model()->newQuery(); + } + /** * Set the value cast. */ @@ -78,15 +87,23 @@ public function get(string $key, mixed $default = null, bool $fresh = false): mi return $this->offsetGet($key); } - $model = $this->model()->newQuery()->firstWhere('key', '=', $key); + return $this->refresh($key, $default); + } - if (! is_null($model)) { - $model->castValue($this->casts[$key] ?? null); + /** + * Refresh the given key. + */ + public function refresh(string $key, mixed $default = null): mixed + { + $model = $this->query()->firstWhere('key', '=', $key); - $this->offsetSet($key, $model->value); - } + $value = is_null($model) + ? $default + : $model->castValue($this->casts[$key] ?? null)->value; + + $this->offsetSet($key, $value); - return $this->cache[$key] ?? $default; + return $value; } /** @@ -94,7 +111,7 @@ public function get(string $key, mixed $default = null, bool $fresh = false): mi */ public function set(string $key, mixed $value): mixed { - $model = $this->model()->newQuery()->firstOrNew(['key' => $key]); + $model = $this->query()->firstOrNew(['key' => $key]); $model->castValue($this->casts[$key] ?? null); @@ -116,7 +133,7 @@ public function delete(string|array $keys): void $this->offsetUnset($key); } - $this->model()->newQuery()->whereIn('key', (array) $keys)->delete(); + $this->query()->whereIn('key', (array) $keys)->delete(); } /** diff --git a/tests/Settings/SettingsTest.php b/tests/Settings/SettingsTest.php new file mode 100644 index 00000000..03f03673 --- /dev/null +++ b/tests/Settings/SettingsTest.php @@ -0,0 +1,70 @@ +<?php + +namespace Cone\Root\Tests\Settings; + +use Cone\Root\Settings\Registry; +use Cone\Root\Settings\Repository; +use Cone\Root\Tests\TestCase; +use Illuminate\Support\Facades\Date; + +class SettingsTest extends TestCase +{ + protected Registry $registry; + + public function setUp(): void + { + parent::setUp(); + + $this->registry = new Registry(new Repository); + } + + public function test_setting_can_be_set(): void + { + $value = $this->registry->set('foo', 'bar'); + $this->assertSame('bar', $value); + + $this->assertDatabaseHas('root_settings', ['key' => 'foo', 'value' => 'bar']); + } + + public function test_setting_value_with_cast(): void + { + $this->registry->cast('ran_at', 'datetime'); + + $value = $this->registry->get('ran_at'); + $this->assertNull($value); + + $value = $this->registry->set('ran_at', $now = Date::now()); + $this->assertSame( + $now->__toString(), + $this->registry->query()->firstWhere('key', 'ran_at')->value + ); + + $this->assertSame( + $now->__toString(), + $this->registry->get('ran_at')->__toString() + ); + } + + public function test_setting_can_be_get(): void + { + $value = $this->registry->get('foo'); + $this->assertNull($value); + + $value = $this->registry->get('foo', 'bar'); + $this->assertSame('bar', $value); + } + + public function test_setting_can_be_deleted(): void + { + $value = $this->registry->set('foo', 'bar'); + $this->assertSame('bar', $value); + + $value = $this->registry->get('foo'); + $this->assertSame('bar', $value); + + $this->registry->delete('foo'); + $this->assertNull($this->registry->get('foo')); + + $this->assertDatabaseMissing('root_settings', ['key' => 'foo']); + } +}