Skip to content

Commit

Permalink
Extract shared caching logic
Browse files Browse the repository at this point in the history
  • Loading branch information
xificurk committed Sep 10, 2022
1 parent 2341b02 commit 869c179
Show file tree
Hide file tree
Showing 11 changed files with 318 additions and 64 deletions.
10 changes: 10 additions & 0 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ parameters:
count: 1
path: tests/KdybyTests/Autowired/ComponentFactoriesFixtures/NonPresenterComponent.php

-
message: "#^Parameter \\#1 \\$componentClass of method Kdyby\\\\Autowired\\\\Caching\\\\CacheFactory\\:\\:create\\(\\) expects class\\-string\\<Nette\\\\Application\\\\UI\\\\Component\\>, class\\-string\\<static\\(KdybyTests\\\\Autowired\\\\ComponentFactoriesFixtures\\\\NonPresenterComponent\\)\\> given\\.$#"
count: 1
path: tests/KdybyTests/Autowired/ComponentFactoriesFixtures/NonPresenterComponent.php

-
message: "#^KdybyTests\\\\Autowired\\\\PropertiesFixtures\\\\NonPresenterComponent\\:\\:__get\\(\\) calls parent\\:\\:__get\\(\\) but KdybyTests\\\\Autowired\\\\PropertiesFixtures\\\\NonPresenterComponent does not extend any class\\.$#"
count: 1
Expand All @@ -45,6 +50,11 @@ parameters:
count: 1
path: tests/KdybyTests/Autowired/PropertiesFixtures/NonPresenterComponent.php

-
message: "#^Parameter \\#1 \\$componentClass of method Kdyby\\\\Autowired\\\\Caching\\\\CacheFactory\\:\\:create\\(\\) expects class\\-string\\<Nette\\\\Application\\\\UI\\\\Component\\>, class\\-string\\<static\\(KdybyTests\\\\Autowired\\\\PropertiesFixtures\\\\NonPresenterComponent\\)\\> given\\.$#"
count: 1
path: tests/KdybyTests/Autowired/PropertiesFixtures/NonPresenterComponent.php

-
message: "#^Property KdybyTests\\\\Autowired\\\\PropertiesFixtures\\\\WithMissingPropertyTypePresenter\\:\\:\\$service has no type specified\\.$#"
count: 1
Expand Down
36 changes: 11 additions & 25 deletions src/Kdyby/Autowired/AutowireComponentFactories.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

namespace Kdyby\Autowired;

use Kdyby\Autowired\Caching\CacheFactory;
use Nette;
use Nette\ComponentModel\IComponent;
use Nette\Utils\Reflection;
Expand Down Expand Up @@ -41,27 +42,20 @@ public function injectComponentFactories(Nette\DI\Container $dic): void

$this->autowireComponentFactoriesLocator = $dic;

/** @var Nette\Caching\Storage $storage */
$storage = $dic->hasService('autowired.cacheStorage')
? $dic->getService('autowired.cacheStorage')
: $dic->getByType(Nette\Caching\Storage::class);
$cache = new Nette\Caching\Cache($storage, 'Kdyby.Autowired.AutowireComponentFactories');

$containerFileName = (new \ReflectionClass($this->autowireComponentFactoriesLocator))->getFileName();
/** @var class-string<self> $presenterClass */
$presenterClass = static::class;
$cacheKey = [$presenterClass, $containerFileName];
try {
$cacheFactory = $dic->getByType(CacheFactory::class);
} catch (Nette\DI\MissingServiceException $exception) {
$cacheFactory = CacheFactory::fromContainer($dic);
}
$cache = $cacheFactory->create(static::class, 'Kdyby.Autowired.AutowireComponentFactories');

if ($cache->load($cacheKey) !== NULL) {
if ($cache->load() !== NULL) {
return;
}

$nettePresenterParents = class_parents(Nette\Application\UI\Presenter::class);
assert(is_array($nettePresenterParents));
$ignore = $nettePresenterParents + ['ui' => Nette\Application\UI\Presenter::class];
$rc = new \ReflectionClass($presenterClass);
$rc = new \ReflectionClass($this);
foreach ($rc->getMethods() as $method) {
if (in_array($method->getDeclaringClass()->getName(), $ignore, TRUE) || ! Strings::startsWith($method->getName(), 'createComponent')) {
if (is_a(Nette\Application\UI\Presenter::class, $method->getDeclaringClass()->getName(), TRUE) || ! Strings::startsWith($method->getName(), 'createComponent')) {
continue;
}

Expand All @@ -72,15 +66,7 @@ public function injectComponentFactories(Nette\DI\Container $dic): void
}
}

$presenterParents = class_parents($presenterClass);
assert(is_array($presenterParents));
$files = array_map(fn ($class) => (new \ReflectionClass($class))->getFileName(), array_diff(array_values($presenterParents + ['me' => $presenterClass]), $ignore));

$files[] = $containerFileName;

$cache->save($cacheKey, TRUE, [
$cache::FILES => $files,
]);
$cache->save(TRUE);
}

/**
Expand Down
36 changes: 11 additions & 25 deletions src/Kdyby/Autowired/AutowireProperties.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
namespace Kdyby\Autowired;

use Kdyby\Autowired\Attributes\Autowire;
use Kdyby\Autowired\Caching\CacheFactory;
use Nette;
use Nette\Utils\Reflection;
use Nette\Utils\Strings;
Expand Down Expand Up @@ -42,18 +43,14 @@ public function injectProperties(Nette\DI\Container $dic): void

$this->autowirePropertiesLocator = $dic;

/** @var Nette\Caching\Storage $storage */
$storage = $dic->hasService('autowired.cacheStorage')
? $dic->getService('autowired.cacheStorage')
: $dic->getByType(Nette\Caching\Storage::class);
$cache = new Nette\Caching\Cache($storage, 'Kdyby.Autowired.AutowireProperties');

$containerFileName = (new \ReflectionClass($this->autowirePropertiesLocator))->getFileName();
/** @var class-string<self> $presenterClass */
$presenterClass = static::class;
$cacheKey = [$presenterClass, $containerFileName];
try {
$cacheFactory = $dic->getByType(CacheFactory::class);
} catch (Nette\DI\MissingServiceException $exception) {
$cacheFactory = CacheFactory::fromContainer($dic);
}
$cache = $cacheFactory->create(static::class, 'Kdyby.Autowired.AutowireProperties');

$metadata = $cache->load($cacheKey);
$metadata = $cache->load();
if (is_array($metadata)) {
$this->autowirePropertiesMeta = $metadata;
foreach ($this->autowirePropertiesMeta as $propName => $tmp) {
Expand All @@ -62,27 +59,16 @@ public function injectProperties(Nette\DI\Container $dic): void
return;
}

$nettePresenterParents = class_parents(Nette\Application\UI\Presenter::class);
assert(is_array($nettePresenterParents));
$ignore = $nettePresenterParents + ['ui' => Nette\Application\UI\Presenter::class];
$rc = new \ReflectionClass($presenterClass);
$rc = new \ReflectionClass($this);
foreach ($rc->getProperties() as $prop) {
if (in_array($prop->getDeclaringClass()->getName(), $ignore, TRUE)) {
if (is_a(Nette\Application\UI\Presenter::class, $prop->getDeclaringClass()->getName(), TRUE)) {
continue;
}

$this->resolveProperty($prop);
}

$presenterParents = class_parents($presenterClass);
assert(is_array($presenterParents));
$files = array_map(fn ($class) => (new \ReflectionClass($class))->getFileName(), array_diff(array_values($presenterParents + ['me' => $presenterClass]), $ignore));

$files[] = $containerFileName;

$cache->save($cacheKey, $this->autowirePropertiesMeta, [
$cache::FILES => $files,
]);
$cache->save($this->autowirePropertiesMeta);
}

/**
Expand Down
79 changes: 79 additions & 0 deletions src/Kdyby/Autowired/Caching/Cache.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php
declare(strict_types=1);

namespace Kdyby\Autowired\Caching;

use Nette;

final class Cache
{

private Nette\Caching\Cache $cache;

/**
* @var class-string<Nette\Application\UI\Component>
*/
private string $componentClass;

private string $containerFile;

/**
* @param Nette\Caching\Cache $cache
* @param class-string<Nette\Application\UI\Component> $componentClass
* @param string $containerFile
*/
public function __construct(Nette\Caching\Cache $cache, string $componentClass, string $containerFile)
{
$this->cache = $cache;
$this->componentClass = $componentClass;
$this->containerFile = $containerFile;
}

public function load(): mixed
{
return $this->cache->load($this->getCacheKey());
}

public function save(mixed $value): void
{
$this->cache->save(
$this->getCacheKey(),
$value,
[
Nette\Caching\Cache::FILES => $this->getFileDependencies(),
],
);
}

/**
* @return mixed[]
*/
private function getCacheKey(): array
{
return [$this->componentClass, $this->containerFile];
}

/**
* @return list<string>
*/
private function getFileDependencies(): array
{
/** @var list<class-string> $nettePresenterParents */
$nettePresenterParents = class_parents(Nette\Application\UI\Presenter::class);
assert(is_array($nettePresenterParents));
$ignore = $nettePresenterParents + ['ui' => Nette\Application\UI\Presenter::class];

/** @var list<class-string> $componentParents */
$componentParents = class_parents($this->componentClass);
assert(is_array($componentParents));
$files = array_map(
fn (string $class): string => (string) (new \ReflectionClass($class))->getFileName(),
array_diff($componentParents + ['me' => $this->componentClass], $ignore),
);

$files[] = $this->containerFile;

return array_values(array_unique($files));
}

}
39 changes: 39 additions & 0 deletions src/Kdyby/Autowired/Caching/CacheFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php
declare(strict_types=1);

namespace Kdyby\Autowired\Caching;

use Nette;

final class CacheFactory
{

private Nette\Caching\Storage $cacheStorage;

private string $containerFile;

public function __construct(Nette\Caching\Storage $cacheStorage, string $containerFile)
{
$this->cacheStorage = $cacheStorage;
$this->containerFile = $containerFile;
}

public static function fromContainer(Nette\DI\Container $container, ?Nette\Caching\Storage $cacheStorage = NULL): self
{
$containerFile = (string) (new \ReflectionClass($container))->getFileName();
$cacheStorage ??= $container->getByType(Nette\Caching\Storage::class);
return new self($cacheStorage, $containerFile);
}

/**
* @param class-string<Nette\Application\UI\Component> $componentClass
* @param string $namespace
* @return Cache
*/
public function create(string $componentClass, string $namespace): Cache
{
$cache = new Nette\Caching\Cache($this->cacheStorage, $namespace);
return new Cache($cache, $componentClass, $this->containerFile);
}

}
8 changes: 8 additions & 0 deletions src/Kdyby/Autowired/DI/AutowiredExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

namespace Kdyby\Autowired\DI;

use Kdyby\Autowired\Caching\CacheFactory;
use Nette;
use Nette\DI\Definitions\ServiceDefinition;
use Nette\PhpGenerator as Code;
Expand Down Expand Up @@ -34,6 +35,13 @@ public function loadConfiguration(): void
$storage->setFactory(is_string($config['cacheStorage'])
? new Nette\DI\Definitions\Statement($config['cacheStorage'])
: $config['cacheStorage']);

$builder->addDefinition($this->prefix('cacheFactory'), new ServiceDefinition())
->setType(CacheFactory::class)
->setArguments([
'cacheStorage' => $storage,
'containerFile' => $builder::literal('__FILE__'),
]);
}

public function afterCompile(Code\ClassType $class): void
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use Kdyby;
use Nette;

class IntegrationPresenter extends Nette\Application\UI\Presenter
abstract class BaseControl extends Nette\Application\UI\Control
{

use Kdyby\Autowired\AutowireProperties;
Expand All @@ -17,11 +17,6 @@ class IntegrationPresenter extends Nette\Application\UI\Presenter
*/
public LoremService $service;

/**
* @autowire(factory=\KdybyTests\Autowired\IntegrationFixtures\DatagridFactory)
*/
public DatagridComponent $factoryResult;

protected function createComponentSilly(DatagridFactory $factory): DatagridComponent
{
return $factory->create();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php
declare(strict_types=1);

namespace KdybyTests\Autowired\IntegrationFixtures;

class IntegrationControl extends BaseControl
{

/**
* @autowire(factory=\KdybyTests\Autowired\IntegrationFixtures\DatagridFactory)
*/
public DatagridComponent $factoryResult;

protected function createComponentSilly(DatagridFactory $factory): DatagridComponent
{
return $factory->create();
}

}
58 changes: 58 additions & 0 deletions tests/KdybyTests/Autowired/IntegrationFixtures/TestStorage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php
declare(strict_types=1);

namespace KdybyTests\Autowired\IntegrationFixtures;

use Nette;

final class TestStorage implements Nette\Caching\Storage
{

/**
* @var array<string, array{value: mixed, dependencies: array<string, mixed>}>
*/
public array $records = [];

public function read(string $key): mixed
{
return $this->records[$key]['value'] ?? NULL;
}

public function lock(string $key): void
{
}

/**
* @param string $key
* @param mixed $data
* @param array<string, mixed> $dependencies
*/
public function write(string $key, mixed $data, array $dependencies): void
{
$this->records[$key] = ['value' => $data, 'dependencies' => $dependencies];
}

public function remove(string $key): void
{
unset($this->records[$key]);
}

/**
* @param array<string, mixed> $conditions
*/
public function clean(array $conditions): void
{
if ($conditions[Nette\Caching\Cache::ALL] === TRUE) {
$this->records = [];
}
}

/**
* @return array<string, array{value: mixed, dependencies: array<string, mixed>}>
*/
public function getRecords(): array
{
return $this->records;
}

}

0 comments on commit 869c179

Please sign in to comment.