Skip to content

Commit

Permalink
ANS-17342 add GetAllPostcodesRequest (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
ropczan authored Jun 17, 2024
1 parent b8fbebf commit a7911e6
Show file tree
Hide file tree
Showing 9 changed files with 298 additions and 1 deletion.
37 changes: 37 additions & 0 deletions src/Command/GetAllPostCodes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace Answear\SpeedyBundle\Command;

use Answear\SpeedyBundle\Client\Client;
use Answear\SpeedyBundle\Client\RequestTransformer;
use Answear\SpeedyBundle\Exception\MalformedResponseException;
use Answear\SpeedyBundle\Request\GetAllPostCodesRequest;
use Answear\SpeedyBundle\Response\GetAllPostCodesResponse;

class GetAllPostCodes extends AbstractCommand
{
private Client $client;
private RequestTransformer $transformer;

public function __construct(Client $client, RequestTransformer $transformer)
{
$this->client = $client;
$this->transformer = $transformer;
}

public function getAllPostCodes(GetAllPostCodesRequest $request): GetAllPostCodesResponse
{
$httpRequest = $this->transformer->transform($request);
$response = $this->client->request($httpRequest);

try {
$result = GetAllPostCodesResponse::fromCsv($response->getBody()->getContents());
} catch (\Throwable $throwable) {
throw new MalformedResponseException($throwable->getMessage(), $response, $throwable);
}

return $result;
}
}
28 changes: 28 additions & 0 deletions src/Request/GetAllPostCodesRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace Answear\SpeedyBundle\Request;

class GetAllPostCodesRequest extends Request
{
private const ENDPOINT = '/location/postcode/csv';
private const HTTP_METHOD = 'POST';

private int $countryId;

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

public function getEndpoint(): string
{
return self::ENDPOINT . '/' . $this->countryId;
}

public function getMethod(): string
{
return self::HTTP_METHOD;
}
}
46 changes: 46 additions & 0 deletions src/Response/GetAllPostCodesResponse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

declare(strict_types=1);

namespace Answear\SpeedyBundle\Response;

use Answear\SpeedyBundle\Response\Struct\PostCode;
use Answear\SpeedyBundle\Response\Struct\PostCodeCollection;
use Answear\SpeedyBundle\Service\CsvUtil;

class GetAllPostCodesResponse
{
public PostCodeCollection $postCodes;

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

public function getPostCodes(): PostCodeCollection
{
return $this->postCodes;
}

public static function fromCsv(string $csv): self
{
$file = CsvUtil::parseCsvStringToSplFileObject($csv);

$collection = [];
foreach ($file as $i => $row) {
if (0 === $i) {
continue;
}

$postCode = new PostCode();
$postCode->postCode = $row[0];
$postCode->siteId = (int) $row[1];

$collection[] = $postCode;
}

return new self(
new PostCodeCollection($collection)
);
}
}
11 changes: 11 additions & 0 deletions src/Response/Struct/PostCode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Answear\SpeedyBundle\Response\Struct;

class PostCode
{
public string $postCode;
public int $siteId;
}
42 changes: 42 additions & 0 deletions src/Response/Struct/PostCodeCollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

declare(strict_types=1);

namespace Answear\SpeedyBundle\Response\Struct;

use Webmozart\Assert\Assert;

class PostCodeCollection implements \Countable, \IteratorAggregate
{
/**
* @var PostCode[]
*/
private array $postCodes;

public function __construct(array $postCodes)
{
Assert::allIsInstanceOf($postCodes, PostCode::class);

$this->postCodes = $postCodes;
}

/**
* @return \Traversable<PostCode>
*/
public function getIterator(): \Traversable
{
foreach ($this->postCodes as $key => $postCode) {
yield $key => $postCode;
}
}

public function get($key): ?PostCode
{
return $this->postCodes[$key] ?? null;
}

public function count(): int
{
return \count($this->postCodes);
}
}
2 changes: 1 addition & 1 deletion src/Response/Struct/Site.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class Site
public string $municipalityEn;
public string $region;
public string $regionEn;
public string $postCode;
public ?string $postCode;
public int $addressNomenclature;
public float $x;
public float $y;
Expand Down
18 changes: 18 additions & 0 deletions src/Service/CsvUtil.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace Answear\SpeedyBundle\Service;

class CsvUtil
{
public static function parseCsvStringToSplFileObject(string $csv): \SplFileObject
{
$file = new \SplFileObject('php://temp', 'r+');
$file->fwrite($csv);
$file->rewind();
$file->setFlags(\SplFileObject::READ_CSV | \SplFileObject::READ_AHEAD | \SplFileObject::SKIP_EMPTY | \SplFileObject::DROP_NEW_LINE);

return $file;
}
}
105 changes: 105 additions & 0 deletions tests/Integration/Command/GetAllPostCodesTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<?php

declare(strict_types=1);

namespace Answear\SpeedyBundle\Tests\Integration\Command;

use Answear\SpeedyBundle\Client\AuthenticationDecorator;
use Answear\SpeedyBundle\Client\Client;
use Answear\SpeedyBundle\Client\RequestTransformer;
use Answear\SpeedyBundle\Client\Serializer;
use Answear\SpeedyBundle\Command\GetAllPostCodes;
use Answear\SpeedyBundle\Request\GetAllPostCodesRequest;
use Answear\SpeedyBundle\Response\GetAllPostCodesResponse;
use Answear\SpeedyBundle\Tests\ConfigProviderTrait;
use Answear\SpeedyBundle\Tests\MockGuzzleTrait;
use GuzzleHttp\Psr7\Response;
use PHPUnit\Framework\TestCase;

class GetAllPostCodesTest extends TestCase
{
use ConfigProviderTrait;
use MockGuzzleTrait;

private Client $client;

public function setUp(): void
{
parent::setUp();

$this->client = new Client($this->getConfiguration(), $this->setupGuzzleClient());
}

/**
* @test
*/
public function successfulGetAllPostcodes(): void
{
$command = $this->getCommand();
$this->mockGuzzleResponse(new Response(200, [], $this->getSuccessfulBody()));

$response = $command->getAllPostCodes(new GetAllPostCodesRequest(100));

$this->assertCount(9, $response->getPostCodes());
$this->assertPostCodes($response);
}

/**
* @test
*/
public function responseWithError(): void
{
$command = $this->getCommand();
$this->mockGuzzleResponse(new Response(200, [], $this->getErrorBody()));

$response = $command->getAllPostCodes(new GetAllPostCodesRequest(100));

$this->assertCount(0, $response->getPostCodes());
}

private function assertPostCodes(GetAllPostCodesResponse $response): void
{
$postCode = $response->getPostCodes()->get(0);

$this->assertSame(
'1000,68134',
implode(
',',
[
$postCode->postCode,
$postCode->siteId,
],
)
);
}

private function getCommand(): GetAllPostCodes
{
$transformer = new RequestTransformer(
new Serializer(),
new AuthenticationDecorator($this->getConfiguration()),
$this->getConfiguration()
);

return new GetAllPostCodes($this->client, $transformer);
}

private function getSuccessfulBody(): string
{
return file_get_contents(__DIR__ . '/data/getAllPostCodesResponse.csv');
}

private function getErrorBody(): string
{
return \json_encode(
[
'error' => [
'context' => 'user.expired',
'message' => 'Потребителят е с изтекла валидност',
'id' => 'EE20210317183038558FZEMSKVR',
'code' => 1,
],
]
);
}
}
10 changes: 10 additions & 0 deletions tests/Integration/Command/data/getAllPostCodesResponse.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
postCode,siteId
1000,68134
1111,68134
1113,68134
1123,68134
1124,68134
1125,68134
1137,55419
1138,68134
1142,68134

0 comments on commit a7911e6

Please sign in to comment.