Skip to content

Commit

Permalink
Improvement: Add Cache layer to Graph::build steps
Browse files Browse the repository at this point in the history
  • Loading branch information
chrispenny authored and adrhumphreys committed Oct 18, 2021
1 parent 77a3e6e commit ae18ecd
Show file tree
Hide file tree
Showing 12 changed files with 204 additions and 95 deletions.
6 changes: 1 addition & 5 deletions _config/config.yml → _config/blacklist.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
---
Name: keysforcache
Name: kfc-blacklist
---
SilverStripe\ORM\DataObject:
extensions:
CacheKeyExtension: Terraformers\KeysForCache\Extensions\CacheKeyExtension

Terraformers\KeysForCache\Models\CacheKey:
blacklist:
CacheKey: Terraformers\KeysForCache\Models\CacheKey
Expand Down
8 changes: 8 additions & 0 deletions _config/cache.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
Name: kfc-cache
---
SilverStripe\Core\Injector\Injector:
Psr\SimpleCache\CacheInterface.KeysForCache:
factory: SilverStripe\Core\Cache\CacheFactory
constructor:
namespace: "KeysForCache"
6 changes: 6 additions & 0 deletions _config/extensions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
Name: kfc-extensions
---
SilverStripe\ORM\DataObject:
extensions:
CacheKeyExtension: Terraformers\KeysForCache\Extensions\CacheKeyExtension
92 changes: 61 additions & 31 deletions src/RelationshipGraph/Graph.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,61 @@
namespace Terraformers\KeysForCache\RelationshipGraph;

use Exception;
use Psr\SimpleCache\CacheInterface;
use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Config\Config_ForClass;
use SilverStripe\Core\Flushable;
use SilverStripe\Core\Injector\Injectable;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\ORM\DataObject;

class Graph
class Graph implements Flushable
{
use Injectable;

public const CACHE_KEY = CacheInterface::class . '.KeysForCache';
public const CACHE_KEY_EDGES = 'Edges';
public const CACHE_KEY_GLOBAL_CARES = 'GlobalCares';

private array $nodes = [];
private array $edges = [];
private array $global_cares = [];

public function __construct()
{
// Make sure that our Edges and GlobalCares are built and available
$this->buildEdges();
$this->buildGlobalCares();
}

public static function flush()
{
Injector::inst()->get(self::CACHE_KEY)->clear();

$inst = static::singleton();
$inst->buildEdges();
$inst->buildGlobalCares();
}

public function getEdgesFrom(string $from): array
{
return array_filter(
$this->edges,
$this->getEdges(),
function (Edge $e) use ($from) {
return $e->getFromClassName() === $from;
}
);
}

public function getGlobalCares(): array
public function getEdges(): array
{
return $this->global_cares;
return $this->edges;
}

public function flush(): void
public function getGlobalCares(): array
{
$this->nodes = [];
$this->edges = [];
$this->global_cares = [];
return $this->global_cares;
}

private function addNode(Node $node): self
Expand All @@ -69,23 +84,16 @@ private function findOrCreateNode(string $className): Node
return $node;
}

private function addEdge(Edge $edge): self
{
$this->edges[] = $edge;

return $this;
}

private function getClassAndRelation(string $input): array
{
$res = explode('.', $input);

return [$res[0], $res[1] ?? null];
}

private function getRelationshipConfig(?array $keys, Config_ForClass $config): array
private function getRelationshipConfig(?array $relationships, Config_ForClass $config): array
{
if (!$keys) {
if (!$relationships) {
return [];
}

Expand All @@ -99,8 +107,8 @@ private function getRelationshipConfig(?array $keys, Config_ForClass $config): a

return array_filter(
$relationshipConfigs,
function ($relationship) use ($keys) {
return in_array($relationship, $keys);
function ($relationship) use ($relationships) {
return in_array($relationship, $relationships);
},
ARRAY_FILTER_USE_KEY
);
Expand Down Expand Up @@ -176,8 +184,18 @@ private function getRelationType(string $className, string $relation): ?string

private function buildEdges(): void
{
$cache = Injector::inst()->get(self::CACHE_KEY);

if ($cache->has(self::CACHE_KEY_EDGES)) {
$this->edges = $cache->get(self::CACHE_KEY_EDGES);

return;
}

// Relations only exist from data objects
$classes = ClassInfo::getValidSubClasses(DataObject::class);
// The Edges that we're about to create
$edges = [];

foreach ($classes as $className) {
$config = Config::forClass($className);
Expand All @@ -196,7 +214,7 @@ private function buildEdges(): void
// There is a chance that there was no valid Edge (for a reason that we do understand, and did not
// want to throw an error for)
if ($edge) {
$this->addEdge($edge);
$edges[] = $edge;
}

continue;
Expand All @@ -206,7 +224,7 @@ private function buildEdges(): void

$touchNode = $this->findOrCreateNode($touchClassName);
$edge = new Edge($node, $touchNode, $relation, $this->getRelationType($className, $relation));
$this->addEdge($edge);
$edges[] = $edge;
}

// $cares Edges always need to go $from the class being cared about $to this class
Expand All @@ -224,7 +242,7 @@ private function buildEdges(): void
// There is a chance that there was no valid Edge (for a reason that we do understand, and did not
// want to throw an error for)
if ($edge) {
$this->addEdge($edge);
$edges[] = $edge;
}

continue;
Expand All @@ -237,12 +255,12 @@ private function buildEdges(): void
// A dot notation is available, so we can map this immediately and continue
if ($caresRelation) {
$careNode = $this->findOrCreateNode($careClassName);
$this->addEdge(new Edge(
$edges[] = new Edge(
$careNode,
$node,
$caresRelation,
$this->getRelationType($careClassName, $caresRelation)
));
);

continue;
}
Expand Down Expand Up @@ -273,12 +291,12 @@ private function buildEdges(): void
}

$careNode = $this->findOrCreateNode($careClassName);
$this->addEdge(new Edge(
$edges[] = new Edge(
$careNode,
$node,
$caresRelation,
$this->getRelationType($careClassName, $caresRelation)
));
);

continue;
}
Expand All @@ -294,12 +312,12 @@ private function buildEdges(): void
// Yes, it was a has_many on the other end of the relationship. We can add this Edge and continue
if ($caresRelation) {
$careNode = $this->findOrCreateNode($careClassName);
$this->addEdge(new Edge(
$edges[] = new Edge(
$careNode,
$node,
$caresRelation,
$this->getRelationType($careClassName, $caresRelation)
));
);

continue;
}
Expand All @@ -322,18 +340,29 @@ private function buildEdges(): void
}

$careNode = $this->findOrCreateNode($careClassName);
$this->addEdge(new Edge(
$edges[] = new Edge(
$careNode,
$node,
$caresRelation,
$this->getRelationType($careClassName, $caresRelation)
));
);
}
}

$cache->set(self::CACHE_KEY_EDGES, $edges);
$this->edges = $cache->get(self::CACHE_KEY_EDGES);
}

private function buildGlobalCares(): void
{
$cache = Injector::inst()->get(self::CACHE_KEY);

if ($cache->has(self::CACHE_KEY_GLOBAL_CARES)) {
$this->global_cares = $cache->get(self::CACHE_KEY_GLOBAL_CARES);

return;
}

$classes = ClassInfo::getValidSubClasses(DataObject::class);

$classes = array_map(
Expand Down Expand Up @@ -366,7 +395,8 @@ function($carry, $item) {
[]
);

$this->global_cares = $classes;
$cache->set(self::CACHE_KEY_GLOBAL_CARES, $classes);
$this->global_cares = $cache->get(self::CACHE_KEY_GLOBAL_CARES);
}

private function getThroughClassAndToField(array $throughData): ?array
Expand Down
Loading

0 comments on commit ae18ecd

Please sign in to comment.