Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Custom Caster Feature #35

Merged
merged 10 commits into from
May 2, 2024
Merged
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,17 @@ delete_config('key');
read_nested('foo.bar');
```

### Custom Casters
You can also custom casters:

```php
$config = factory(Config::class)->create([
'name' => 'custom-cast-config-name',
'val' => [ConfigDataType::DATE],
'type' => AsEnumCollection::class.':'.ConfigDataType::class,
]);
```

### Testing

``` bash
Expand Down
69 changes: 60 additions & 9 deletions src/Casts/ConfigValueCast.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,77 @@
namespace TarfinLabs\LaravelConfig\Casts;

use Carbon\Carbon;
use Illuminate\Contracts\Database\Eloquent\Castable;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Contracts\Database\Eloquent\CastsInboundAttributes;
use Illuminate\Database\Eloquent\Model;
use TarfinLabs\LaravelConfig\Enums\ConfigDataType;

class ConfigValueCast implements CastsAttributes
{
public function get(Model $model, string $key, mixed $value, array $attributes)
{
return match ($attributes['type']) {
ConfigDataType::BOOLEAN->value => (bool) $value,
ConfigDataType::INTEGER->value => (int) $value,
ConfigDataType::DATE->value => Carbon::createFromFormat('Y-m-d', $value),
ConfigDataType::DATE_TIME->value => Carbon::createFromFormat('Y-m-d H:i', $value),
ConfigDataType::JSON->value => json_decode($value, true),
default => $value,
};
switch ($attributes['type']) {
case ConfigDataType::BOOLEAN->value:
return (bool) $value;
case ConfigDataType::INTEGER->value:
return (int) $value;
case ConfigDataType::DATE->value:
return Carbon::createFromFormat('Y-m-d', $value);
case ConfigDataType::DATE_TIME->value:
return Carbon::createFromFormat('Y-m-d H:i', $value);
case ConfigDataType::JSON->value:
return json_decode($value, true);
default:
$parts = explode(':', $attributes['type']);
$casterClass = array_shift($parts);
if (class_exists($casterClass)) {
$caster = match (true) {
is_subclass_of($casterClass, CastsAttributes::class), is_subclass_of($casterClass, CastsInboundAttributes::class) => new $casterClass(...$parts),
is_subclass_of($casterClass, Castable::class) => $casterClass::castUsing($parts),
default => null
};

if ($caster !== null) {
return $caster->get(model: $model, key: $key, value: $value, attributes: $attributes);
}
}

return $value;
}
}

public function set(Model $model, string $key, mixed $value, array $attributes)
{
return $value;
$type = $attributes['type']?->value ?? $attributes['type'] ?? null;

switch ($type) {
case ConfigDataType::DATE->value:
return Carbon::parse($value)->format('Y-m-d');
case ConfigDataType::DATE_TIME->value:
return Carbon::parse($value)->format('Y-m-d H:i');
case ConfigDataType::JSON->value:
return match (true) {
is_string($value) => $value,
default => json_encode($value)
};
default:
$parts = explode(':', $type);
$casterClass = array_shift($parts);

if (class_exists($casterClass)) {
$caster = match (true) {
is_subclass_of($casterClass, CastsAttributes::class), is_subclass_of($casterClass, CastsInboundAttributes::class) => new $casterClass(...$parts),
is_subclass_of($casterClass, Castable::class) => $casterClass::castUsing($parts),
default => null
};

if ($caster !== null) {
return $caster->set(model: $model, key: $key, value: $value, attributes: $parts);
}
}

return $value;
}
}
}
2 changes: 1 addition & 1 deletion src/LaravelConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,8 @@ public function delete(Config $config): int
private function fillColumns(Config $config, ConfigItem $configItem): Config
{
$config->name = $configItem->name;
$config->val = $configItem->val;
$config->type = $configItem->type;
$config->val = $configItem->val;
$config->description = $configItem->description;
$config->tags = $configItem->tags;

Expand Down
62 changes: 49 additions & 13 deletions tests/LaravelConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
namespace TarfinLabs\LaravelConfig\Tests;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Casts\AsCollection;
use Illuminate\Database\Eloquent\Casts\AsEnumCollection;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use TarfinLabs\LaravelConfig\Config\Config;
use TarfinLabs\LaravelConfig\Config\ConfigFactory;
Expand All @@ -26,10 +29,10 @@ public function it_create_a_new_config_parameter(): void
{
$factory = new ConfigFactory();
$configItem = $factory->setName(Str::random(5))
->setType(ConfigDataType::BOOLEAN)
->setValue('1')
->setDescription(Str::random(50))
->get();
->setType(ConfigDataType::BOOLEAN)
->setValue('1')
->setDescription(Str::random(50))
->get();

$this->laravelConfig->create($configItem);

Expand Down Expand Up @@ -72,10 +75,10 @@ public function it_does_not_create_a_config_parameter_with_the_same_name(): void

$factory = new ConfigFactory();
$configItem = $factory->setName($config->name)
->setType(ConfigDataType::BOOLEAN)
->setValue('1')
->setDescription(Str::random(50))
->get();
->setType(ConfigDataType::BOOLEAN)
->setValue('1')
->setDescription(Str::random(50))
->get();

$response = $this->laravelConfig->create($configItem);

Expand All @@ -90,9 +93,9 @@ public function it_updates_existing_config_parameter(): void

$factory = new ConfigFactory($config);
$configItem = $factory->setType(ConfigDataType::BOOLEAN)
->setValue('0')
->setDescription('updated-description')
->get();
->setValue('0')
->setDescription('updated-description')
->get();

$this->laravelConfig->update($config, $configItem);

Expand Down Expand Up @@ -256,7 +259,7 @@ public function it_returns_date_value_for_date_type_config_parameter_if_exists()
{
$config = factory(Config::class)->create([
'name' => 'yunus.was.here',
'val' => '2024-02-29',
'val' => '2024-02-29 14:50:00',
'type' => ConfigDataType::DATE,
]);

Expand All @@ -270,7 +273,7 @@ public function it_returns_json_value_for_json_type_config_parameter_if_exists()
{
$config = factory(Config::class)->create([
'name' => 'yunus.was.here',
'val' => '{"9":[7,8,9],"2":[7,8,9],"31":[10,11,12]}',
'val' => [9 => [7, 8, 9], 2 => [7, 8, 9], 31 => [10, 11, 12]],
'type' => ConfigDataType::JSON,
]);

Expand All @@ -282,4 +285,37 @@ public function it_returns_json_value_for_json_type_config_parameter_if_exists()
$this->assertArrayHasKey(2, $response);
$this->assertArrayHasKey(31, $response);
}

/** @test */
public function it_returns_in_caster_type_if_type_is_custom_caster_with_param(): void
{
$config = factory(Config::class)->create([
'name' => 'fatih.was.here',
'val' => [ConfigDataType::DATE],
'type' => AsEnumCollection::class.':'.ConfigDataType::class,
]);

$response = $this->laravelConfig->get($config->name);

$this->assertInstanceOf(Collection::class, $response);
$this->assertCount(1, $response);

$this->assertEquals([ConfigDataType::DATE], $response->toArray());
}

/** @test */
public function it_returns_in_caster_type_if_type_is_custom_caster(): void
{
$config = factory(Config::class)->create([
'name' => 'fatih.was.here',
'val' => [ConfigDataType::DATE->value],
'type' => AsCollection::class,
]);

$response = $this->laravelConfig->get($config->name);

$this->assertInstanceOf(Collection::class, $response);
$this->assertCount(1, $response);
$this->assertEquals([ConfigDataType::DATE->value], $response->toArray());
}
}
Loading