Skip to content

Commit c7ddf23

Browse files
authored
Added listener for flushing Str cache between requests (#86)
1 parent 53239eb commit c7ddf23

File tree

6 files changed

+173
-3
lines changed

6 files changed

+173
-3
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ The format is based on [Keep a Changelog][keepachangelog] and this project adher
99
### Added
1010

1111
- Laravel 9 support [#78]
12+
- Listener `FlushStrCacheListener` for flushing `Str` cache between requests [#86]
1213

1314
### Removed
1415

1516
- Laravel 6 and 7 is no longer supported [#78]
1617

1718
[#78]:https://github.com/spiral/roadrunner-laravel/pull/78
19+
[#86]:https://github.com/spiral/roadrunner-laravel/pull/86
1820

1921
## v5.6.0
2022

src/Defaults.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ public static function afterLoopIteration(): array
9696
Listeners\FlushDumperStackListener::class,
9797
Listeners\FlushLogContextListener::class,
9898
Listeners\FlushArrayCacheListener::class,
99+
Listeners\FlushStrCacheListener::class,
99100
Listeners\FlushMonologStateListener::class,
100101
Listeners\FlushTranslatorCacheListener::class,
101102
Listeners\ResetDatabaseRecordModificationStateListener::class,
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Spiral\RoadRunnerLaravel\Listeners;
6+
7+
use Illuminate\Support\Str;
8+
9+
/**
10+
* @link https://github.com/laravel/octane/blob/1.x/src/Listeners/FlushStrCache.php
11+
*/
12+
class FlushStrCacheListener implements ListenerInterface
13+
{
14+
use Traits\InvokerTrait;
15+
16+
/**
17+
* {@inheritdoc}
18+
*/
19+
public function handle($event): void
20+
{
21+
/**
22+
* Method `flushCache` for the Str available since Laravel v8.81.0.
23+
*
24+
* @link https://github.com/illuminate/support/blob/v8.81.0/Str.php#L994
25+
* @see \Illuminate\Support\Str::flushCache
26+
*/
27+
if (! $this->invokeStaticMethod($class = Str::class, 'flushCache')) {
28+
foreach (['snakeCache', 'camelCache', 'studlyCache'] as $property) {
29+
$this->setStaticProperty($class, $property, []);
30+
}
31+
}
32+
}
33+
}

src/Listeners/Traits/InvokerTrait.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,26 @@ final protected function invokeMethod(object $object, string $method_name, ...$a
2929
return false;
3030
}
3131

32+
/**
33+
* Invoke the static method on class.
34+
*
35+
* @param class-string $class
36+
* @param string $method_name
37+
* @param mixed ...$args
38+
*
39+
* @return bool TRUE if the method exists and invoked, FALSE otherwise.
40+
*/
41+
final protected function invokeStaticMethod(string $class, string $method_name, ...$args): bool
42+
{
43+
if (\method_exists($class, $method_name)) {
44+
$class::{$method_name}(...$args);
45+
46+
return true;
47+
}
48+
49+
return false;
50+
}
51+
3252
/**
3353
* Change object property value (even protected or private). Black magic is used.
3454
*
@@ -55,4 +75,37 @@ final protected function setProperty(object $object, string $property_name, $val
5575

5676
return $changed;
5777
}
78+
79+
/**
80+
* Change static object property value (even protected or private). Black magic is used.
81+
*
82+
* @param class-string $class
83+
* @param string $property_name
84+
* @param mixed $value
85+
*
86+
* @return bool TRUE if the property exists and changed, FALSE otherwise.
87+
*/
88+
final protected function setStaticProperty(string $class, string $property_name, $value): bool
89+
{
90+
$changed = false;
91+
92+
try {
93+
$instance = (new \ReflectionClass($class))->newInstanceWithoutConstructor();
94+
95+
$closure = function () use ($value, $property_name, &$changed): void {
96+
if (\property_exists($this, $property_name) && static::${$property_name} !== null) {
97+
static::${$property_name} = $value;
98+
99+
$changed = true;
100+
}
101+
};
102+
103+
$reset = $closure->bindTo($instance, $instance);
104+
$reset();
105+
} catch (\ReflectionException $e) {
106+
return false;
107+
}
108+
109+
return $changed;
110+
}
58111
}

tests/Unit/Listeners/AbstractListenerTestCase.php

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ abstract protected function listenerFactory();
3131
abstract protected function testHandle(): void;
3232

3333
/**
34-
* @deprecated
35-
*
3634
* @param object $object
3735
* @param string $property
3836
*
@@ -53,8 +51,29 @@ protected function getProperty($object, string $property)
5351
}
5452

5553
/**
56-
* @deprecated
54+
* @param class-string $class
55+
* @param string $property
5756
*
57+
* @return mixed
58+
* @throws \ReflectionException
59+
*/
60+
protected function getStaticProperty(string $class, string $property)
61+
{
62+
$result = null;
63+
64+
$closure = function () use ($property, &$result): void {
65+
$result = static::${$property};
66+
};
67+
68+
$instance = (new \ReflectionClass($class))->newInstanceWithoutConstructor();
69+
70+
$getter = $closure->bindTo($instance, $instance);
71+
$getter();
72+
73+
return $result;
74+
}
75+
76+
/**
5877
* @param object $object
5978
* @param string $property
6079
* @param mixed $value
@@ -70,4 +89,24 @@ protected function setProperty($object, string $property, $value): void
7089
$setter = $closure->bindTo($object, $object);
7190
$setter();
7291
}
92+
93+
/**
94+
* @param class-string $class
95+
* @param string $property
96+
* @param mixed $value
97+
*
98+
* @return void
99+
* @throws \ReflectionException
100+
*/
101+
protected function setStaticProperty(string $class, string $property, $value): void
102+
{
103+
$closure = function () use ($property, &$value): void {
104+
static::${$property} = $value;
105+
};
106+
107+
$instance = (new \ReflectionClass($class))->newInstanceWithoutConstructor();
108+
109+
$setter = $closure->bindTo($instance, $instance);
110+
$setter();
111+
}
73112
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Spiral\RoadRunnerLaravel\Tests\Unit\Listeners;
6+
7+
use Illuminate\Support\Str;
8+
use Spiral\RoadRunnerLaravel\Listeners\FlushStrCacheListener;
9+
10+
/**
11+
* @covers \Spiral\RoadRunnerLaravel\Listeners\FlushStrCacheListener
12+
*/
13+
class FlushStrCacheListenerTest extends AbstractListenerTestCase
14+
{
15+
/**
16+
* {@inheritdoc}
17+
*/
18+
public function testHandle(): void
19+
{
20+
Str::snake('Hello world');
21+
Str::camel('Hello world');
22+
Str::studly('Hello world');
23+
24+
$this->assertNotEmpty($this->getStaticProperty($class = Str::class, 'snakeCache'));
25+
$this->assertNotEmpty($this->getStaticProperty($class, 'camelCache'));
26+
$this->assertNotEmpty($this->getStaticProperty($class, 'studlyCache'));
27+
28+
$this->listenerFactory()->handle(new \stdClass());
29+
30+
$this->assertEmpty($this->getStaticProperty($class, 'snakeCache'));
31+
$this->assertEmpty($this->getStaticProperty($class, 'camelCache'));
32+
$this->assertEmpty($this->getStaticProperty($class, 'studlyCache'));
33+
}
34+
35+
/**
36+
* @return FlushStrCacheListener
37+
*/
38+
protected function listenerFactory(): FlushStrCacheListener
39+
{
40+
return new FlushStrCacheListener();
41+
}
42+
}

0 commit comments

Comments
 (0)