Skip to content

Commit ef7e8a0

Browse files
author
Lorna Jane Mitchell
authored
Merge pull request #200 from Nexmo/numbers-application-search
Added additional parameters to search numbers by application
2 parents f1492e8 + 3963405 commit ef7e8a0

File tree

3 files changed

+139
-43
lines changed

3 files changed

+139
-43
lines changed

README.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ You can list the numbers owned by your account and optionally include filtering:
522522
* `1` - the number includes `pattern`
523523
* `2` - the number ends with `pattern`
524524

525-
```
525+
```php
526526
$client->numbers()->searchOwned(
527527
'234',
528528
[
@@ -531,6 +531,31 @@ $client->numbers()->searchOwned(
531531
);
532532
```
533533

534+
`has_application`:
535+
* `true` - The number is attached to an application
536+
* `false` - The number is not attached to an application
537+
538+
```php
539+
$client->numbers()->searchOwned(
540+
null,
541+
[
542+
"has_application" => true,
543+
]
544+
);
545+
```
546+
547+
`application_id`:
548+
* Supply an application ID to get all of the numbers associated with the requestion application
549+
550+
```php
551+
$client->numbers()->searchOwned(
552+
null,
553+
[
554+
"application_id" => "66c04cea-68b2-45e4-9061-3fd847d627b8",
555+
]
556+
);
557+
```
558+
534559
### Search Available Numbers
535560

536561
You can search for numbers available to purchase in a specific country:

src/Numbers/Client.php

Lines changed: 69 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -92,27 +92,28 @@ public function search($number = null)
9292
return $this->searchOwned($number);
9393
}
9494

95-
public function searchAvailable($country, $options = [])
95+
/**
96+
* Returns a set of numbers for the specified country
97+
*
98+
* @param string $country The two character country code in ISO 3166-1 alpha-2 format
99+
* @param array $options Additional options, see https://developer.nexmo.com/api/numbers#getAvailableNumbers
100+
*/
101+
public function searchAvailable(string $country, array $options = []) : array
96102
{
97-
$query = [
98-
'country' => $country
99-
];
103+
$options['country'] = $country;
100104

101105
// These are all optional parameters
102106
$possibleParameters = [
103-
'pattern',
104-
'search_pattern',
105-
'features',
106-
'size',
107-
'type',
108-
'index'
107+
'country' => 'string',
108+
'pattern' => 'string',
109+
'search_pattern' => 'integer',
110+
'features' => 'array',
111+
'size' => 'integer',
112+
'type' => 'string',
113+
'index' => 'integer'
109114
];
110115

111-
foreach ($possibleParameters as $param) {
112-
if (isset($options[$param])) {
113-
$query[$param] = $options[$param];
114-
}
115-
}
116+
$query = $this->parseParameters($possibleParameters, $options);
116117

117118
$request = new Request(
118119
$this->client->getRestUrl() . '/number/search?' . http_build_query($query),
@@ -125,30 +126,33 @@ public function searchAvailable($country, $options = [])
125126
return $this->handleNumberSearchResult($response, null);
126127
}
127128

128-
public function searchOwned($number = null, $options = [])
129+
/**
130+
* Returns a set of numbers for the specified country
131+
*
132+
* @param string|Number $number Number to search for, if any
133+
* @param array $options Additional options, see https://developer.nexmo.com/api/numbers#getOwnedNumbers
134+
*/
135+
public function searchOwned($number = null, array $options = []) : array
129136
{
130-
$query = [];
131137
if ($number !== null) {
132138
if ($number instanceof Number) {
133-
$query = ['pattern' => $number->getId()];
139+
$options['pattern'] = $number->getId();
134140
} else {
135-
$query = ['pattern' => $number];
141+
$options['pattern'] = $number;
136142
}
137143
}
138144

139145
// These are all optional parameters
140146
$possibleParameters = [
141-
'search_pattern',
142-
'size',
143-
'index'
147+
'pattern' => 'string',
148+
'search_pattern' => 'integer',
149+
'size' => 'integer',
150+
'index' => 'integer',
151+
'has_application' => 'boolean',
152+
'application_id' => 'string'
144153
];
145154

146-
foreach ($options as $param => $value) {
147-
if (!in_array($param, $possibleParameters)) {
148-
throw new Exception\Request("Unknown option: '".$param."'");
149-
}
150-
$query[$param] = $value;
151-
}
155+
$query = $this->parseParameters($possibleParameters, $options);
152156

153157
$queryString = http_build_query($query);
154158

@@ -159,9 +163,46 @@ public function searchOwned($number = null, $options = [])
159163
);
160164

161165
$response = $this->client->send($request);
166+
162167
return $this->handleNumberSearchResult($response, $number);
163168
}
164169

170+
/**
171+
* Checks and converts parameters into appropriate values for the API
172+
*/
173+
protected function parseParameters(array $possibleParameters, array $data = []) : array
174+
{
175+
$query = [];
176+
foreach ($data as $param => $value) {
177+
if (!array_key_exists($param, $possibleParameters)) {
178+
throw new Exception\Request("Unknown option: '" . $param . "'");
179+
}
180+
181+
switch ($possibleParameters[$param]) {
182+
case 'boolean':
183+
$value = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
184+
if (is_null($value)) {
185+
throw new Exception\Request("Invalid value: '" . $param . "' must be a boolean value");
186+
}
187+
$value = $value ? "true" : "false";
188+
break;
189+
case 'integer':
190+
$value = filter_var($value, FILTER_VALIDATE_INT);
191+
if ($value === false) {
192+
throw new Exception\Request("Invalid value: '" . $param . "' must be an integer");
193+
}
194+
break;
195+
default:
196+
// No-op, take the value whatever it is
197+
break;
198+
}
199+
200+
$query[$param] = $value;
201+
}
202+
203+
return $query;
204+
}
205+
165206
private function handleNumberSearchResult($response, $number)
166207
{
167208
if ($response->getStatusCode() != '200') {

test/Numbers/ClientTest.php

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Nexmo\Numbers\Client;
1212
use Nexmo\Numbers\Number;
1313
use Nexmo\Client\Exception;
14+
use Nexmo\Client\Exception\Request;
1415
use NexmoTest\Psr7AssertionTrait;
1516
use Prophecy\Argument;
1617
use Psr\Http\Message\RequestInterface;
@@ -182,38 +183,41 @@ public function testListNumbers()
182183

183184
public function testSearchAvailablePassesThroughWhitelistedOptions()
184185
{
185-
186-
$allowedOptions = [
186+
$options = [
187187
'pattern' => 'one',
188188
'search_pattern' => '2',
189189
'features' => 'SMS,VOICE',
190190
'size' => '100',
191191
'index' => '19'
192192
];
193-
$invalidOptions = ['foo' => 'bananas'];
194-
195-
$options = array_merge($allowedOptions, $invalidOptions);
196193

197-
$this->nexmoClient->send(Argument::that(function(RequestInterface $request) use ($allowedOptions, $invalidOptions){
194+
$this->nexmoClient->send(Argument::that(function (RequestInterface $request) use ($options) {
198195
$this->assertEquals('/number/search', $request->getUri()->getPath());
199196
$this->assertEquals('rest.nexmo.com', $request->getUri()->getHost());
200197
$this->assertEquals('GET', $request->getMethod());
201198

202199
// Things that are whitelisted should be shown
203-
foreach ($allowedOptions as $name => $value) {
200+
foreach ($options as $name => $value) {
204201
$this->assertRequestQueryContains($name, $value, $request);
205202
}
206203

207-
// Anything else should be dropped
208-
foreach ($invalidOptions as $name => $value) {
209-
$this->assertRequestQueryNotContains($name, $request);
210-
}
211204
return true;
212205
}))->willReturn($this->getResponse('available-numbers'));
213206

214207
$this->numberClient->searchAvailable('US', $options);
215208
}
216209

210+
/**
211+
* Make sure that unknown parameters fail validation
212+
*/
213+
public function testUnknownParameterValueForSearchThrowsException()
214+
{
215+
$this->expectException(Request::class);
216+
$this->expectExceptionMessage("Unknown option: 'foo'");
217+
218+
$this->numberClient->searchAvailable('US', ['foo' => 'bar']);
219+
}
220+
217221
public function testSearchAvailableReturnsNumberList()
218222
{
219223
$this->nexmoClient->send(Argument::that(function(RequestInterface $request){
@@ -264,18 +268,22 @@ public function testSearchOwnedErrorsOnUnknownSearchParameters()
264268

265269
public function testSearchOwnedPassesInAllowedAdditionalParameters()
266270
{
267-
$this->nexmoClient->send(Argument::that(function(RequestInterface $request){
271+
$this->nexmoClient->send(Argument::that(function (RequestInterface $request) {
268272
$this->assertEquals('/account/numbers', $request->getUri()->getPath());
269273
$this->assertEquals('rest.nexmo.com', $request->getUri()->getHost());
270274
$this->assertEquals('GET', $request->getMethod());
271-
$this->assertEquals('pattern=1415550100&index=1&size=100&search_pattern=0', $request->getUri()->getQuery());
275+
$this->assertEquals(
276+
'index=1&size=100&search_pattern=0&has_application=false&pattern=1415550100',
277+
$request->getUri()->getQuery()
278+
);
272279
return true;
273280
}))->willReturn($this->getResponse('single'));
274281

275282
$this->numberClient->searchOwned('1415550100', [
276283
'index' => 1,
277284
'size' => '100',
278-
'search_pattern' => 0
285+
'search_pattern' => 0,
286+
'has_application' => false,
279287
]);
280288
}
281289

@@ -422,6 +430,28 @@ public function testCancelNumberError()
422430
$this->numberClient->cancel($num);
423431
}
424432

433+
/**
434+
* Make sure that integer values that fail validation throw properly
435+
*/
436+
public function testInvalidIntegerValueForSearchThrowsException()
437+
{
438+
$this->expectException(Request::class);
439+
$this->expectExceptionMessage("Invalid value: 'size' must be an integer");
440+
441+
$this->numberClient->searchOwned(null, ['size' => 'bob']);
442+
}
443+
444+
/**
445+
* Make sure that boolean values that fail validation throw properly
446+
*/
447+
public function testInvalidBooleanValueForSearchThrowsException()
448+
{
449+
$this->expectException(Request::class);
450+
$this->expectExceptionMessage("Invalid value: 'has_application' must be a boolean value");
451+
452+
$this->numberClient->searchOwned(null, ['has_application' => 'bob']);
453+
}
454+
425455
/**
426456
* Get the API response we'd expect for a call to the API.
427457
*

0 commit comments

Comments
 (0)