Skip to content

Commit

Permalink
Added a callable to decide what provider that should be used. (#731)
Browse files Browse the repository at this point in the history
* Added a callable to decide what provider that should be used.

* Applied changes from StyleCI
  • Loading branch information
Nyholm committed Jul 9, 2017
1 parent f7df9ad commit d0ebd1d
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 39 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,16 @@

The change log describes what is "Added", "Removed", "Changed" or "Fixed" between each release.

## Unreleased

### Added

- The constructor of `ProvierAggregator` will accept a callable that can decide what providers should be used for a specific query.

### Changed

- `ProvierAggregator::getProvider` is now private

## 4.0.0 - Beta 2

### Added
Expand Down
47 changes: 35 additions & 12 deletions ProviderAggregator.php
Expand Up @@ -38,28 +38,44 @@ class ProviderAggregator implements Geocoder
*/
private $limit;

/**
* A callable that decided what provider to use.
*
* @var callable
*/
private $decider;

/**
* @param int $limit
*/
public function __construct(int $limit = Geocoder::DEFAULT_RESULT_LIMIT)
public function __construct(int $limit = Geocoder::DEFAULT_RESULT_LIMIT, callable $decider = null)
{
$this->limit($limit);
$this->decider = $decider ?? __CLASS__.'::getProvider';
}

/**
* {@inheritdoc}
*/
public function geocodeQuery(GeocodeQuery $query): Collection
{
return $this->getProvider()->geocodeQuery($query);
if (null === $query->getLimit()) {
$query = $query->withLimit($this->limit);
}

return call_user_func($this->decider, $query, $this->providers, $this->provider)->geocodeQuery($query);
}

/**
* {@inheritdoc}
*/
public function reverseQuery(ReverseQuery $query): Collection
{
return $this->getProvider()->reverseQuery($query);
if (null === $query->getLimit()) {
$query = $query->withLimit($this->limit);
}

return call_user_func($this->decider, $query, $this->providers, $this->provider)->reverseQuery($query);
}

/**
Expand Down Expand Up @@ -167,22 +183,29 @@ public function getProviders(): array
}

/**
* Returns the current provider in use.
* Get a provider to use for this query.
*
* @param GeocodeQuery|ReverseQuery $query
* @param Provider[] $providers
* @param Provider $currentProvider
*
* @return Provider
*
* @throws \RuntimeException
* @throws ProviderNotRegistered
*/
protected function getProvider(): Provider
private static function getProvider($query, array $providers, Provider $currentProvider = null): Provider
{
if (null === $this->provider) {
if (0 === count($this->providers)) {
throw ProviderNotRegistered::noProviderRegistered();
}
if (null !== $currentProvider) {
return $currentProvider;
}

$this->using(key($this->providers));
if (0 === count($providers)) {
throw ProviderNotRegistered::noProviderRegistered();
}

return $this->provider;
// Take first
$key = key($providers);

return $providers[$key];
}
}
72 changes: 45 additions & 27 deletions Tests/ProviderAggregatorTest.php
Expand Up @@ -14,6 +14,8 @@

use Geocoder\Collection;
use Geocoder\Geocoder;
use Geocoder\Model\Address;
use Geocoder\Model\AddressCollection;
use Geocoder\Query\GeocodeQuery;
use Geocoder\Query\ReverseQuery;
use Geocoder\ProviderAggregator;
Expand All @@ -36,38 +38,49 @@ protected function setUp()
$this->geocoder = new ProviderAggregator();
}

public function testRegisterProvider()
public function testGeocode()
{
$provider = new MockProvider('test');
$this->geocoder->registerProvider($provider);

$this->assertSame($provider, NSA::invokeMethod($this->geocoder, 'getProvider'));
}
$provider1 = new MockProvider('test1');
$provider1->result = [Address::createFromArray(['providedBy' => 'p1'])];
$provider2 = new MockProvider('test2');
$provider2->result = [Address::createFromArray(['providedBy' => 'p2'])];

public function testRegisterProviders()
{
$provider = new MockProvider('test');
$this->geocoder->registerProviders([$provider]);
$this->geocoder->registerProvider($provider1);
$this->geocoder->registerProvider($provider2);

$this->assertSame($provider, NSA::invokeMethod($this->geocoder, 'getProvider'));
$result = $this->geocoder->geocode('foo');
$this->assertEquals('p1', $result->first()->getProvidedBy());
}

public function testUsing()
public function testReverse()
{
$provider1 = new MockProvider('test1');
$provider1->result = [Address::createFromArray(['providedBy' => 'p1'])];
$provider2 = new MockProvider('test2');
$this->geocoder->registerProviders([$provider1, $provider2]);
$provider2->result = [Address::createFromArray(['providedBy' => 'p2'])];

$this->geocoder->registerProvider($provider1);
$this->geocoder->registerProvider($provider2);
$this->geocoder->using('test2');

$this->assertSame($provider1, NSA::invokeMethod($this->geocoder, 'getProvider'));
$result = $this->geocoder->reverse(0.1, 0.2);
$this->assertEquals('p2', $result->first()->getProvidedBy());
}

$this->geocoder->using('test1');
$this->assertSame($provider1, NSA::invokeMethod($this->geocoder, 'getProvider'));
public function testRegisterProvider()
{
$provider = new MockProvider('test');
$this->geocoder->registerProvider($provider);

$this->geocoder->using('test2');
$this->assertSame($provider2, NSA::invokeMethod($this->geocoder, 'getProvider'));
$this->assertSame(['test' => $provider], NSA::getProperty($this->geocoder, 'providers'));
}

$this->geocoder->using('test1');
$this->assertSame($provider1, NSA::invokeMethod($this->geocoder, 'getProvider'));
public function testRegisterProviders()
{
$provider = new MockProvider('test');
$this->geocoder->registerProviders([$provider]);

$this->assertSame(['test' => $provider], NSA::getProperty($this->geocoder, 'providers'));
}

/**
Expand Down Expand Up @@ -109,19 +122,21 @@ public function testGetProviders()
*/
public function testGetProvider()
{
NSA::invokeMethod($this->geocoder, 'getProvider');
NSA::invokeMethod($this->geocoder, 'getProvider', GeocodeQuery::create('foo'), [], null);
$this->fail('getProvider() should throw an exception');
}

public function testGetProviderWithMultipleProvidersReturnsTheFirstOne()
{
$this->geocoder->registerProviders([
$providers = [
$provider1 = new MockProvider('test1'),
$provider2 = new MockProvider('test2'),
$provider3 = new MockProvider('test3'),
]);
];

$this->assertSame($provider1, NSA::invokeMethod($this->geocoder, 'getProvider'));
$query = GeocodeQuery::create('foo');
$this->assertSame($provider1, NSA::invokeMethod($this->geocoder, 'getProvider', $query, $providers, null));
$this->assertSame($provider2, NSA::invokeMethod($this->geocoder, 'getProvider', $query, $providers, $provider2));
}

public function testDefaultMaxResults()
Expand All @@ -134,19 +149,21 @@ class MockProvider implements Provider
{
protected $name;

public $result = [];

public function __construct($name)
{
$this->name = $name;
}

public function geocodeQuery(GeocodeQuery $query): Collection
{
return $this->returnResult([]);
return $this->returnResult();
}

public function reverseQuery(ReverseQuery $query): Collection
{
return $this->returnResult([]);
return $this->returnResult();
}

public function getName(): string
Expand All @@ -163,7 +180,8 @@ public function limit($limit)
return $this;
}

public function returnResult(array $data = [])
private function returnResult()
{
return new AddressCollection($this->result);
}
}

0 comments on commit d0ebd1d

Please sign in to comment.