Skip to content

Commit

Permalink
cache & sets
Browse files Browse the repository at this point in the history
  • Loading branch information
azuradara committed Jul 13, 2024
1 parent 50aa8f3 commit dddfbc8
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 42 deletions.
7 changes: 7 additions & 0 deletions src/Contracts/Driver.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,11 @@ public function get(string $name, $context);
* @param (callable(mixed $context): mixed) $resolver
*/
public function define(string $name, callable $resolver): void;

/**
* @param mixed $context
* @param mixed $value
*
*/
public function set(string $name, $context, $value): void;
}
46 changes: 45 additions & 1 deletion src/Drivers/ArrayDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace YouCanShop\Foggle\Drivers;

use Illuminate\Contracts\Events\Dispatcher;
use stdClass;
use YouCanShop\Foggle\Contracts\Driver;

class ArrayDriver implements Driver
Expand All @@ -13,6 +14,12 @@ class ArrayDriver implements Driver
/** @var array<string, (callable(mixed $context): mixed)> */
protected array $resolvers;

/** @var array<string, array<string, mixed>> */
protected array $resolved = [];

/** @var stdClass */
protected stdClass $unknown;

/**
* @param Dispatcher $dispatcher
* @param array<string, (callable(mixed $context): mixed)> $resolvers
Expand All @@ -21,6 +28,8 @@ public function __construct(Dispatcher $dispatcher, array $resolvers)
{
$this->dispatcher = $dispatcher;
$this->resolvers = $resolvers;

$this->unknown = new stdClass;
}

/**
Expand All @@ -38,7 +47,42 @@ public function get(string $name, $context)
{
$key = foggle()->serialize($context);

return $this->resolvers[$name]($key);
if (isset($this->resolved[$name][$key])) {
return $this->resolved[$name][$key];
}

return with(
$this->resolveValue($name, $context),
function ($value) use ($name, $key) {
if ($value === $this->unknown) {
return false;
}

$this->set($name, $key, $value);

return $value;
}
);
}

/**
* @param mixed $context
*
* @return mixed
*/
protected function resolveValue(string $name, $context)
{
if (!array_key_exists($name, $this->resolvers)) {
return $this->unknown;
}

return $this->resolvers[$name]($context);
}

public function set(string $name, $context, $value): void
{
$this->resolved[$name] = $this->resolved[$name] ?? [];
$this->resolved[$name][foggle()->serialize($context)] = $value;
}

/**
Expand Down
81 changes: 63 additions & 18 deletions src/Drivers/Decorator.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Closure;
use Illuminate\Contracts\Container\Container;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use Symfony\Component\Finder\Finder;
use YouCanShop\Foggle\Contracts\Driver;
Expand All @@ -16,31 +17,41 @@
*/
class Decorator implements Driver
{
/** @var Collection<int, array{ name: string, context: mixed, value: mixed}> */
protected $cache;

/** @var string */
private string $name;

/** @var Driver */
private Driver $driver;

/** @var Container */
private Container $container;

/**
* @param string $name
* @param Driver $driver
* @param Container $container
* @param Collection<int, array{ name: string, context: mixed, value: mixed}> $cache
*/
public function __construct(
string $name,
Driver $driver,
Container $container
Container $container,
Collection $cache
) {
$this->name = $name;
$this->driver = $driver;
$this->container = $container;
$this->cache = $cache;
}

public function discover(string $namespace = 'App\\Features', ?string $path = null): void
{
$namespace = Str::finish($namespace, '\\');

$entries = (new Finder)
->files()
->name('*.php')
->depth(0)
->in($path ?? base_path('app/Features'));
$entries = (new Finder)->files()->name('*.php')->depth(0)->in($path ?? base_path('app/Features'));

collect($entries)->each(fn($file) => $this->define("$namespace{$file->getBasename('.php')}"));
}
Expand All @@ -60,10 +71,7 @@ public function define(string $name, callable $resolver = null): void
$this->driver->define($name, function ($context) use ($name, $resolver) {
if ($resolver instanceof Lazily) {
$resolver = with(
$this->container[$resolver->feature],
fn($i) => method_exists($i, 'resolve')
? $i->resolve($context)
: $i($context)
$this->container[$resolver->feature], fn($i) => method_exists($i, 'resolve') ? $i->resolve($context) : $i($context)
);
}

Expand All @@ -75,13 +83,6 @@ public function define(string $name, callable $resolver = null): void
});
}

protected function parseContext($context)
{
return $context instanceof Foggable
? $context->foggleId()
: $context;
}

/**
* @param string $name
* @param callable $resolver
Expand All @@ -98,14 +99,58 @@ public function get(string $name, $context)
{
$context = $this->parseContext($context);

return $this->driver->get($name, $context);
$item = $this->cache->whereStrict('context', foggle()->serialize($context))->whereStrict('name', $name)->first();

if ($item !== null) {
return $item['value'];
}

$value = $this->driver->get($name, $context);
$this->cPut($name, $context, $value);

return $value;
}

protected function parseContext($context)
{
return $context instanceof Foggable ? $context->foggleId() : $context;
}

/**
* @param string $name
* @param mixed $context
* @param mixed $value
*
* @return void
*/
protected function cPut(string $name, $context, $value): void
{
$key = foggle()->serialize($context);

$index = $this->cache->search(
fn($i) => $i['name'] === $name && $i['context'] === $key
);

$index === false ? $this->cache[] = ['name' => $name, 'context' => $key, 'value' => $value] : $this->cache[$index] = [
'name' => $name,
'context' => $key,
'value' => $value,
];
}

public function defined(): array
{
return $this->driver->defined();
}

public function set(string $name, $context, $value): void
{
$context = $this->parseContext($context);
$this->driver->set($name, $context, $value);

$this->cPut($name, $context, $value);
}

/**
* @param string $name
* @param array $arguments
Expand Down
57 changes: 35 additions & 22 deletions src/Drivers/RedisDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,63 +15,58 @@ class RedisDriver implements Driver

protected string $name;
protected string $prefix;
protected Config $config;
protected RedisManager $redis;
protected Config $config;
protected Dispatcher $dispatcher;

/** @var array<string, (callable(mixed $context): mixed)> */
protected array $resolvers;

public function __construct(
string $name,
Config $config,
array $resolvers,
RedisManager $redis,
Config $config,
Dispatcher $dispatcher
) {
$this->name = $name;
$this->resolvers = $resolvers;
$this->redis = $redis;
$this->config = $config;
$this->resolvers = $resolvers;
$this->dispatcher = $dispatcher;

$this->unknown = new stdClass;
$this->prefix = $this->config->get("foggle.stores.$this->name.prefix");
}

public function defined(): array
{
return array_keys($this->resolvers);
}

public function get(string $name, $context)
{
$key = foggle()->serialize($context);

$result = $this->connection()->command(
'HGET',
["$this->prefix:$name", $context]
["$this->prefix:$name", $key]
);

if ($result) {
return $result;
}

return with($this->resolveValue($name, $context), function ($value) use ($name, $context) {
if ($value === $this->unknown) {
return false;
}

// $this->set($name, $context, $value);
return with(
$this->resolveValue($name, $context),
function ($value) use ($name, $key) {
if ($value === $this->unknown) {
return false;
}

return $value;
});
}
$this->set($name, $key, $value);

public function define(string $name, callable $resolver): void
{
$this->resolvers[$name] = $resolver;
return $value;
}
);
}

public function connection(): Connection
protected function connection(): Connection
{
return $this->redis->connection(
$this->config->get("foggle.stores.$this->name.connection")
Expand All @@ -86,4 +81,22 @@ protected function resolveValue(string $feature, $context)

return $this->resolvers[$feature]($context);
}

public function set(string $name, $context, $value): void
{
if ($context) {
$key = foggle()->serialize($context);
$this->connection()->command('HSET', ["$this->prefix:$name", $key, $value]);
}
}

public function defined(): array
{
return array_keys($this->resolvers);
}

public function define(string $name, callable $resolver): void
{
$this->resolvers[$name] = $resolver;
}
}
13 changes: 12 additions & 1 deletion src/Foggle.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use RuntimeException;
use YouCanShop\Foggle\Drivers\ArrayDriver;
use YouCanShop\Foggle\Drivers\Decorator;
use YouCanShop\Foggle\Drivers\RedisDriver;

/**
* @mixin Decorator
Expand Down Expand Up @@ -58,11 +59,21 @@ protected function resolve(string $name): Decorator
$driver = new ArrayDriver($this->container['events'], []);
}

if ($name === 'redis') {
$driver = new RedisDriver(
$name,
[],
$this->container['config'],
$this->container['redis'],
$this->container['events']
);
}

if (!isset($driver)) {
throw new InvalidArgumentException("Driver [{$config['driver']}] is not supported");
}

return new Decorator($name, $driver, $this->container);
return new Decorator($name, $driver, $this->container, collect());
}

protected function getDriverConfig(string $name): ?array
Expand Down

0 comments on commit dddfbc8

Please sign in to comment.