Skip to content

Commit 3b66016

Browse files
authored
Adding cache provider (#717)
* Adding cache provider * Applied changes from StyleCI * Bugfix * Added major version number in cache key * Be more relaxed with tests
1 parent b132d44 commit 3b66016

File tree

12 files changed

+415
-1
lines changed

12 files changed

+415
-1
lines changed

composer.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@
2929
"php-http/message": "^1.0",
3030
"php-http/curl-client": "^1.7",
3131
"php-http/mock-client": "^1.0",
32-
"nyholm/psr7": "^0.2.2"
32+
"nyholm/psr7": "^0.2.2",
33+
"cache/simple-cache-bridge": "^0.1.1",
34+
"cache/array-adapter": "^0.5.0"
3335
},
3436
"suggest": {
3537
"ext-geoip": "Enabling the geoip extension allows you to use the MaxMindProvider.",

src/Provider/Cache/.gitattributes

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.gitattributes export-ignore
2+
.travis.yml export-ignore
3+
phpunit.xml.dist export-ignore
4+
Tests/ export-ignore

src/Provider/Cache/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
vendor/
2+
composer.lock
3+
phpunit.xml

src/Provider/Cache/.travis.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
language: php
2+
sudo: false
3+
4+
php: 7.0
5+
6+
7+
install:
8+
- composer update --prefer-stable --prefer-dist
9+
10+
script:
11+
- composer test-ci
12+
13+
after_success:
14+
- wget https://scrutinizer-ci.com/ocular.phar
15+
- php ocular.phar code-coverage:upload --format=php-clover build/coverage.xml
16+

src/Provider/Cache/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Change Log
2+
3+
The change log describes what is "Added", "Removed", "Changed" or "Fixed" between each release.
4+
5+
## 4.0.0
6+
7+
First release of this library.

src/Provider/Cache/LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2011 — William Durand <[email protected]>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

src/Provider/Cache/ProviderCache.php

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Geocoder package.
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*
10+
* @license MIT License
11+
*/
12+
13+
namespace Geocoder\Provider\Cache;
14+
15+
use Geocoder\Collection;
16+
use Geocoder\Query\GeocodeQuery;
17+
use Geocoder\Query\ReverseQuery;
18+
use Geocoder\Provider\Provider;
19+
use Psr\SimpleCache\CacheInterface;
20+
21+
/**
22+
* @author Tobias Nyholm <[email protected]>
23+
*/
24+
final class ProviderCache implements Provider
25+
{
26+
/**
27+
* @var Provider
28+
*/
29+
private $realProvider;
30+
31+
/**
32+
* @var CacheInterface
33+
*/
34+
private $cache;
35+
36+
/**
37+
* How log a result is going to be cached.
38+
*
39+
* @var int|null
40+
*/
41+
private $lifetime;
42+
43+
/**
44+
* @param Provider $realProvider
45+
* @param CacheInterface $cache
46+
* @param int $lifetime
47+
*/
48+
public function __construct(Provider $realProvider, CacheInterface $cache, int $lifetime = null)
49+
{
50+
$this->realProvider = $realProvider;
51+
$this->cache = $cache;
52+
$this->lifetime = $lifetime;
53+
}
54+
55+
/**
56+
* {@inheritdoc}
57+
*/
58+
public function geocodeQuery(GeocodeQuery $query): Collection
59+
{
60+
$cacheKey = $this->getCacheKey($query);
61+
if (null !== $result = $this->cache->get($cacheKey)) {
62+
return $result;
63+
}
64+
65+
$result = $this->realProvider->geocodeQuery($query);
66+
$this->cache->set($cacheKey, $result, $this->lifetime);
67+
68+
return $result;
69+
}
70+
71+
/**
72+
* {@inheritdoc}
73+
*/
74+
public function reverseQuery(ReverseQuery $query): Collection
75+
{
76+
$cacheKey = $this->getCacheKey($query);
77+
if (null !== $result = $this->cache->get($cacheKey)) {
78+
return $result;
79+
}
80+
81+
$result = $this->realProvider->reverseQuery($query);
82+
$this->cache->set($cacheKey, $result, $this->lifetime);
83+
84+
return $result;
85+
}
86+
87+
/**
88+
* {@inheritdoc}
89+
*/
90+
public function getName(): string
91+
{
92+
return sprintf('%s (cache)', $this->realProvider->getName());
93+
}
94+
95+
public function __call($method, $args)
96+
{
97+
return call_user_func_array([$this->realProvider, $method], $args);
98+
}
99+
100+
/**
101+
* @param GeocodeQuery|ReverseQuery $query
102+
*
103+
* @return string
104+
*/
105+
private function getCacheKey($query): string
106+
{
107+
// Include the major version number of the geocoder to avoid issues unserializing.
108+
return 'v4'.sha1((string) $query);
109+
}
110+
}

src/Provider/Cache/Readme.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Cache provider
2+
[![Build Status](https://travis-ci.org/geocoder-php/cache-provider.svg?branch=master)](http://travis-ci.org/geocoder-php/cache-provider)
3+
[![Latest Stable Version](https://poser.pugx.org/geocoder-php/cache-provider/v/stable)](https://packagist.org/packages/geocoder-php/cache-provider)
4+
[![Total Downloads](https://poser.pugx.org/geocoder-php/cache-provider/downloads)](https://packagist.org/packages/geocoder-php/cache-provider)
5+
[![Monthly Downloads](https://poser.pugx.org/geocoder-php/cache-provider/d/monthly.png)](https://packagist.org/packages/geocoder-php/cache-provider)
6+
[![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/geocoder-php/cache-provider.svg?style=flat-square)](https://scrutinizer-ci.com/g/geocoder-php/cache-provider)
7+
[![Quality Score](https://img.shields.io/scrutinizer/g/geocoder-php/cache-provider.svg?style=flat-square)](https://scrutinizer-ci.com/g/geocoder-php/cache-provider)
8+
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)
9+
10+
This is the a cache provider from the PHP Geocoder. This is a **READ ONLY** repository. See the
11+
[main repo](https://github.com/geocoder-php/Geocoder) for information and documentation.
12+
13+
### Install
14+
15+
```bash
16+
composer require geocoder-php/cache-provider
17+
```
18+
19+
### Contribute
20+
21+
Contributions are very welcome! Send a pull request to the [main repository](https://github.com/geocoder-php/Geocoder) or
22+
report any issues you find on the [issue tracker](https://github.com/geocoder-php/Geocoder/issues).
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Geocoder package.
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*
10+
* @license MIT License
11+
*/
12+
13+
namespace Geocoder\Provider\Cache\Tests;
14+
15+
use Geocoder\Model\Address;
16+
use Geocoder\Model\AddressCollection;
17+
use Geocoder\Provider\Cache\ProviderCache;
18+
use Geocoder\Provider\Provider;
19+
use Geocoder\Query\GeocodeQuery;
20+
use Geocoder\Query\ReverseQuery;
21+
use PHPUnit\Framework\TestCase;
22+
use Psr\SimpleCache\CacheInterface;
23+
24+
/**
25+
* @author Tobias Nyholm <[email protected]>
26+
*/
27+
class ProviderCacheTest extends TestCase
28+
{
29+
/**
30+
* @var \PHPUnit_Framework_MockObject_MockObject|Provider
31+
*/
32+
private $providerMock;
33+
34+
/**
35+
* @var \PHPUnit_Framework_MockObject_MockObject|CacheInterface
36+
*/
37+
private $cacheMock;
38+
39+
protected function setUp()
40+
{
41+
parent::setUp();
42+
43+
$this->cacheMock = $this->getMockBuilder(CacheInterface::class)
44+
->setMethods(['get', 'set', 'delete', 'clear', 'setMultiple', 'getMultiple', 'deleteMultiple', 'has'])
45+
46+
->getMock();
47+
48+
$this->providerMock = $this->getMockBuilder(Provider::class)
49+
->setMethods(['getFoo', 'getName', 'geocodeQuery', 'reverseQuery'])
50+
->getMock();
51+
}
52+
53+
public function testName()
54+
{
55+
$this->providerMock->expects($this->once())
56+
->method('getName')
57+
->willReturn('foo');
58+
59+
$providerCache = new ProviderCache($this->providerMock, $this->cacheMock);
60+
$this->assertEquals('foo (cache)', $providerCache->getName());
61+
}
62+
63+
public function testMagicFunction()
64+
{
65+
$this->providerMock->expects($this->once())
66+
->method('getFoo')
67+
->willReturn('foo');
68+
69+
$providerCache = new ProviderCache($this->providerMock, $this->cacheMock);
70+
$this->assertEquals('foo', $providerCache->getFoo());
71+
}
72+
73+
public function testGeocodeMiss()
74+
{
75+
$query = GeocodeQuery::create('foo');
76+
$result = new AddressCollection([Address::createFromArray([])]);
77+
$ttl = 4711;
78+
79+
$this->cacheMock->expects($this->once())
80+
->method('get')
81+
->willReturn(null);
82+
83+
$this->cacheMock->expects($this->once())
84+
->method('set')
85+
->with($this->anything(), $result, $ttl)
86+
->willReturn(null);
87+
88+
$this->providerMock->expects($this->once())
89+
->method('geocodeQuery')
90+
->with($query)
91+
->willReturn($result);
92+
93+
$providerCache = new ProviderCache($this->providerMock, $this->cacheMock, $ttl);
94+
$providerCache->geocodeQuery($query);
95+
}
96+
97+
public function testGeocodeHit()
98+
{
99+
$query = GeocodeQuery::create('foo');
100+
$result = new AddressCollection([Address::createFromArray([])]);
101+
$ttl = 4711;
102+
103+
$this->cacheMock->expects($this->once())
104+
->method('get')
105+
->willReturn($result);
106+
107+
$this->cacheMock->expects($this->never())
108+
->method('set');
109+
110+
$this->providerMock->expects($this->never())
111+
->method('geocodeQuery');
112+
113+
$providerCache = new ProviderCache($this->providerMock, $this->cacheMock, $ttl);
114+
$providerCache->geocodeQuery($query);
115+
}
116+
117+
public function testReverseMiss()
118+
{
119+
$query = ReverseQuery::fromCoordinates(1, 2);
120+
$result = new AddressCollection([Address::createFromArray([])]);
121+
$ttl = 4711;
122+
123+
$this->cacheMock->expects($this->once())
124+
->method('get')
125+
->willReturn(null);
126+
127+
$this->cacheMock->expects($this->once())
128+
->method('set')
129+
->with($this->anything(), $result, $ttl)
130+
->willReturn(null);
131+
132+
$this->providerMock->expects($this->once())
133+
->method('reverseQuery')
134+
->with($query)
135+
->willReturn($result);
136+
137+
$providerCache = new ProviderCache($this->providerMock, $this->cacheMock, $ttl);
138+
$providerCache->reverseQuery($query);
139+
}
140+
141+
public function testReverseHit()
142+
{
143+
$query = ReverseQuery::fromCoordinates(1, 2);
144+
$result = new AddressCollection([Address::createFromArray([])]);
145+
$ttl = 4711;
146+
147+
$this->cacheMock->expects($this->once())
148+
->method('get')
149+
->willReturn($result);
150+
151+
$this->cacheMock->expects($this->never())
152+
->method('set');
153+
154+
$this->providerMock->expects($this->never())
155+
->method('reverseQuery');
156+
157+
$providerCache = new ProviderCache($this->providerMock, $this->cacheMock, $ttl);
158+
$providerCache->reverseQuery($query);
159+
}
160+
}

0 commit comments

Comments
 (0)