Skip to content

Commit

Permalink
Merge 67a349d into 9828eb5
Browse files Browse the repository at this point in the history
  • Loading branch information
danut007ro committed Oct 2, 2019
2 parents 9828eb5 + 67a349d commit 0605062
Show file tree
Hide file tree
Showing 6 changed files with 250 additions and 102 deletions.
44 changes: 36 additions & 8 deletions README.md
Expand Up @@ -105,6 +105,24 @@ with the original keys `[ 2, 9, 6, 1 ]`:
]
```

##### Providing context values to batch function

There might be some cases when providing a context value to batch function could prove useful.
For instance, when loading data from elasticsearch you can specify what fields to load,
in order to not load the entire document.

This context values can be passed with `load()`or `loadMany()` methods. The library will group by
this context value (using === equality) and pass the context to batch function. The function will
then be able to do the query based on this context value:

```php
// This will make 2 batch calls, but the content will be loaded only for the first document.
// When using graphql, this can be the list of fields that are passed in the query.
$documentLoader->load(1, ['title', 'content']);
$documentLoader->load(2, ['title']);
$documentLoader->load(3, ['title']);
```


### Caching (current PHP instance)

Expand Down Expand Up @@ -248,36 +266,46 @@ Create a new `DataLoaderPHP` given a batch loading instance and options.
- *cacheMap*: An instance of `CacheMap` to be
used as the underlying cache for this loader. Default `new CacheMap()`.

##### `load($key)`
##### `load($key, $context = null)`

Loads a key, returning a `Promise` for the value represented by that key.

- *$key*: An key value to load.
- *$context*: A value to be passed to loader method.

##### `loadMany($keys)`
##### `loadMany($keys, $context = null)`

Loads multiple keys, promising an array of values:

```php
list($a, $b) = DataLoader::await($myLoader->loadMany(['a', 'b']));
list($a, $b) = DataLoader::await($myLoader->loadMany(['a', 'b'], true));
```

This is equivalent to the more verbose:

```php
list($a, $b) = DataLoader::await(\React\Promise\all([
$myLoader->load('a'),
$myLoader->load('b')
$myLoader->load('a', true),
$myLoader->load('b', true)
]));
```

- *$keys*: An array of key values to load.
- *$context*: A value to be passed to loader method.

##### `clear($key)`
##### `clear($key, $context = null)`

Clears the value at `$key` from the cache, if it exists. Returns itself for
method chaining.

- *$key*: An key value to clear.
- *$context*: A value for which to clear given key.

##### `clearKey($key)`

Clears the value at `$key` from the cache for all context values, if it exists. Returns itself for
method chaining.

- *$key*: An key value to clear.

##### `clearAll()`
Expand All @@ -286,9 +314,9 @@ Clears the entire cache. To be used when some event results in unknown
invalidations across this particular `DataLoaderPHP`. Returns itself for
method chaining.

##### `prime($key, $value)`
##### `prime($key, $value, $context = null)`

Primes the cache with the provided key and value. If the key already exists, no
Primes the cache with the provided key and value, grouped by given context value. If the key already exists, no
change is made. (To forcefully prime the cache, clear the key first with
`$loader->clear($key)->prime($key, $value)`. Returns itself for method chaining.

Expand Down
63 changes: 54 additions & 9 deletions src/CacheMap.php
Expand Up @@ -13,41 +13,86 @@

class CacheMap
{
private $promiseCache = [];
protected $promiseCache = [];

public function get($key)
public function get($key, $context = null)
{
$key = self::serializedKey($key);
foreach ($this->promiseCache as $cache) {
if ($cache['context'] === $context) {
return isset($cache['values'][$key]) ? $cache['values'][$key] : null;
}
}

return isset($this->promiseCache[$key]) ? $this->promiseCache[$key] : null;
return null;
}

public function has($key)
public function has($key, $context = null)
{
return isset($this->promiseCache[self::serializedKey($key)]);
foreach ($this->promiseCache as $cache) {
if ($cache['context'] === $context) {
return isset($cache['values'][self::serializedKey($key)]);
}
}

return false;
}

public function set($key, $promise)
public function set($key, $promise, $context = null)
{
$this->promiseCache[self::serializedKey($key)] = $promise;
foreach ($this->promiseCache as $k => $cache) {
if ($cache['context'] === $context) {
$this->promiseCache[$k]['values'][self::serializedKey($key)] = $promise;

return $this;
}
}

$this->promiseCache[] = [
'context' => $context,
'values' => [
self::serializedKey($key) => $promise,
],
];

return $this;
}

public function clear($key)
public function clear($key, $context = null)
{
unset($this->promiseCache[self::serializedKey($key)]);
foreach ($this->promiseCache as $k => $cache) {
if ($cache['context'] === $context) {
$this->removeValue($k, $key);

break;
}
}

return $this;
}

public function clearKey($key)
{
foreach ($this->promiseCache as $k => $cache) {
$this->removeValue($k, $key);
}
}

public function clearAll()
{
$this->promiseCache = [];

return $this;
}

private function removeValue($index, $key)
{
unset($this->promiseCache[$index]['values'][self::serializedKey($key)]);
if (count($this->promiseCache[$index]['values']) === 0) {
unset($this->promiseCache[$index]);
}
}

private static function serializedKey($key)
{
if (is_object($key)) {
Expand Down

0 comments on commit 0605062

Please sign in to comment.