Skip to content

Commit a7911e6

Browse files
authored
ANS-17342 add GetAllPostcodesRequest (#7)
1 parent b8fbebf commit a7911e6

File tree

9 files changed

+298
-1
lines changed

9 files changed

+298
-1
lines changed

src/Command/GetAllPostCodes.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Answear\SpeedyBundle\Command;
6+
7+
use Answear\SpeedyBundle\Client\Client;
8+
use Answear\SpeedyBundle\Client\RequestTransformer;
9+
use Answear\SpeedyBundle\Exception\MalformedResponseException;
10+
use Answear\SpeedyBundle\Request\GetAllPostCodesRequest;
11+
use Answear\SpeedyBundle\Response\GetAllPostCodesResponse;
12+
13+
class GetAllPostCodes extends AbstractCommand
14+
{
15+
private Client $client;
16+
private RequestTransformer $transformer;
17+
18+
public function __construct(Client $client, RequestTransformer $transformer)
19+
{
20+
$this->client = $client;
21+
$this->transformer = $transformer;
22+
}
23+
24+
public function getAllPostCodes(GetAllPostCodesRequest $request): GetAllPostCodesResponse
25+
{
26+
$httpRequest = $this->transformer->transform($request);
27+
$response = $this->client->request($httpRequest);
28+
29+
try {
30+
$result = GetAllPostCodesResponse::fromCsv($response->getBody()->getContents());
31+
} catch (\Throwable $throwable) {
32+
throw new MalformedResponseException($throwable->getMessage(), $response, $throwable);
33+
}
34+
35+
return $result;
36+
}
37+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Answear\SpeedyBundle\Request;
6+
7+
class GetAllPostCodesRequest extends Request
8+
{
9+
private const ENDPOINT = '/location/postcode/csv';
10+
private const HTTP_METHOD = 'POST';
11+
12+
private int $countryId;
13+
14+
public function __construct(int $countryId)
15+
{
16+
$this->countryId = $countryId;
17+
}
18+
19+
public function getEndpoint(): string
20+
{
21+
return self::ENDPOINT . '/' . $this->countryId;
22+
}
23+
24+
public function getMethod(): string
25+
{
26+
return self::HTTP_METHOD;
27+
}
28+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Answear\SpeedyBundle\Response;
6+
7+
use Answear\SpeedyBundle\Response\Struct\PostCode;
8+
use Answear\SpeedyBundle\Response\Struct\PostCodeCollection;
9+
use Answear\SpeedyBundle\Service\CsvUtil;
10+
11+
class GetAllPostCodesResponse
12+
{
13+
public PostCodeCollection $postCodes;
14+
15+
public function __construct(PostCodeCollection $postCodes)
16+
{
17+
$this->postCodes = $postCodes;
18+
}
19+
20+
public function getPostCodes(): PostCodeCollection
21+
{
22+
return $this->postCodes;
23+
}
24+
25+
public static function fromCsv(string $csv): self
26+
{
27+
$file = CsvUtil::parseCsvStringToSplFileObject($csv);
28+
29+
$collection = [];
30+
foreach ($file as $i => $row) {
31+
if (0 === $i) {
32+
continue;
33+
}
34+
35+
$postCode = new PostCode();
36+
$postCode->postCode = $row[0];
37+
$postCode->siteId = (int) $row[1];
38+
39+
$collection[] = $postCode;
40+
}
41+
42+
return new self(
43+
new PostCodeCollection($collection)
44+
);
45+
}
46+
}

src/Response/Struct/PostCode.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Answear\SpeedyBundle\Response\Struct;
6+
7+
class PostCode
8+
{
9+
public string $postCode;
10+
public int $siteId;
11+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Answear\SpeedyBundle\Response\Struct;
6+
7+
use Webmozart\Assert\Assert;
8+
9+
class PostCodeCollection implements \Countable, \IteratorAggregate
10+
{
11+
/**
12+
* @var PostCode[]
13+
*/
14+
private array $postCodes;
15+
16+
public function __construct(array $postCodes)
17+
{
18+
Assert::allIsInstanceOf($postCodes, PostCode::class);
19+
20+
$this->postCodes = $postCodes;
21+
}
22+
23+
/**
24+
* @return \Traversable<PostCode>
25+
*/
26+
public function getIterator(): \Traversable
27+
{
28+
foreach ($this->postCodes as $key => $postCode) {
29+
yield $key => $postCode;
30+
}
31+
}
32+
33+
public function get($key): ?PostCode
34+
{
35+
return $this->postCodes[$key] ?? null;
36+
}
37+
38+
public function count(): int
39+
{
40+
return \count($this->postCodes);
41+
}
42+
}

src/Response/Struct/Site.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class Site
1717
public string $municipalityEn;
1818
public string $region;
1919
public string $regionEn;
20-
public string $postCode;
20+
public ?string $postCode;
2121
public int $addressNomenclature;
2222
public float $x;
2323
public float $y;

src/Service/CsvUtil.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Answear\SpeedyBundle\Service;
6+
7+
class CsvUtil
8+
{
9+
public static function parseCsvStringToSplFileObject(string $csv): \SplFileObject
10+
{
11+
$file = new \SplFileObject('php://temp', 'r+');
12+
$file->fwrite($csv);
13+
$file->rewind();
14+
$file->setFlags(\SplFileObject::READ_CSV | \SplFileObject::READ_AHEAD | \SplFileObject::SKIP_EMPTY | \SplFileObject::DROP_NEW_LINE);
15+
16+
return $file;
17+
}
18+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Answear\SpeedyBundle\Tests\Integration\Command;
6+
7+
use Answear\SpeedyBundle\Client\AuthenticationDecorator;
8+
use Answear\SpeedyBundle\Client\Client;
9+
use Answear\SpeedyBundle\Client\RequestTransformer;
10+
use Answear\SpeedyBundle\Client\Serializer;
11+
use Answear\SpeedyBundle\Command\GetAllPostCodes;
12+
use Answear\SpeedyBundle\Request\GetAllPostCodesRequest;
13+
use Answear\SpeedyBundle\Response\GetAllPostCodesResponse;
14+
use Answear\SpeedyBundle\Tests\ConfigProviderTrait;
15+
use Answear\SpeedyBundle\Tests\MockGuzzleTrait;
16+
use GuzzleHttp\Psr7\Response;
17+
use PHPUnit\Framework\TestCase;
18+
19+
class GetAllPostCodesTest extends TestCase
20+
{
21+
use ConfigProviderTrait;
22+
use MockGuzzleTrait;
23+
24+
private Client $client;
25+
26+
public function setUp(): void
27+
{
28+
parent::setUp();
29+
30+
$this->client = new Client($this->getConfiguration(), $this->setupGuzzleClient());
31+
}
32+
33+
/**
34+
* @test
35+
*/
36+
public function successfulGetAllPostcodes(): void
37+
{
38+
$command = $this->getCommand();
39+
$this->mockGuzzleResponse(new Response(200, [], $this->getSuccessfulBody()));
40+
41+
$response = $command->getAllPostCodes(new GetAllPostCodesRequest(100));
42+
43+
$this->assertCount(9, $response->getPostCodes());
44+
$this->assertPostCodes($response);
45+
}
46+
47+
/**
48+
* @test
49+
*/
50+
public function responseWithError(): void
51+
{
52+
$command = $this->getCommand();
53+
$this->mockGuzzleResponse(new Response(200, [], $this->getErrorBody()));
54+
55+
$response = $command->getAllPostCodes(new GetAllPostCodesRequest(100));
56+
57+
$this->assertCount(0, $response->getPostCodes());
58+
}
59+
60+
private function assertPostCodes(GetAllPostCodesResponse $response): void
61+
{
62+
$postCode = $response->getPostCodes()->get(0);
63+
64+
$this->assertSame(
65+
'1000,68134',
66+
implode(
67+
',',
68+
[
69+
$postCode->postCode,
70+
$postCode->siteId,
71+
],
72+
)
73+
);
74+
}
75+
76+
private function getCommand(): GetAllPostCodes
77+
{
78+
$transformer = new RequestTransformer(
79+
new Serializer(),
80+
new AuthenticationDecorator($this->getConfiguration()),
81+
$this->getConfiguration()
82+
);
83+
84+
return new GetAllPostCodes($this->client, $transformer);
85+
}
86+
87+
private function getSuccessfulBody(): string
88+
{
89+
return file_get_contents(__DIR__ . '/data/getAllPostCodesResponse.csv');
90+
}
91+
92+
private function getErrorBody(): string
93+
{
94+
return \json_encode(
95+
[
96+
'error' => [
97+
'context' => 'user.expired',
98+
'message' => 'Потребителят е с изтекла валидност',
99+
'id' => 'EE20210317183038558FZEMSKVR',
100+
'code' => 1,
101+
],
102+
]
103+
);
104+
}
105+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
postCode,siteId
2+
1000,68134
3+
1111,68134
4+
1113,68134
5+
1123,68134
6+
1124,68134
7+
1125,68134
8+
1137,55419
9+
1138,68134
10+
1142,68134

0 commit comments

Comments
 (0)