Passed
Push — master ( 7073d8...993609 )
by y
01:42
created

Cache::addKeys()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Helix\Asana\Api;
4
5
use Closure;
6
use Helix\Asana\Api;
7
use Helix\Asana\Base\AbstractEntity;
8
use Helix\Asana\Base\Data;
9
10
/**
11
 * Pools entities in runtime memory.
12
 */
13
class Cache {
14
15
    /**
16
     * `[ gid => entity ]`
17
     *
18
     * @var AbstractEntity[]
19
     */
20
    protected $entities = [];
21
22
    /**
23
     * `[ key => gid ]`
24
     *
25
     * @var string[];
26
     */
27
    protected $gids = [];
28
29
    /**
30
     * Caches the entity using all available keys.
31
     *
32
     * If the entity has no GID, or has diffs, does nothing.
33
     *
34
     * @param AbstractEntity $entity
35
     * @return bool Success
36
     */
37
    public function add (AbstractEntity $entity): bool {
38
        if ($gid = $entity->getGid() and !$entity->isDiff()) {
39
            $this->entities[$gid] = $entity;
40
            $this->addKeys($gid, $entity->getCacheKeys());
41
            return true;
42
        }
43
        return false;
44
    }
45
46
    /**
47
     * Adds keys for a GID.
48
     *
49
     * @param string $gid
50
     * @param string[] $keys
51
     */
52
    protected function addKeys (string $gid, array $keys): void {
53
        $this->gids += array_fill_keys($keys, $gid);
54
    }
55
56
    /**
57
     * Fetches an entity from the pool, creating it via factory if needed.
58
     *
59
     * If the factory returns an entity with a GID that is already cached,
60
     * the cached version is used instead, and the given key is added for it.
61
     *
62
     * @param string $key
63
     * @param Api|Data $caller
64
     * @param Closure $factory `fn($caller): null|AbstractEntity`
65
     * @return null|mixed|AbstractEntity
66
     */
67
    public function get (string $key, $caller, Closure $factory) {
68
        // POOL HIT
69
        if ($gid = $this->gids[$key] ?? null) {
70
            return $this->entities[$gid];
71
        }
72
        // POOL MISS
73
        $entity = $factory($caller);
74
        if ($entity instanceof AbstractEntity) {
75
            $gid = $entity->getGid();
76
            // if the entity is already pooled, it means the key is new (dynamic/nonstandard).
77
            // renew all known keys and return the existing entity.
78
            if (isset($this->entities[$gid])) {
79
                $this->addKeys($gid, [$key]);
80
                $this->addKeys($gid, $entity->getCacheKeys());
81
                return $this->entities[$gid];
82
            }
83
            // pool the entity and return it
84
            $this->add($entity);
85
            return $entity;
86
        }
87
        return null;
88
    }
89
90
    /**
91
     * Removes the entity and its associated keys from cache.
92
     *
93
     * @param AbstractEntity $entity
94
     */
95
    public function remove (AbstractEntity $entity): void {
96
        $gid = $entity->getGid();
97
        unset($this->entities[$gid]);
98
        foreach ($entity->getCacheKeys() as $key) {
99
            unset($this->gids[$key]);
100
        }
101
    }
102
103
}