Skip to content

Commit c283de3

Browse files
committed
Search numbers available to purchase
This commit deprecates `Numbers::search` in favour of `Numbers::searchOwned` to make it clear when you're searching your own numbers or those which are available. When searching available numbers, there is a whitelist of supported query parameters, via https://developer.nexmo.com/api/developer/numbers#search-available-numbers * pattern * search_pattern * features * size * index Resolves #54
1 parent ef65339 commit c283de3

File tree

4 files changed

+130
-0
lines changed

4 files changed

+130
-0
lines changed

src/Numbers/Client.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,49 @@ public function get($number = null)
8282
return $items[0];
8383
}
8484

85+
/**
86+
* @param null|string $number
87+
* @return array []Number
88+
* @deprecated Use `searchOwned` instead
89+
*/
8590
public function search($number = null)
91+
{
92+
return $this->searchOwned($number);
93+
}
94+
95+
public function searchAvailable($country, $options = [])
96+
{
97+
$query = [
98+
'country' => $country
99+
];
100+
101+
// These are all optional parameters
102+
$possibleParameters = [
103+
'pattern',
104+
'search_pattern',
105+
'features',
106+
'size',
107+
'index'
108+
];
109+
110+
foreach ($possibleParameters as $param) {
111+
if (isset($options[$param])) {
112+
$query[$param] = $options[$param];
113+
}
114+
}
115+
116+
$request = new Request(
117+
\Nexmo\Client::BASE_REST . '/number/search?' . http_build_query($query),
118+
'GET',
119+
'php://temp'
120+
);
121+
122+
$response = $this->client->send($request);
123+
124+
return $this->handleNumberSearchResult($response, null);
125+
}
126+
127+
public function searchOwned($number = null)
86128
{
87129
$queryString = '';
88130
if ($number !== null) {
@@ -102,7 +144,11 @@ public function search($number = null)
102144
);
103145

104146
$response = $this->client->send($request);
147+
return $this->handleNumberSearchResult($response, $number);
148+
}
105149

150+
private function handleNumberSearchResult($response, $number)
151+
{
106152
if($response->getStatusCode() != '200'){
107153
throw $this->getException($response);
108154
}

test/Numbers/ClientTest.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,58 @@ public function testListNumbers()
178178
$this->assertSame('14155550101', $numbers[1]->getId());
179179
}
180180

181+
public function testSearchAvailablePassesThroughWhitelistedOptions()
182+
{
183+
184+
$allowedOptions = [
185+
'pattern' => 'one',
186+
'search_pattern' => '2',
187+
'features' => 'SMS,VOICE',
188+
'size' => '100',
189+
'index' => '19'
190+
];
191+
$invalidOptions = ['foo' => 'bananas'];
192+
193+
$options = array_merge($allowedOptions, $invalidOptions);
194+
195+
$this->nexmoClient->send(Argument::that(function(RequestInterface $request) use ($allowedOptions, $invalidOptions){
196+
$this->assertEquals('/number/search', $request->getUri()->getPath());
197+
$this->assertEquals('rest.nexmo.com', $request->getUri()->getHost());
198+
$this->assertEquals('GET', $request->getMethod());
199+
200+
// Things that are whitelisted should be shown
201+
foreach ($allowedOptions as $name => $value) {
202+
$this->assertRequestQueryContains($name, $value, $request);
203+
}
204+
205+
// Anything else should be dropped
206+
foreach ($invalidOptions as $name => $value) {
207+
$this->assertRequestQueryNotContains($name, $value, $request);
208+
}
209+
return true;
210+
}))->willReturn($this->getResponse('available-numbers'));
211+
212+
$this->numberClient->searchAvailable('US', $options);
213+
}
214+
215+
public function testSearchAvailableReturnsNumberList()
216+
{
217+
$this->nexmoClient->send(Argument::that(function(RequestInterface $request){
218+
$this->assertEquals('/number/search', $request->getUri()->getPath());
219+
$this->assertEquals('rest.nexmo.com', $request->getUri()->getHost());
220+
$this->assertEquals('GET', $request->getMethod());
221+
return true;
222+
}))->willReturn($this->getResponse('available-numbers'));
223+
224+
$numbers = $this->numberClient->searchAvailable('US');
225+
226+
$this->assertInternalType('array', $numbers);
227+
$this->assertInstanceOf('Nexmo\Numbers\Number', $numbers[0]);
228+
$this->assertInstanceOf('Nexmo\Numbers\Number', $numbers[1]);
229+
230+
$this->assertSame('14155550100', $numbers[0]->getId());
231+
$this->assertSame('14155550101', $numbers[1]->getId());
232+
}
181233

182234
public function testPurchaseNumberWithNumberObject()
183235
{
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"count": 94441,
3+
"numbers": [
4+
{
5+
"country": "US",
6+
"msisdn": "14155550100",
7+
"cost": "0.67",
8+
"type": "mobile-lvn",
9+
"features": [
10+
"VOICE",
11+
"SMS"
12+
]
13+
},
14+
{
15+
"country": "US",
16+
"msisdn": "14155550101",
17+
"cost": "0.67",
18+
"type": "mobile-lvn",
19+
"features": [
20+
"VOICE"
21+
]
22+
}
23+
]
24+
}

test/Psr7AssertionTrait.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ public static function assertRequestUrl($host, $path, $method, RequestInterface
4242
self::assertEquals($method, $request->getMethod());
4343
}
4444

45+
public static function assertRequestQueryNotContains($key, $value, RequestInterface $request)
46+
{
47+
$query = $request->getUri()->getQuery();
48+
$params = [];
49+
parse_str($query, $params);
50+
self::assertArrayNotHasKey($key, $params, 'query string has key when it should not: ' . $key);
51+
}
52+
4553
public static function assertRequestQueryContains($key, $value, RequestInterface $request)
4654
{
4755
$query = $request->getUri()->getQuery();

0 commit comments

Comments
 (0)