Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvement: Add Cache layer to Graph::build steps #18

Merged
merged 1 commit into from
Oct 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we change this to disallow list we should avoid using the terminology "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