Skip to content

Commit

Permalink
Enums as setting keys (#37)
Browse files Browse the repository at this point in the history
  • Loading branch information
rawilk authored Oct 1, 2023
1 parent 90181dd commit 1b6c576
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 27 deletions.
24 changes: 12 additions & 12 deletions docs/api/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ public function context(Context $context = null): self
/**
* Remove a persisted setting from storage.
*
* @param string $key
* @param string|\BackedEnum $key
* @return void
*/
public function forget($key)
public function forget(string|BackedEnum $key)
```

### get
Expand All @@ -34,11 +34,11 @@ public function forget($key)
/**
* Retrieve a setting from storage.
*
* @param string $key
* @param string|\BackedEnum $key
* @param mixed $default
* @return mixed
*/
public function get(string $key, $default = null)
public function get(string|BackedEnum $key, $default = null)
```

### all
Expand All @@ -59,10 +59,10 @@ public function all($keys = null): \Illuminate\Support\Collection
/**
* Determine if a setting has been persisted to storage.
*
* @param string $key
* @param string|\BackedEnum $key
* @return bool
*/
public function has($key): bool
public function has(string|BackedEnum $key): bool
```

### set
Expand All @@ -86,11 +86,11 @@ public function set(string $key, $value = null)
* Determine if a setting is set to a false value.
* Returns true if the value is false, '0', or 0.
*
* @param string $key
* @param string|\BackedEnum $key
* @param bool|int|string $default
* @return bool
*/
public function isFalse(string $key, $default = false): bool
public function isFalse(string|BackedEnum $key, $default = false): bool
```

### isTrue
Expand All @@ -100,11 +100,11 @@ public function isFalse(string $key, $default = false): bool
* Determine if a setting is set to a truthy value.
* Returns true if the value is true, '1', or 1.
*
* @param string $key
* @param string|\BackedEnum $key
* @param bool|int|string $default
* @return bool
*/
public function isTrue(string $key, $default = true): bool
public function isTrue(string|BackedEnum $key, $default = true): bool
```

### flush
Expand All @@ -125,8 +125,8 @@ public function flush($keys = null): void
/**
* Get the correct cache key for a given setting.
*
* @param string $key
* @param string|\BackedEnum $key
* @return string
*/
public function cacheKeyForSetting(string $key): string
public function cacheKeyForSetting(string|BackedEnum $key): string
```
30 changes: 30 additions & 0 deletions docs/best-practices/enums.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
title: Enums
sort: 4
---

## Introduction

PHP 8.1 introduced native enums, which can be a great way to define setting keys to use with this package.
Using an enum instead of hard-coding your setting keys can be helpful for both keeping track of which
settings are available to the application and for consistency.
As of version `3.1.0` of the package, the settings service will support enums as setting keys in the `get()`,
`set()`, `forget()`, and `has()` methods, as well as `isTrue()`, `isFalse()`, and `cacheKeyForSetting()`.

To use an enum as a setting key, you must use a string backed enum, like the example below:

```php
namespace App\Enums;

enum SettingKey: string
{
case Timezone = 'app.timezone';
case DefaultRole = 'default-role';
}
```

Now, you can use that enum when interacting with settings:

```php
settings()->get(SettingKey::Timezone);
```
15 changes: 15 additions & 0 deletions src/Exceptions/InvalidEnumType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Rawilk\Settings\Exceptions;

use InvalidArgumentException;

final class InvalidEnumType extends InvalidArgumentException
{
public static function make(string $enumClass): self
{
return new self("Only string backed enums are supported. `{$enumClass}` is not a string backed enum.");
}
}
12 changes: 6 additions & 6 deletions src/Facades/Settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
* @see \Rawilk\Settings\Settings
*
* @method static \Rawilk\Settings\Settings context(null|\Rawilk\Settings\Support\Context $context = null)
* @method static null|mixed forget($key)
* @method static mixed get(string $key, null|mixed $default = null)
* @method static null|mixed forget(string|\BackedEnum $key)
* @method static mixed get(string|\BackedEnum $key, null|mixed $default = null)
* @method static \Illuminate\Support\Collection all($keys)
* @method static bool isFalse(string $key, bool|int|string $default = false)
* @method static bool isTrue(string $key, bool|int|string $default = true)
* @method static bool has($key)
* @method static null|mixed set(string $key, null|mixed $value = null)
* @method static bool isFalse(string|\BackedEnum $key, bool|int|string $default = false)
* @method static bool isTrue(string|\BackedEnum $key, bool|int|string $default = true)
* @method static bool has(string|\BackedEnum $key)
* @method static null|mixed set(string|\BackedEnum $key, null|mixed $value = null)
* @method static void flush($keys)
* @method static self disableCache()
* @method static self enableCache()
Expand Down
29 changes: 20 additions & 9 deletions src/Settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Rawilk\Settings;

use BackedEnum;
use Illuminate\Contracts\Cache\Repository as Cache;
use Illuminate\Contracts\Encryption\Encrypter;
use Illuminate\Database\Eloquent\Model;
Expand All @@ -17,6 +18,7 @@
use Rawilk\Settings\Events\SettingWasDeleted;
use Rawilk\Settings\Events\SettingWasStored;
use Rawilk\Settings\Exceptions\InvalidBulkValueResult;
use Rawilk\Settings\Exceptions\InvalidEnumType;
use Rawilk\Settings\Exceptions\InvalidKeyGenerator;
use Rawilk\Settings\Support\Context;
use Rawilk\Settings\Support\KeyGenerators\Md5KeyGenerator;
Expand Down Expand Up @@ -108,7 +110,7 @@ public function setTeamForeignKey(?string $foreignKey): self
return $this;
}

public function forget($key)
public function forget(string|BackedEnum $key)
{
$key = $this->normalizeKey($key);

Expand Down Expand Up @@ -141,7 +143,7 @@ public function forget($key)
return $driverResult;
}

public function get(string $key, $default = null)
public function get(string|BackedEnum $key, $default = null)
{
$key = $this->normalizeKey($key);

Expand Down Expand Up @@ -210,7 +212,7 @@ public function all($keys = null): Collection
return $values;
}

public function has($key): bool
public function has(string|BackedEnum $key): bool
{
$key = $this->normalizeKey($key);

Expand All @@ -229,7 +231,7 @@ public function has($key): bool
return $has;
}

public function set(string $key, $value = null): mixed
public function set(string|BackedEnum $key, $value = null): mixed
{
$key = $this->normalizeKey($key);

Expand Down Expand Up @@ -269,14 +271,14 @@ public function set(string $key, $value = null): mixed
return $driverResult;
}

public function isFalse(string $key, $default = false): bool
public function isFalse(string|BackedEnum $key, $default = false): bool
{
$value = $this->get(key: $key, default: $default);

return $value === false || $value === '0' || $value === 0;
}

public function isTrue(string $key, $default = true): bool
public function isTrue(string|BackedEnum $key, $default = true): bool
{
$value = $this->get(key: $key, default: $default);

Expand Down Expand Up @@ -400,7 +402,7 @@ public function getKeyGenerator(): KeyGenerator
* Generate the key to use for caching a specific setting.
* This is meant for external usage.
*/
public function cacheKeyForSetting(string $key): string
public function cacheKeyForSetting(string|BackedEnum $key): string
{
$storageKey = $this->getKeyForStorage(
$this->normalizeKey($key),
Expand All @@ -417,8 +419,17 @@ public function cacheKeyForSetting(string $key): string
return $cacheKey;
}

protected function normalizeKey(string $key): string
protected function normalizeKey(string|BackedEnum $key): string
{
if ($key instanceof BackedEnum) {
throw_unless(
is_string($key->value),
InvalidEnumType::make($key::class)
);

$key = $key->value;
}

if (Str::startsWith(haystack: $key, needles: 'file_')) {
return str_replace(search: 'file_', replace: 'file.', subject: $key);
}
Expand Down Expand Up @@ -542,6 +553,6 @@ protected function normalizeBulkLookupKey($key): string|Collection|bool
return collect($key)
->flatten()
->filter()
->map(fn (string $key): string => $this->getKeyForStorage($this->normalizeKey($key)));
->map(fn (string|BackedEnum $key): string => $this->getKeyForStorage($this->normalizeKey($key)));
}
}
18 changes: 18 additions & 0 deletions tests/Feature/SettingsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Rawilk\Settings\Events\SettingsFlushed;
use Rawilk\Settings\Events\SettingWasDeleted;
use Rawilk\Settings\Events\SettingWasStored;
use Rawilk\Settings\Exceptions\InvalidEnumType;
use Rawilk\Settings\Exceptions\InvalidKeyGenerator;
use Rawilk\Settings\Facades\Settings as SettingsFacade;
use Rawilk\Settings\Support\Context;
Expand All @@ -17,6 +18,8 @@
use Rawilk\Settings\Support\KeyGenerators\Md5KeyGenerator;
use Rawilk\Settings\Support\KeyGenerators\ReadableKeyGenerator;
use Rawilk\Settings\Support\ValueSerializers\JsonValueSerializer;
use Rawilk\Settings\Tests\Support\Enums\IntBackedEnum as InvalidEnumTypeEnum;
use Rawilk\Settings\Tests\Support\Enums\SettingKey;

beforeEach(function () {
config([
Expand Down Expand Up @@ -499,6 +502,21 @@
expect(SettingsFacade::cacheKeyForSetting('foo'))->toBe('settings.foo::team:1');
});

it('accepts a backed enum for a key instead of a string', function () {
SettingsFacade::set(SettingKey::Timezone, 'foo');

expect(SettingsFacade::get(SettingKey::Timezone))->toBe('foo')
->and(SettingsFacade::has(SettingKey::Timezone))->toBeTrue();

SettingsFacade::forget(SettingKey::Timezone);

expect(SettingsFacade::has(SettingKey::Timezone))->toBeFalse();
});

it('throws an exception when an int backed enum is used', function () {
SettingsFacade::get(InvalidEnumTypeEnum::Foo);
})->throws(InvalidEnumType::class);

// Helpers...

function assertQueryCount(int $expected): void
Expand Down
10 changes: 10 additions & 0 deletions tests/Support/Enums/IntBackedEnum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace Rawilk\Settings\Tests\Support\Enums;

enum IntBackedEnum: int
{
case Foo = 1;
}
10 changes: 10 additions & 0 deletions tests/Support/Enums/SettingKey.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace Rawilk\Settings\Tests\Support\Enums;

enum SettingKey: string
{
case Timezone = 'app.timezone';
}

0 comments on commit 1b6c576

Please sign in to comment.