Skip to content

Commit bcd7a13

Browse files
Merge pull request #74 from TheDragonCode/3.x
Added specifying the array key when generating a hash
2 parents 8ca0bfc + 1b0ae94 commit bcd7a13

File tree

6 files changed

+145
-44
lines changed

6 files changed

+145
-44
lines changed

README.md

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Or manually update `require` block of `composer.json` and run `composer update`.
2121
```json
2222
{
2323
"require": {
24-
"dragon-code/laravel-cache": "^3.7"
24+
"dragon-code/laravel-cache": "^3.9"
2525
}
2626
}
2727
```
@@ -84,14 +84,19 @@ Since the main problem of working with the cache's key compilation, this package
8484

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

87+
The hash is formed by the value `key=value`, which allows avoiding collisions when passing identical objects.
88+
89+
In the case of passing nested arrays, the key is formed according to the principle `key1.key2=value`, where `key1`
90+
and `key2` are the keys of each nested array.
91+
8792
For example:
8893

8994
```php
9095
use DragonCode\Cache\Services\Cache;
9196

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

94-
// Key is `acbd18db4cc2f85cedef654fccc4a4d8:37b51d194a7513e45b56f6524f2d51f2:73feffa4b7f6bb68e44cf984c85f6e88:b47951d522316fdd8811b23fc9c2f583`
99+
// Key is `d76f2bde023f5602ae837d01f4ec1876:660a13c00e04c0d3ffb4dbf02a84a07a:6fc3659bd986e86534c6587caf5f431a:bd62cbee62e027d0be4b1656781edcbf`
95100
```
96101

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

104-
Cache::make()->key('foo', 'foo')->put('foo');
105-
Cache::make()->key('foo', 'bar')->put('bar');
106-
Cache::make()->key('baz')->put('baz');
109+
Cache::make()->key('foo', 'foo')->put('Foo');
110+
Cache::make()->key('foo', 'bar')->put('Bar');
111+
Cache::make()->key('baz')->put('Baz');
112+
113+
// d76f2bde023f5602ae837d01f4ec1876:
114+
// 086f76c144511e1198c29a261e87ca50: Foo
115+
// 660a13c00e04c0d3ffb4dbf02a84a07a: Bar
116+
// 1b9829f3bd21835a15735f3a65cc75e9: Baz
117+
```
118+
119+
#### Disable key hashing
120+
121+
In some cases, you need to disable the use of the key hashing mechanism.
122+
To do this, simply call the `hashKey(false)` method:
123+
124+
```php
125+
use DragonCode\Cache\Services\Cache;
126+
127+
Cache::make()->key('foo', 'foo')->hashKey(false)->put('Foo');
128+
Cache::make()->key('foo', 'bar')->hashKey(false)->put('Bar');
129+
Cache::make()->key('baz')->hashKey(false)->put('Baz');
130+
131+
// 0=foo:
132+
// 1=foo: Foo
133+
// 1=bar: Bar
134+
// 0=baz: Baz
135+
```
136+
137+
```php
138+
use DragonCode\Cache\Services\Cache;
139+
140+
Cache::make()->key([
141+
['foo' => 'Foo'],
142+
['bar' => 'Bar'],
143+
[['Baz', 'Qwerty']],
144+
])->hashKey(false)->put('Baz');
107145

108-
// acbd18db4cc2f85cedef654fccc4a4d8:
109-
// acbd18db4cc2f85cedef654fccc4a4d8: foo
110-
// 37b51d194a7513e45b56f6524f2d51f2: bar
111-
// 73feffa4b7f6bb68e44cf984c85f6e88: baz
146+
// 0.foo=Foo:1.bar=Bar:2.0.0=Baz:2.0.1=Qwerty
112147
```
113148

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

128-
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
163+
When processing requests with a call to the withAuth method, the binding will be carried out not only by identifier, but
164+
also by reference to the model class, since a project can
129165
have several models with the possibility of authorization.
130166

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

196232
#### Method Call Chain
197233

198-
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:
234+
Sometimes in the process of working with a cache, it becomes necessary to call some code between certain actions, and in
235+
this case the `call` method will come to the rescue:
199236

200237
```php
201238
use DragonCode\Cache\Services\Cache;
@@ -306,12 +343,15 @@ Cache::make()->ttl('custom_key', false);
306343
Cache::make()->ttl((object) ['foo' => 'Foo'], false);
307344
```
308345

309-
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).
346+
If the value is not found, the [default value](config/cache.php) will be taken, which you can also override in
347+
the [configuration file](config/cache.php).
310348

311349
##### With Contract
312350

313-
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
314-
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`
351+
Starting with version [`2.9.0`](https://github.com/TheDragonCode/laravel-cache/releases/tag/v2.9.0), we added the
352+
ability to dynamically specify TTLs in objects. To do this, you
353+
need to implement the `DragonCode\Contracts\Cache\Ttl` contract into your object and add a method that returns one of
354+
the following types of variables: `DateTimeInterface`
315355
, `Carbon\Carbon`, `string`
316356
or `integer`.
317357

@@ -380,7 +420,8 @@ $cache->forget();
380420
// Will remove the key from the cache.
381421
```
382422

383-
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:
423+
To retrieve a tagged cache item, pass the same ordered list of tags to the tags method and then call the get method with
424+
the key you wish to retrieve:
384425

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

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
"require": {
4848
"php": "^8.0",
4949
"dragon-code/contracts": "^2.16",
50-
"dragon-code/support": "^6.1",
50+
"dragon-code/support": "^6.11.3",
5151
"illuminate/support": ">=6.0 <11.0"
5252
},
5353
"require-dev": {

src/Concerns/Arrayable.php

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ trait Arrayable
2222
protected function arrayMap(array $values, callable $callback): array
2323
{
2424
return Arr::of($values)
25-
->map(function ($value) {
25+
->map(function (mixed $value) {
2626
if ($this->isArrayable($value)) {
2727
return $this->toArray($value);
2828
}
@@ -40,6 +40,36 @@ protected function arrayMap(array $values, callable $callback): array
4040
->toArray();
4141
}
4242

43+
protected function arrayFlattenKeysMap(array $values, callable $callback): array
44+
{
45+
return Arr::of($values)
46+
->flattenKeys()
47+
->filter(static fn ($value) => ! empty($value) || is_numeric($value) || is_bool($value))
48+
->map(fn (mixed $value, mixed $key) => $callback($key . '=' . $value))
49+
->toArray();
50+
}
51+
52+
protected function flattenKeys(mixed $array, string $delimiter = '.', ?string $prefix = null): array
53+
{
54+
$result = [];
55+
56+
foreach ($array as $key => $value) {
57+
$new_key = ! empty($prefix) ? $prefix . $delimiter . $key : $key;
58+
59+
if (is_array($value)) {
60+
$values = $this->flattenKeys($value, $delimiter, $new_key);
61+
62+
$result = array_merge($result, $values);
63+
64+
continue;
65+
}
66+
67+
$result[$new_key] = $value;
68+
}
69+
70+
return $result;
71+
}
72+
4373
protected function toArray($value): array
4474
{
4575
return Arr::of(Arr::wrap($value))

src/Support/Key.php

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@ class Key
1313
{
1414
use Arrayable;
1515

16-
public function get(string $separator, array|ArrayObject|DragonArrayable|IlluminateArrayable $values, bool $hash = true): string
17-
{
16+
public function get(
17+
string $separator,
18+
array|ArrayObject|DragonArrayable|IlluminateArrayable $values,
19+
bool $hash = true
20+
): string {
1821
$values = $this->toArray($values);
1922

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

2528
protected function hash(array $values, bool $hash = true): array
2629
{
27-
return $this->arrayMap($values, static function (mixed $value) use ($hash) {
28-
$value = is_bool($value) ? (int) $value : $value;
29-
30-
return $hash ? md5((string) $value) : (string) $value;
31-
});
30+
return $this->arrayFlattenKeysMap($values, fn (mixed $value) => $hash ? md5($value) : $value);
3231
}
3332

3433
protected function compile(array $values, string $separator): string

tests/Cache/When/Simple/RedisTest.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,15 +101,14 @@ public function testWithAuth()
101101
$this->assertTrue($this->cache()->doesntHave());
102102
$this->assertTrue($this->cache()->withAuth()->doesntHave());
103103

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

107-
$this->assertFalse($this->cache()->doesntHave());
106+
$this->assertTrue($this->cache()->doesntHave());
108107
$this->assertTrue($this->cache()->withAuth()->has());
109108

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

112111
$this->assertSame($this->value_second, $this->cache()->withAuth()->get());
113-
$this->assertSame($this->value_second, $this->cache([], $key)->get());
112+
$this->assertNull($this->cache([], $key)->get());
114113
}
115114
}

tests/Support/KeyTest.php

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ public function testString()
3131
{
3232
$key = Key::get(':', ['Foo', 'Bar', 'Baz']);
3333

34-
$expected = '1356c67d7ad1638d816bfb822dd2c25d:ddc35f88fa71b6ef142ae61f35364653:f8dce67f2c94388282ed3fa797968a7c';
34+
$expected =
35+
'17358f5eb750c32289df798e7766e830:64db6856f253b7bf17202a3dd3254fc1:05797d9d2d667864e94e07ba8df60840';
3536

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

43-
$expected = 'c4ca4238a0b923820dcc509a6f75849b:c81e728d9d4c2f636f067f89cc14862c:eccbc87e4b5ce2fe28308fd9f2a7baf3';
44+
$expected =
45+
'd944267ac25276f12cb03fc698810d94:7b2fb106352b24c6dd644a8cdf200295:d8526ab50063e2025ef690f730cd5542';
4446

4547
$this->assertSame($expected, $key);
4648
}
@@ -53,7 +55,12 @@ public function testArray()
5355
[['Baz', 'Qwerty']],
5456
]);
5557

56-
$expected = '1356c67d7ad1638d816bfb822dd2c25d:ddc35f88fa71b6ef142ae61f35364653:f8dce67f2c94388282ed3fa797968a7c:acbd9ab2f68bea3f5291f825416546a1';
58+
$expected = implode(':', [
59+
'b58721335d52d66a9486072fe3383ccf',
60+
'f61f09aec2b68da240f6680a6fc88c6a',
61+
'a13960759cc35a02e91fafb356f491c6',
62+
'70f48dde06f86de7fae03486c277f597',
63+
]);
5764

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

65-
$expected = 'c4ca4238a0b923820dcc509a6f75849b:cfcd208495d565ef66e7dff9f98764da';
72+
$expected = implode(':', [
73+
'd944267ac25276f12cb03fc698810d94',
74+
'bcb8c4703eae71d5d05c0a6eec1f7daa',
75+
]);
6676

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

74-
$expected = 'c4ca4238a0b923820dcc509a6f75849b:1356c67d7ad1638d816bfb822dd2c25d:ddc35f88fa71b6ef142ae61f35364653:f8dce67f2c94388282ed3fa797968a7c';
84+
$expected = implode(':', [
85+
'd944267ac25276f12cb03fc698810d94',
86+
'5bfe89f7c2ace87ef1c208c3d95fc1b6',
87+
'a6426f0db8f32e1156366c7ffe317a6c',
88+
'6e30ad368454c1fdd71d181f47314222',
89+
]);
7590

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

83-
$expected = '1356c67d7ad1638d816bfb822dd2c25d:ddc35f88fa71b6ef142ae61f35364653';
98+
$expected = implode(':', [
99+
'b58721335d52d66a9486072fe3383ccf',
100+
'8a5c22700ece9adc6c0265fa4af575f1',
101+
]);
84102

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

92-
$expected = '1356c67d7ad1638d816bfb822dd2c25d';
110+
$expected = 'b58721335d52d66a9486072fe3383ccf';
93111

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

111-
$expected
112-
= '76d80224611fc919a5d54f0ff9fba446:24113791d2218cb84c9f0462e91596ef:'
113-
. '1356c67d7ad1638d816bfb822dd2c25d:ddc35f88fa71b6ef142ae61f35364653:'
114-
. '91412421a30e87ce15a4f10ea39f6682:1356c67d7ad1638d816bfb822dd2c25d';
129+
$expected = implode(':', [
130+
'6ced27e919d8e040c44929d72fffb681',
131+
'b619de70b824374bf86438df3b059bca',
132+
'bc5ea0aa608c8e0ef8175083e334abff',
133+
'89f5d16cceb669516a0d37c6f2d47df8',
134+
'4d1c034a3e1f42f73339950f3a416c46',
135+
'eb499c88d41a72f17278348308b4bae8',
136+
]);
115137

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

123-
$expected = 'cfcd208495d565ef66e7dff9f98764da:cfcd208495d565ef66e7dff9f98764da';
145+
$expected = implode(':', [
146+
'2d4bab7f33ac57126deb8cde12a0c2ae',
147+
'3e3a3e1902376d96020b11c67bec7a08',
148+
]);
124149

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

132-
$expected = 'e07e8d069dbdfde3b73552938ec82f0a:acbd18db4cc2f85cedef654fccc4a4d8:37b51d194a7513e45b56f6524f2d51f2';
157+
$expected =
158+
'87789eae95facc4a5bfdeb957b860942:086f76c144511e1198c29a261e87ca50:2b72000f7b07c51cbbe0e7f85a19597e';
133159

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

144-
$expected = '1391beb7fd700594df5a1d09d0afe677:72d97f016fa1dda7e212de874853ae28';
170+
$expected = '67f1a84c86633483bea1d2080767711c:aeab04bbac549fe6268a7e12ef761165';
145171

146172
$this->assertSame($expected, $key);
147173
}
@@ -157,7 +183,10 @@ public function testFormRequest()
157183
])
158184
);
159185

160-
$expected = '1356c67d7ad1638d816bfb822dd2c25d:ddc35f88fa71b6ef142ae61f35364653';
186+
$expected = implode(':', [
187+
'b58721335d52d66a9486072fe3383ccf',
188+
'8a5c22700ece9adc6c0265fa4af575f1',
189+
]);
161190

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

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

175-
$expected = 'acbd18db4cc2f85cedef654fccc4a4d8:37b51d194a7513e45b56f6524f2d51f2';
204+
$expected = implode(':', [
205+
'33e35b61ea46b126d2a6bf81acda8724',
206+
'660a13c00e04c0d3ffb4dbf02a84a07a',
207+
]);
176208

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

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

190-
$expected = 'Foo:Bar:Baz:Qwerty';
222+
$expected = '0.foo=Foo:1.bar=Bar:2.0.0=Baz:2.0.1=Qwerty';
191223

192224
$this->assertSame($expected, $key);
193225
}

0 commit comments

Comments
 (0)