Skip to content

Commit

Permalink
Merge pull request #74 from TheDragonCode/3.x
Browse files Browse the repository at this point in the history
Added specifying the array key when generating a hash
  • Loading branch information
andrey-helldar committed Aug 3, 2023
2 parents 8ca0bfc + 1b0ae94 commit bcd7a13
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 44 deletions.
71 changes: 56 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Or manually update `require` block of `composer.json` and run `composer update`.
```json
{
"require": {
"dragon-code/laravel-cache": "^3.7"
"dragon-code/laravel-cache": "^3.9"
}
}
```
Expand Down Expand Up @@ -84,14 +84,19 @@ Since the main problem of working with the cache's key compilation, this package

By passing values to the `keys` method, we get a ready-made key at the output.

The hash is formed by the value `key=value`, which allows avoiding collisions when passing identical objects.

In the case of passing nested arrays, the key is formed according to the principle `key1.key2=value`, where `key1`
and `key2` are the keys of each nested array.

For example:

```php
use DragonCode\Cache\Services\Cache;

Cache::make()->key('foo', 'bar', [null, 'baz', 'baq']);

// Key is `acbd18db4cc2f85cedef654fccc4a4d8:37b51d194a7513e45b56f6524f2d51f2:73feffa4b7f6bb68e44cf984c85f6e88:b47951d522316fdd8811b23fc9c2f583`
// Key is `d76f2bde023f5602ae837d01f4ec1876:660a13c00e04c0d3ffb4dbf02a84a07a:6fc3659bd986e86534c6587caf5f431a:bd62cbee62e027d0be4b1656781edcbf`
```

This means that when writing to the cache, the tree view will be used.
Expand All @@ -101,14 +106,44 @@ For example:
```php
use DragonCode\Cache\Services\Cache;

Cache::make()->key('foo', 'foo')->put('foo');
Cache::make()->key('foo', 'bar')->put('bar');
Cache::make()->key('baz')->put('baz');
Cache::make()->key('foo', 'foo')->put('Foo');
Cache::make()->key('foo', 'bar')->put('Bar');
Cache::make()->key('baz')->put('Baz');

// d76f2bde023f5602ae837d01f4ec1876:
// 086f76c144511e1198c29a261e87ca50: Foo
// 660a13c00e04c0d3ffb4dbf02a84a07a: Bar
// 1b9829f3bd21835a15735f3a65cc75e9: Baz
```

#### Disable key hashing

In some cases, you need to disable the use of the key hashing mechanism.
To do this, simply call the `hashKey(false)` method:

```php
use DragonCode\Cache\Services\Cache;

Cache::make()->key('foo', 'foo')->hashKey(false)->put('Foo');
Cache::make()->key('foo', 'bar')->hashKey(false)->put('Bar');
Cache::make()->key('baz')->hashKey(false)->put('Baz');

// 0=foo:
// 1=foo: Foo
// 1=bar: Bar
// 0=baz: Baz
```

```php
use DragonCode\Cache\Services\Cache;

Cache::make()->key([
['foo' => 'Foo'],
['bar' => 'Bar'],
[['Baz', 'Qwerty']],
])->hashKey(false)->put('Baz');

// acbd18db4cc2f85cedef654fccc4a4d8:
// acbd18db4cc2f85cedef654fccc4a4d8: foo
// 37b51d194a7513e45b56f6524f2d51f2: bar
// 73feffa4b7f6bb68e44cf984c85f6e88: baz
// 0.foo=Foo:1.bar=Bar:2.0.0=Baz:2.0.1=Qwerty
```

### With Authentication
Expand All @@ -125,7 +160,8 @@ Cache::make()->withAuth()->key('foo', 'bar');
Cache::make()->key(get_class(Auth::user()), Auth::id(), 'foo', 'bar');
```

When processing requests with a call to the withAuth method, the binding will be carried out not only by identifier, but also by reference to the model class, since a project can
When processing requests with a call to the withAuth method, the binding will be carried out not only by identifier, but
also by reference to the model class, since a project can
have several models with the possibility of authorization.

For example, `App\Models\Employee`, `App\Models\User`.
Expand Down Expand Up @@ -195,7 +231,8 @@ $cache->forget();

#### Method Call Chain

Sometimes in the process of working with a cache, it becomes necessary to call some code between certain actions, and in this case the `call` method will come to the rescue:
Sometimes in the process of working with a cache, it becomes necessary to call some code between certain actions, and in
this case the `call` method will come to the rescue:

```php
use DragonCode\Cache\Services\Cache;
Expand Down Expand Up @@ -306,12 +343,15 @@ Cache::make()->ttl('custom_key', false);
Cache::make()->ttl((object) ['foo' => 'Foo'], false);
```

If the value is not found, the [default value](config/cache.php) will be taken, which you can also override in the [configuration file](config/cache.php).
If the value is not found, the [default value](config/cache.php) will be taken, which you can also override in
the [configuration file](config/cache.php).

##### With Contract

Starting with version [`2.9.0`](https://github.com/TheDragonCode/laravel-cache/releases/tag/v2.9.0), we added the ability to dynamically specify TTLs in objects. To do this, you
need to implement the `DragonCode\Contracts\Cache\Ttl` contract into your object and add a method that returns one of the following types of variables: `DateTimeInterface`
Starting with version [`2.9.0`](https://github.com/TheDragonCode/laravel-cache/releases/tag/v2.9.0), we added the
ability to dynamically specify TTLs in objects. To do this, you
need to implement the `DragonCode\Contracts\Cache\Ttl` contract into your object and add a method that returns one of
the following types of variables: `DateTimeInterface`
, `Carbon\Carbon`, `string`
or `integer`.

Expand Down Expand Up @@ -380,7 +420,8 @@ $cache->forget();
// Will remove the key from the cache.
```

To retrieve a tagged cache item, pass the same ordered list of tags to the tags method and then call the get method with the key you wish to retrieve:
To retrieve a tagged cache item, pass the same ordered list of tags to the tags method and then call the get method with
the key you wish to retrieve:

```php
use DragonCode\Cache\Services\Cache;
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"require": {
"php": "^8.0",
"dragon-code/contracts": "^2.16",
"dragon-code/support": "^6.1",
"dragon-code/support": "^6.11.3",
"illuminate/support": ">=6.0 <11.0"
},
"require-dev": {
Expand Down
32 changes: 31 additions & 1 deletion src/Concerns/Arrayable.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ trait Arrayable
protected function arrayMap(array $values, callable $callback): array
{
return Arr::of($values)
->map(function ($value) {
->map(function (mixed $value) {
if ($this->isArrayable($value)) {
return $this->toArray($value);
}
Expand All @@ -40,6 +40,36 @@ protected function arrayMap(array $values, callable $callback): array
->toArray();
}

protected function arrayFlattenKeysMap(array $values, callable $callback): array
{
return Arr::of($values)
->flattenKeys()
->filter(static fn ($value) => ! empty($value) || is_numeric($value) || is_bool($value))
->map(fn (mixed $value, mixed $key) => $callback($key . '=' . $value))
->toArray();
}

protected function flattenKeys(mixed $array, string $delimiter = '.', ?string $prefix = null): array
{
$result = [];

foreach ($array as $key => $value) {
$new_key = ! empty($prefix) ? $prefix . $delimiter . $key : $key;

if (is_array($value)) {
$values = $this->flattenKeys($value, $delimiter, $new_key);

$result = array_merge($result, $values);

continue;
}

$result[$new_key] = $value;
}

return $result;
}

protected function toArray($value): array
{
return Arr::of(Arr::wrap($value))
Expand Down
13 changes: 6 additions & 7 deletions src/Support/Key.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ class Key
{
use Arrayable;

public function get(string $separator, array|ArrayObject|DragonArrayable|IlluminateArrayable $values, bool $hash = true): string
{
public function get(
string $separator,
array|ArrayObject|DragonArrayable|IlluminateArrayable $values,
bool $hash = true
): string {
$values = $this->toArray($values);

$hashed = $this->hash($values, $hash);
Expand All @@ -24,11 +27,7 @@ public function get(string $separator, array|ArrayObject|DragonArrayable|Illumin

protected function hash(array $values, bool $hash = true): array
{
return $this->arrayMap($values, static function (mixed $value) use ($hash) {
$value = is_bool($value) ? (int) $value : $value;

return $hash ? md5((string) $value) : (string) $value;
});
return $this->arrayFlattenKeysMap($values, fn (mixed $value) => $hash ? md5($value) : $value);
}

protected function compile(array $values, string $separator): string
Expand Down
5 changes: 2 additions & 3 deletions tests/Cache/When/Simple/RedisTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,15 +101,14 @@ public function testWithAuth()
$this->assertTrue($this->cache()->doesntHave());
$this->assertTrue($this->cache()->withAuth()->doesntHave());

$this->cache()->put($this->value);
$this->cache()->withAuth()->put($this->value_second);

$this->assertFalse($this->cache()->doesntHave());
$this->assertTrue($this->cache()->doesntHave());
$this->assertTrue($this->cache()->withAuth()->has());

$key = [User::class, $this->user_id, 'Foo', 'Bar', 'Baz'];

$this->assertSame($this->value_second, $this->cache()->withAuth()->get());
$this->assertSame($this->value_second, $this->cache([], $key)->get());
$this->assertNull($this->cache([], $key)->get());
}
}
66 changes: 49 additions & 17 deletions tests/Support/KeyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ public function testString()
{
$key = Key::get(':', ['Foo', 'Bar', 'Baz']);

$expected = '1356c67d7ad1638d816bfb822dd2c25d:ddc35f88fa71b6ef142ae61f35364653:f8dce67f2c94388282ed3fa797968a7c';
$expected =
'17358f5eb750c32289df798e7766e830:64db6856f253b7bf17202a3dd3254fc1:05797d9d2d667864e94e07ba8df60840';

$this->assertSame($expected, $key);
}
Expand All @@ -40,7 +41,8 @@ public function testNumeric()
{
$key = Key::get(':', [1, 2, 3]);

$expected = 'c4ca4238a0b923820dcc509a6f75849b:c81e728d9d4c2f636f067f89cc14862c:eccbc87e4b5ce2fe28308fd9f2a7baf3';
$expected =
'd944267ac25276f12cb03fc698810d94:7b2fb106352b24c6dd644a8cdf200295:d8526ab50063e2025ef690f730cd5542';

$this->assertSame($expected, $key);
}
Expand All @@ -53,7 +55,12 @@ public function testArray()
[['Baz', 'Qwerty']],
]);

$expected = '1356c67d7ad1638d816bfb822dd2c25d:ddc35f88fa71b6ef142ae61f35364653:f8dce67f2c94388282ed3fa797968a7c:acbd9ab2f68bea3f5291f825416546a1';
$expected = implode(':', [
'b58721335d52d66a9486072fe3383ccf',
'f61f09aec2b68da240f6680a6fc88c6a',
'a13960759cc35a02e91fafb356f491c6',
'70f48dde06f86de7fae03486c277f597',
]);

$this->assertSame($expected, $key);
}
Expand All @@ -62,7 +69,10 @@ public function testBoolean()
{
$key = Key::get(':', [true, false]);

$expected = 'c4ca4238a0b923820dcc509a6f75849b:cfcd208495d565ef66e7dff9f98764da';
$expected = implode(':', [
'd944267ac25276f12cb03fc698810d94',
'bcb8c4703eae71d5d05c0a6eec1f7daa',
]);

$this->assertSame($expected, $key);
}
Expand All @@ -71,7 +81,12 @@ public function testCombine()
{
$key = Key::get(':', [1, 'Foo', [['Bar', 'Baz']]]);

$expected = 'c4ca4238a0b923820dcc509a6f75849b:1356c67d7ad1638d816bfb822dd2c25d:ddc35f88fa71b6ef142ae61f35364653:f8dce67f2c94388282ed3fa797968a7c';
$expected = implode(':', [
'd944267ac25276f12cb03fc698810d94',
'5bfe89f7c2ace87ef1c208c3d95fc1b6',
'a6426f0db8f32e1156366c7ffe317a6c',
'6e30ad368454c1fdd71d181f47314222',
]);

$this->assertSame($expected, $key);
}
Expand All @@ -80,7 +95,10 @@ public function testArrayable()
{
$key = Key::get(':', $this->dto());

$expected = '1356c67d7ad1638d816bfb822dd2c25d:ddc35f88fa71b6ef142ae61f35364653';
$expected = implode(':', [
'b58721335d52d66a9486072fe3383ccf',
'8a5c22700ece9adc6c0265fa4af575f1',
]);

$this->assertSame($expected, $key);
}
Expand All @@ -89,7 +107,7 @@ public function testCustomObject()
{
$key = Key::get(':', [new CustomObject()]);

$expected = '1356c67d7ad1638d816bfb822dd2c25d';
$expected = 'b58721335d52d66a9486072fe3383ccf';

$this->assertSame($expected, $key);
}
Expand All @@ -108,10 +126,14 @@ public function testMultiObjectArrays()
// Before hashing, the keys look like this:
// qwe:rty:Foo:Bar:WASD:Foo

$expected
= '76d80224611fc919a5d54f0ff9fba446:24113791d2218cb84c9f0462e91596ef:'
. '1356c67d7ad1638d816bfb822dd2c25d:ddc35f88fa71b6ef142ae61f35364653:'
. '91412421a30e87ce15a4f10ea39f6682:1356c67d7ad1638d816bfb822dd2c25d';
$expected = implode(':', [
'6ced27e919d8e040c44929d72fffb681',
'b619de70b824374bf86438df3b059bca',
'bc5ea0aa608c8e0ef8175083e334abff',
'89f5d16cceb669516a0d37c6f2d47df8',
'4d1c034a3e1f42f73339950f3a416c46',
'eb499c88d41a72f17278348308b4bae8',
]);

$this->assertSame($expected, $key);
}
Expand All @@ -120,7 +142,10 @@ public function testEmpties()
{
$key = Key::get(':', [null, '', 0, [], false]);

$expected = 'cfcd208495d565ef66e7dff9f98764da:cfcd208495d565ef66e7dff9f98764da';
$expected = implode(':', [
'2d4bab7f33ac57126deb8cde12a0c2ae',
'3e3a3e1902376d96020b11c67bec7a08',
]);

$this->assertSame($expected, $key);
}
Expand All @@ -129,7 +154,8 @@ public function testModelKey()
{
$key = Key::get(':', [User::class, 'foo', 'bar']);

$expected = 'e07e8d069dbdfde3b73552938ec82f0a:acbd18db4cc2f85cedef654fccc4a4d8:37b51d194a7513e45b56f6524f2d51f2';
$expected =
'87789eae95facc4a5bfdeb957b860942:086f76c144511e1198c29a261e87ca50:2b72000f7b07c51cbbe0e7f85a19597e';

$this->assertSame($expected, $key);
}
Expand All @@ -141,7 +167,7 @@ public function testCarbon()
Carbon::parse('2022-10-07 15:00:00'),
]);

$expected = '1391beb7fd700594df5a1d09d0afe677:72d97f016fa1dda7e212de874853ae28';
$expected = '67f1a84c86633483bea1d2080767711c:aeab04bbac549fe6268a7e12ef761165';

$this->assertSame($expected, $key);
}
Expand All @@ -157,7 +183,10 @@ public function testFormRequest()
])
);

$expected = '1356c67d7ad1638d816bfb822dd2c25d:ddc35f88fa71b6ef142ae61f35364653';
$expected = implode(':', [
'b58721335d52d66a9486072fe3383ccf',
'8a5c22700ece9adc6c0265fa4af575f1',
]);

$this->assertSame($expected, $key);
}
Expand All @@ -172,7 +201,10 @@ public function testEnum()

$key = Key::get(':', [WithoutValueEnum::foo, WithValueEnum::bar]);

$expected = 'acbd18db4cc2f85cedef654fccc4a4d8:37b51d194a7513e45b56f6524f2d51f2';
$expected = implode(':', [
'33e35b61ea46b126d2a6bf81acda8724',
'660a13c00e04c0d3ffb4dbf02a84a07a',
]);

$this->assertSame($expected, $key);
}
Expand All @@ -187,7 +219,7 @@ public function testWithoutHash()

$key = Key::get(':', $keys, false);

$expected = 'Foo:Bar:Baz:Qwerty';
$expected = '0.foo=Foo:1.bar=Bar:2.0.0=Baz:2.0.1=Qwerty';

$this->assertSame($expected, $key);
}
Expand Down

0 comments on commit bcd7a13

Please sign in to comment.