Skip to content

Commit 0efa70c

Browse files
feat(Arguments): Added Array Stackable argument
Needed that to match IN filters of freshbooks queries They using non standard query params with the following format: ?search[statusids][]=1&search[statusids][]=2
1 parent b115173 commit 0efa70c

8 files changed

Lines changed: 217 additions & 10 deletions

File tree

src/Request/Api/BaseRequest.php

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
use ZEROSPAM\Framework\SDK\Request\Arguments\Mergeable\IMergeableArgument;
1515
use ZEROSPAM\Framework\SDK\Request\Arguments\Mergeable\Worker\ArgMerger;
1616
use ZEROSPAM\Framework\SDK\Request\Arguments\Stackable\IStackableArgument;
17+
use ZEROSPAM\Framework\SDK\Request\Arguments\Stackable\IStackableArrayArgument;
18+
use ZEROSPAM\Framework\SDK\Request\Arguments\Stackable\Worker\ArgArrayCollector;
1719
use ZEROSPAM\Framework\SDK\Request\Arguments\Stackable\Worker\ArgCollector;
1820
use ZEROSPAM\Framework\SDK\Request\Type\RequestType;
1921
use ZEROSPAM\Framework\SDK\Response\Api\IResponse;
@@ -43,6 +45,9 @@ abstract class BaseRequest implements IRequest
4345
*/
4446
private $stackableArguments = [];
4547

48+
/** @var ArgArrayCollector[] */
49+
private $stackableArrayArguments = [];
50+
4651
/**
4752
* @var \ZEROSPAM\Framework\SDK\Response\Api\IResponse
4853
*/
@@ -74,7 +79,16 @@ public function addArgument(IArgument $arg): IRequest
7479

7580
return $this;
7681
}
77-
if ($arg instanceof IStackableArgument) {
82+
83+
if ($arg instanceof IStackableArrayArgument) {
84+
if (!isset($this->stackableArrayArguments[$arg->getKey()])) {
85+
$this->stackableArrayArguments[$arg->getKey()] = new ArgArrayCollector();
86+
}
87+
88+
$this->stackableArrayArguments[$arg->getKey()]->addArgument($arg);
89+
90+
return $this;
91+
} elseif ($arg instanceof IStackableArgument) {
7892
if (!isset($this->stackableArguments[$arg->getKey()])) {
7993
$this->stackableArguments[$arg->getKey()] = new ArgCollector();
8094
}
@@ -185,7 +199,8 @@ public function toUri(): UriInterface
185199
*/
186200
final public function requestType(): RequestType
187201
{
188-
return $this->requestTypeOverride ?: $this->httpType();
202+
return $this->requestTypeOverride
203+
?: $this->httpType();
189204
}
190205

191206
/**
@@ -277,6 +292,11 @@ private function generateUrl(): string
277292
foreach ($this->stackableArguments as $key => $value) {
278293
$query[$key] = $value->toArray();
279294
}
295+
296+
foreach ($this->stackableArrayArguments as $key => $value) {
297+
$query[$key] = $value->toArray();
298+
}
299+
280300
$queryArg = http_build_query($query, null, '&', PHP_QUERY_RFC3986);
281301

282302
$fullUrl = $this->routeUrl() . '?' . preg_replace($re, $subst, $queryArg);

src/Request/Arguments/RequestArg.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,16 @@ class RequestArg implements IArgument
2222
/**
2323
* @var string
2424
*/
25-
private $key;
25+
protected $key;
26+
2627
/** @var string */
27-
private $value;
28+
protected $value;
2829

2930
/**
3031
* RequestArg constructor.
3132
*
32-
* @param string $key
33-
* @param string $value
33+
* @param string $key
34+
* @param string|array $value
3435
*/
3536
public function __construct($key, $value)
3637
{
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
/**
3+
* Created by PhpStorm.
4+
* User: pbb
5+
* Date: 25/09/18
6+
* Time: 9:40 AM
7+
*/
8+
9+
namespace ZEROSPAM\Framework\SDK\Request\Arguments\Stackable;
10+
11+
/**
12+
* Interface IStackableArrayArgument
13+
*
14+
* Contract for arguments using Freshbooks specific format: ex. ?search[statusids][]=1&search[statusids][]=2
15+
*
16+
* @package ZEROSPAM\Framework\SDK\Request\Arguments\Stackable
17+
*/
18+
interface IStackableArrayArgument extends ISubKeyedStackableArgument
19+
{
20+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
/**
3+
* Created by PhpStorm.
4+
* User: pbb
5+
* Date: 25/09/18
6+
* Time: 9:30 AM
7+
*/
8+
9+
namespace ZEROSPAM\Framework\SDK\Request\Arguments\Stackable;
10+
11+
12+
use ZEROSPAM\Framework\SDK\Request\Arguments\RequestArg;
13+
14+
/**
15+
* Class SubKeyedArrayStackableRequestArg
16+
*
17+
* Implementation for arguments using Freshbooks specific format: ex. ?search[statusids][]=1&search[statusids][]=2
18+
*
19+
* @package ZEROSPAM\Framework\SDK\Request\Arguments\Stackable
20+
*/
21+
class SubKeyedArrayStackableRequestArg extends RequestArg implements IStackableArrayArgument
22+
{
23+
/**
24+
* @var null|string
25+
*/
26+
private $subKey;
27+
28+
public function __construct(string $key, string $subKey, array $value)
29+
{
30+
parent::__construct($key, $value);
31+
$this->subKey = $subKey;
32+
}
33+
34+
/**
35+
* @return string
36+
*/
37+
public function getSubKey(): string
38+
{
39+
return $this->subKey;
40+
}
41+
42+
/**
43+
* @return float|int|mixed|string
44+
*/
45+
public function toPrimitive()
46+
{
47+
return $this->value;
48+
}
49+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
/**
3+
* Created by PhpStorm.
4+
* User: pbb
5+
* Date: 25/09/18
6+
* Time: 9:23 AM
7+
*/
8+
9+
namespace ZEROSPAM\Framework\SDK\Request\Arguments\Stackable\Worker;
10+
11+
12+
use ZEROSPAM\Framework\SDK\Request\Arguments\Stackable\IStackableArgument;
13+
use ZEROSPAM\Framework\SDK\Request\Arguments\Stackable\ISubKeyedStackableArgument;
14+
15+
class ArgArrayCollector extends ArgCollector
16+
{
17+
/**
18+
* @param IStackableArgument $argument
19+
*
20+
* @return $this|ArgCollector
21+
*/
22+
public function addArgument(IStackableArgument $argument)
23+
{
24+
if ($argument instanceof ISubKeyedStackableArgument) {
25+
$key = $argument->getSubKey();
26+
if (isset($this->args[$key])) {
27+
throw new \InvalidArgumentException("Can't override the subkey: $key");
28+
}
29+
} else {
30+
$key = $this->stackKey();
31+
}
32+
33+
$this->args[$key][$argument->getSubKey()] = $argument;
34+
35+
return $this;
36+
}
37+
38+
/**
39+
* @param IStackableArgument $argument
40+
*
41+
* @return $this|ArgCollector
42+
*/
43+
public function removeArgument(IStackableArgument $argument)
44+
{
45+
if ($argument instanceof ISubKeyedStackableArgument) {
46+
$key = $argument->getSubKey();
47+
} else {
48+
$key = $this->stackKey();
49+
}
50+
51+
unset($this->args[$key][$argument->getSubKey()]);
52+
if (empty($this->args[$key])) {
53+
unset($this->args[$key]);
54+
}
55+
56+
return $this;
57+
}
58+
}

src/Request/Arguments/Stackable/Worker/ArgCollector.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,20 @@ class ArgCollector implements Arrayable
1818
/**
1919
* @var IStackableArgument[][]
2020
*/
21-
private $args = [];
21+
protected $args = [];
2222

2323
/**
2424
* @var string
2525
*/
26-
private $stackKey;
26+
protected $stackKey;
2727

2828

2929
/**
3030
* Get the unique stack key
3131
*
3232
* @return string
3333
*/
34-
private function stackKey(): string
34+
protected function stackKey(): string
3535
{
3636
if ($this->stackKey) {
3737
return $this->stackKey;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
/**
3+
* Created by PhpStorm.
4+
* User: pbb
5+
* Date: 25/09/18
6+
* Time: 9:53 AM
7+
*/
8+
9+
namespace ZEROSPAM\Framework\SDK\Test\Base\Argument;
10+
11+
12+
use ZEROSPAM\Framework\SDK\Request\Arguments\Stackable\SubKeyedArrayStackableRequestArg;
13+
14+
class SearchArgumentArray extends SubKeyedArrayStackableRequestArg
15+
{
16+
/**
17+
* SearchArrayArgument constructor.
18+
*
19+
* @param string $searchKey
20+
* @param array $value
21+
*/
22+
public function __construct(string $searchKey, array $value)
23+
{
24+
parent::__construct('search', $searchKey, $value);
25+
}
26+
}

tests/src/Tests/Argument/StackableArgumentTest.php

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
namespace ZEROSPAM\Framework\SDK\Test\Tests\Argument;
1010

1111
use ZEROSPAM\Framework\SDK\Test\Base\Argument\IncludeStackableArg;
12+
use ZEROSPAM\Framework\SDK\Test\Base\Argument\SearchArgumentArray;
1213
use ZEROSPAM\Framework\SDK\Test\Base\Data\TestRequest;
1314
use ZEROSPAM\Framework\SDK\Test\Base\TestCase;
1415

@@ -34,7 +35,6 @@ public function add_argument_stack()
3435
*/
3536
public function remove_argument_stack()
3637
{
37-
$key = (new IncludeStackableArg('t'))->getKey();
3838
$request = new TestRequest();
3939
$request->addArgument(new IncludeStackableArg('test'))
4040
->addArgument(new IncludeStackableArg('superTest'))
@@ -90,4 +90,37 @@ public function testStackableInUrl(): void
9090
->processRequest($request);
9191
$this->validateQuery($client, 'include[]=test', 'include[]=test2');
9292
}
93+
94+
/**
95+
*
96+
*/
97+
public function testArrayStackableInUrl(): void
98+
{
99+
$client = $this->preSuccess([]);
100+
101+
$request = new TestRequest();
102+
$request->addArgument(new SearchArgumentArray('statusids', [1, 2]));
103+
$client->getOAuthTestClient()
104+
->processRequest($request);
105+
$this->validateQuery($client, 'search[statusids][]=1', 'search[statusids][]=2');
106+
}
107+
108+
/**
109+
*
110+
*/
111+
public function removeArrayStackable(): void
112+
{
113+
$client = $this->preSuccess([]);
114+
115+
$request = new TestRequest();
116+
$request->addArgument(new SearchArgumentArray('statusids', [1]))
117+
->removeArgument(new SearchArgumentArray('statusids', [1]));
118+
119+
$client->getOAuthTestClient()
120+
->processRequest($request);
121+
122+
$uri = $request->toUri();
123+
124+
$this->assertNotContains('search[statusids][]=1', $uri->getQuery());
125+
}
93126
}

0 commit comments

Comments
 (0)