From d718cf32b91f326209b3b415eca0daf28d143a31 Mon Sep 17 00:00:00 2001 From: Yevhenii Kovalenko Date: Tue, 17 Sep 2024 16:07:05 +0200 Subject: [PATCH 1/3] Change endpoint --- .php-cs-fixer.php | 2 +- README.md | 31 ++++++++- composer.json | 29 ++++---- src/Client/Client.php | 29 +++++++- src/Client/RequestTransformer.php | 14 ++-- src/ConfigProvider.php | 1 - src/DTO/AddressDTO.php | 43 ++++++++++++ src/DTO/DrawerCollection.php | 4 +- src/DTO/DrawerDTO.php | 2 +- src/DTO/PickupPointDTO.php | 56 +++++++-------- src/DTO/ScheduleCollection.php | 10 +-- src/DTO/ScheduleDTO.php | 4 +- .../AnswearFanCourierExtension.php | 1 - src/DependencyInjection/Configuration.php | 3 +- src/Request/GetPickupPointsRequest.php | 6 +- src/Request/LoginRequest.php | 32 +++++++++ src/Request/RequestInterface.php | 2 +- src/Resources/config/services.yaml | 9 +-- src/Response/GetPickupPointsResponse.php | 19 +++-- src/Response/LoginResponse.php | 27 ++++++++ .../Normalizer/EmptyObjectNormalizer.php | 35 ++++++++++ src/Serializer/Serializer.php | 48 +++++++++++++ src/Service/PickupPointService.php | 2 + .../DependencyInjection/ConfigurationTest.php | 23 ++----- .../Service/PickupPointServiceTest.php | 67 ++++++++++++++---- .../Service/data/exampleLoginResponse.json | 7 ++ .../data/examplePickupPointsResponse.json | 69 +++++++++++++++++++ .../Service/data/exampleResponse.json | 59 ---------------- 28 files changed, 456 insertions(+), 178 deletions(-) create mode 100644 src/DTO/AddressDTO.php create mode 100644 src/Request/LoginRequest.php create mode 100644 src/Response/LoginResponse.php create mode 100644 src/Serializer/Normalizer/EmptyObjectNormalizer.php create mode 100644 src/Serializer/Serializer.php create mode 100644 tests/Integration/Service/data/exampleLoginResponse.json create mode 100644 tests/Integration/Service/data/examplePickupPointsResponse.json delete mode 100644 tests/Integration/Service/data/exampleResponse.json diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index c51474e..2393b5a 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -20,7 +20,7 @@ 'strict_param' => false, 'array_syntax' => ['syntax' => 'short'], 'concat_space' => ['spacing' => 'one'], - 'phpdoc_align' => [], + 'phpdoc_align' => ['align' => 'left'], 'phpdoc_summary' => false, 'void_return' => false, 'phpdoc_var_without_name' => false, diff --git a/README.md b/README.md index f224c03..8b4ce2f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # FanCourier bundle FanCourier integration for Symfony. -Documentation of the API can be found here: https://github.com/FAN-Courier/API-Docs +Documentation of the API can be found here: https://www.fancourier.ro/wp-content/uploads/2023/07/EN_FANCourier_API-2.0-160523.pdf ## Installation @@ -19,17 +19,42 @@ should be added automatically to your `config/bundles.php` file by Symfony Flex. ```yaml # config/packages/answear_fancourier.yaml answear_fan_courier: - clientId: yourClientId username: yourUsername password: yourPassword apiUrl: apiUrl logger: customLogger #default: null ``` + Logger service must implement Psr\Log\LoggerInterface interface. ## Usage -### TODO +### Get pickup points + +```php +namespace App\Service\PickupPointsImporter; + +use Answear\FanCourierBundle\Service\PickupPointService; + +class FanCourierImport +{ + public function __construct( + private PickupPointService $pickupPointService, + ) { + } + + /** + * @return PickupPointDTO[] + */ + public function getPickupPoints(): array + { + return $this->pickupPointService->getAll(); + } +} + +``` + +Above `getPickupPoints` method will return an array of `Answear\FanCourierBundle\DTO\PickupPointDTO` objects. Final notes ------------ diff --git a/composer.json b/composer.json index 03d24aa..fb563c2 100755 --- a/composer.json +++ b/composer.json @@ -4,24 +4,25 @@ "type": "symfony-bundle", "license": "MIT", "require": { - "php": ">=8.1", + "php": ">=8.1|^8.2", "ext-json": "*", - "guzzlehttp/guzzle": "^6.0 || ^7.0", - "psr/log": "^1.1", - "symfony/http-kernel": "^6.1", - "symfony/property-info": "^6.1", - "symfony/serializer": "^6.1", - "webmozart/assert": "^1.3" + "guzzlehttp/guzzle": "^6.5|^7.9.2", + "psr/log": "^1.1.4", + "symfony/http-kernel": "6.4.*", + "symfony/property-access": "6.4.*", + "symfony/property-info": "6.4.*", + "symfony/serializer": "6.4.*", + "webmozart/assert": "^1.11" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.4", - "matthiasnoback/symfony-config-test": "^5.0.0", - "phpro/grumphp": "^1.5.0", - "phpstan/phpstan": "^1.4", - "phpstan/phpstan-webmozart-assert": "^1.2", - "phpunit/phpunit": "10.4.*", + "friendsofphp/php-cs-fixer": "^3.63.2", + "matthiasnoback/symfony-config-test": "^5.2", + "phpro/grumphp": "^2.7.0", + "phpstan/phpstan": "^1.12", + "phpstan/phpstan-webmozart-assert": "^1.2.10", + "phpunit/phpunit": "^10.5.30", "roave/security-advisories": "dev-master", - "symfony/phpunit-bridge": "6.3.*" + "symfony/phpunit-bridge": "6.4.*" }, "autoload": { "psr-4": { diff --git a/src/Client/Client.php b/src/Client/Client.php index ea1cac1..55bdc03 100644 --- a/src/Client/Client.php +++ b/src/Client/Client.php @@ -2,10 +2,13 @@ namespace Answear\FanCourierBundle\Client; +use Answear\FanCourierBundle\ConfigProvider; use Answear\FanCourierBundle\Exception\RequestException; use Answear\FanCourierBundle\Exception\ResponseException; use Answear\FanCourierBundle\Logger\FanCourierLogger; +use Answear\FanCourierBundle\Request\LoginRequest; use Answear\FanCourierBundle\Request\RequestInterface; +use Answear\FanCourierBundle\Response\LoginResponse; use GuzzleHttp\Client as GuzzleClient; use GuzzleHttp\ClientInterface; use GuzzleHttp\Exception\GuzzleException; @@ -15,21 +18,45 @@ class Client { private const CONNECTION_TIMEOUT = 10; private const TIMEOUT = 30; - + + private ?string $token = null; + public function __construct( private readonly RequestTransformerInterface $requestTransformer, private readonly FanCourierLogger $logger, + private readonly ConfigProvider $configProvider, private ?ClientInterface $client = null, ) { $this->client ??= new GuzzleClient(['timeout' => self::TIMEOUT, 'connect_timeout' => self::CONNECTION_TIMEOUT]); } + public function login(): void + { + $loginRequest = new LoginRequest( + $this->configProvider->username, + $this->configProvider->password, + ); + + $response = $this->request($loginRequest); + + $loginResponse = LoginResponse::fromArray( + \json_decode($response->getBody()->getContents(), true), + ); + + $this->token = $loginResponse->token; + } + public function request(RequestInterface $request): ResponseInterface { $this->logger->setRequestId(uniqid('FANCOURIER-', more_entropy: true)); try { $psrRequest = $this->requestTransformer->transform($request); + + if ($this->token) { + $psrRequest = $psrRequest->withHeader('Authorization', 'Bearer ' . $this->token); + } + $this->logger->logRequest($request->getEndpoint(), $psrRequest); $response = $this->client->send($psrRequest); diff --git a/src/Client/RequestTransformer.php b/src/Client/RequestTransformer.php index 7cfe355..536af7a 100644 --- a/src/Client/RequestTransformer.php +++ b/src/Client/RequestTransformer.php @@ -6,6 +6,7 @@ use Answear\FanCourierBundle\ConfigProvider; use Answear\FanCourierBundle\Request\RequestInterface; +use Answear\FanCourierBundle\Serializer\Serializer; use GuzzleHttp\Psr7\Request as HttpRequest; use GuzzleHttp\Psr7\Uri; use Psr\Http\Message\RequestInterface as PsrRequestInterface; @@ -14,6 +15,7 @@ class RequestTransformer implements RequestTransformerInterface { public function __construct( private readonly ConfigProvider $configProvider, + private Serializer $serializer, ) { } @@ -21,17 +23,15 @@ public function transform(RequestInterface $request): PsrRequestInterface { $url = $this->configProvider->apiUrl . $request->getEndpoint(); - $formParams = [ - 'username' => $this->configProvider->username, - 'client_id' => $this->configProvider->clientId, - 'user_pass' => $this->configProvider->password, - ]; + if (!empty($request->getQueryParams())) { + $url .= '?' . http_build_query($request->getQueryParams()); + } return new HttpRequest( $request->getMethod(), new Uri($url), - ['Content-Type' => 'application/x-www-form-urlencoded'], - http_build_query(array_merge($formParams, $request->getOptions())) + ['Content-Type' => 'application/json'], + 'GET' === $request->getMethod() ? null : $this->serializer->serialize($request), ); } } diff --git a/src/ConfigProvider.php b/src/ConfigProvider.php index 7690a60..277b71f 100644 --- a/src/ConfigProvider.php +++ b/src/ConfigProvider.php @@ -7,7 +7,6 @@ class ConfigProvider { public function __construct( - public readonly string $clientId, public readonly string $username, public readonly string $password, public readonly string $apiUrl, diff --git a/src/DTO/AddressDTO.php b/src/DTO/AddressDTO.php new file mode 100644 index 0000000..686fe7a --- /dev/null +++ b/src/DTO/AddressDTO.php @@ -0,0 +1,43 @@ + $drawerArray + * @param array $drawerArray */ public static function fromArray(array $drawerArray): self { diff --git a/src/DTO/DrawerDTO.php b/src/DTO/DrawerDTO.php index a426aa7..5b7195d 100644 --- a/src/DTO/DrawerDTO.php +++ b/src/DTO/DrawerDTO.php @@ -8,7 +8,7 @@ class DrawerDTO { public function __construct( public readonly int $number, - public readonly string $type + public readonly string $type, ) { } } diff --git a/src/DTO/PickupPointDTO.php b/src/DTO/PickupPointDTO.php index dbef1ba..388e539 100644 --- a/src/DTO/PickupPointDTO.php +++ b/src/DTO/PickupPointDTO.php @@ -10,52 +10,42 @@ class PickupPointDTO { public function __construct( public readonly string $id, + public readonly string $code, public readonly string $name, public readonly string $routingLocation, public readonly string $description, - public readonly string $county, - public readonly string $locality, - public readonly string $address, - public readonly string $zipCode, - public readonly string $locationReference, + public readonly AddressDTO $address, public readonly float $latitude, public readonly float $longitude, public readonly ScheduleCollection $schedule, - public readonly DrawerCollection $drawer + public readonly DrawerCollection $drawer, ) { } public static function fromArray(array $pickupPoint): self { - Assert::stringNotEmpty($pickupPoint['Id']); - Assert::stringNotEmpty($pickupPoint['Name']); - Assert::stringNotEmpty($pickupPoint['RoutingLocation']); - Assert::stringNotEmpty($pickupPoint['Description']); - Assert::stringNotEmpty($pickupPoint['County']); - Assert::stringNotEmpty($pickupPoint['Locality']); - Assert::stringNotEmpty($pickupPoint['Address']); - Assert::stringNotEmpty($pickupPoint['ZipCode']); - Assert::stringNotEmpty($pickupPoint['LocationReference']); - Assert::float($pickupPoint['Latitude']); - Assert::float($pickupPoint['Longitude']); - Assert::range($pickupPoint['Latitude'], -90, 90); - Assert::range($pickupPoint['Longitude'], -180, 180); - Assert::count($pickupPoint['Schedule'], 7); + Assert::stringNotEmpty($pickupPoint['id']); + Assert::stringNotEmpty($pickupPoint['name']); + Assert::stringNotEmpty($pickupPoint['routingLocation']); + Assert::stringNotEmpty($pickupPoint['description']); + Assert::notEmpty($pickupPoint['address']); + Assert::stringNotEmpty($pickupPoint['latitude']); + Assert::stringNotEmpty($pickupPoint['longitude']); + Assert::range((float) $pickupPoint['latitude'], -90, 90); + Assert::range((float) $pickupPoint['longitude'], -180, 180); + Assert::count($pickupPoint['schedule'], 7); return new self( - $pickupPoint['Id'], - $pickupPoint['Name'], - $pickupPoint['RoutingLocation'], - $pickupPoint['Description'], - $pickupPoint['County'], - $pickupPoint['Locality'], - $pickupPoint['Address'], - $pickupPoint['ZipCode'], - $pickupPoint['LocationReference'], - $pickupPoint['Latitude'], - $pickupPoint['Longitude'], - ScheduleCollection::fromArray($pickupPoint['Schedule']), - DrawerCollection::fromArray($pickupPoint['Drawer']) + $pickupPoint['id'], + $pickupPoint['code'], + $pickupPoint['name'], + $pickupPoint['routingLocation'], + $pickupPoint['description'], + AddressDTO::fromArray($pickupPoint['address']), + (float) $pickupPoint['latitude'], + (float) $pickupPoint['longitude'], + ScheduleCollection::fromArray($pickupPoint['schedule']), + DrawerCollection::fromArray($pickupPoint['drawer']), ); } } diff --git a/src/DTO/ScheduleCollection.php b/src/DTO/ScheduleCollection.php index 24e9d90..2d43f14 100644 --- a/src/DTO/ScheduleCollection.php +++ b/src/DTO/ScheduleCollection.php @@ -12,20 +12,20 @@ class ScheduleCollection * @param ScheduleDTO[] $schedules */ public function __construct( - public readonly array $schedules = [] + public readonly array $schedules = [], ) { } /** - * @param array $scheduleArray + * @param array $scheduleArray */ public static function fromArray(array $scheduleArray): self { $schedules = []; foreach ($scheduleArray as $schedule) { - Assert::stringNotEmpty($schedule['startHour']); - Assert::stringNotEmpty($schedule['stopHour']); - $schedules[] = new ScheduleDTO($schedule['startHour'], $schedule['stopHour']); + Assert::stringNotEmpty($schedule['firstHour']); + Assert::stringNotEmpty($schedule['secondHour']); + $schedules[] = new ScheduleDTO($schedule['firstHour'], $schedule['secondHour']); } return new self($schedules); diff --git a/src/DTO/ScheduleDTO.php b/src/DTO/ScheduleDTO.php index 7a19e2f..2c9fbd3 100644 --- a/src/DTO/ScheduleDTO.php +++ b/src/DTO/ScheduleDTO.php @@ -7,8 +7,8 @@ class ScheduleDTO { public function __construct( - public readonly string $startHour, - public readonly string $stopHour + public readonly string $firstHour, + public readonly string $secondHour, ) { } } diff --git a/src/DependencyInjection/AnswearFanCourierExtension.php b/src/DependencyInjection/AnswearFanCourierExtension.php index f8dd5fb..0ea192a 100755 --- a/src/DependencyInjection/AnswearFanCourierExtension.php +++ b/src/DependencyInjection/AnswearFanCourierExtension.php @@ -38,7 +38,6 @@ public function load(array $configs, ContainerBuilder $container): void $definition = $container->getDefinition(ConfigProvider::class); $definition->setArguments([ - $this->config['clientId'], $this->config['username'], $this->config['password'], $this->config['apiUrl'], diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 599ec19..ce7b56f 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -15,8 +15,7 @@ public function getConfigTreeBuilder(): TreeBuilder $treeBuilder->getRootNode() ->children() - ->scalarNode('clientId')->isRequired()->cannotBeEmpty()->end() - ?->scalarNode('username')->isRequired()->cannotBeEmpty()->end() + ->scalarNode('username')->isRequired()->cannotBeEmpty()->end() ?->scalarNode('password')->isRequired()->cannotBeEmpty()->end() ?->scalarNode('apiUrl')->isRequired()->cannotBeEmpty()->end() ?->scalarNode('logger')->defaultNull()->end() diff --git a/src/Request/GetPickupPointsRequest.php b/src/Request/GetPickupPointsRequest.php index b80def3..1851782 100644 --- a/src/Request/GetPickupPointsRequest.php +++ b/src/Request/GetPickupPointsRequest.php @@ -6,8 +6,8 @@ class GetPickupPointsRequest implements RequestInterface { - private const ENDPOINT = '/pickup-points.php'; - private const HTTP_METHOD = 'POST'; + private const ENDPOINT = '/reports/pickup-points'; + private const HTTP_METHOD = 'GET'; public function getEndpoint(): string { @@ -19,7 +19,7 @@ public function getMethod(): string return self::HTTP_METHOD; } - public function getOptions(): array + public function getQueryParams(): array { return ['type' => 'fanbox']; } diff --git a/src/Request/LoginRequest.php b/src/Request/LoginRequest.php new file mode 100644 index 0000000..a2d5144 --- /dev/null +++ b/src/Request/LoginRequest.php @@ -0,0 +1,32 @@ + PickupPointDTO::fromArray($pickupPoint), + $data['data'], + ); + + return new self( + $data['status'], + $pickupPoints, + ); } } diff --git a/src/Response/LoginResponse.php b/src/Response/LoginResponse.php new file mode 100644 index 0000000..fcf2507 --- /dev/null +++ b/src/Response/LoginResponse.php @@ -0,0 +1,27 @@ + true, + ]; + } + + public function normalize(mixed $object, ?string $format = null, array $context = []): array + { + return []; + } + + public function supportsNormalization($data, $format = null): bool + { + return is_object($data) && $this->isEmptyClass($data); + } + + private function isEmptyClass($object): bool + { + $reflectionClass = new \ReflectionClass($object); + + return empty($reflectionClass->getProperties()); + } +} diff --git a/src/Serializer/Serializer.php b/src/Serializer/Serializer.php new file mode 100644 index 0000000..098786d --- /dev/null +++ b/src/Serializer/Serializer.php @@ -0,0 +1,48 @@ +getSerializer()->serialize( + $request, + JsonEncoder::FORMAT, + [ + Normalizer\AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ] + ); + } + + private function getSerializer(): SymfonySerializer + { + if (!isset($this->serializer)) { + $this->serializer = new SymfonySerializer( + [ + new EmptyObjectNormalizer(), + new Normalizer\PropertyNormalizer( + null, + null, + new ReflectionExtractor(), + ), + new Normalizer\ArrayDenormalizer(), + ], + [new JsonEncoder()] + ); + } + + return $this->serializer; + } +} diff --git a/src/Service/PickupPointService.php b/src/Service/PickupPointService.php index ae2bfe7..0e6bed1 100644 --- a/src/Service/PickupPointService.php +++ b/src/Service/PickupPointService.php @@ -20,6 +20,8 @@ public function __construct( */ public function getAll(): array { + $this->client->login(); + $response = $this->client->request(new GetPickupPointsRequest()); $pickupPointsResponse = GetPickupPointsResponse::fromArray($this->decodeResponse($response)); diff --git a/tests/Acceptance/DependencyInjection/ConfigurationTest.php b/tests/Acceptance/DependencyInjection/ConfigurationTest.php index 481e41b..dc5030d 100644 --- a/tests/Acceptance/DependencyInjection/ConfigurationTest.php +++ b/tests/Acceptance/DependencyInjection/ConfigurationTest.php @@ -31,15 +31,14 @@ public function validTest(array $configs): void $configProviderDefinition = $builder->getDefinition(ConfigProvider::class); - self::assertSame($configs[0]['clientId'], $configProviderDefinition->getArgument(0)); - self::assertSame($configs[0]['username'], $configProviderDefinition->getArgument(1)); - self::assertSame($configs[0]['password'], $configProviderDefinition->getArgument(2)); - self::assertSame($configs[0]['apiUrl'], $configProviderDefinition->getArgument(3)); + self::assertSame($configs[0]['username'], $configProviderDefinition->getArgument(0)); + self::assertSame($configs[0]['password'], $configProviderDefinition->getArgument(1)); + self::assertSame($configs[0]['apiUrl'], $configProviderDefinition->getArgument(2)); } #[Test] #[DataProvider('provideInvalidConfig')] - public function invalidConfig(array $config, string $expectedMessage = null): void + public function invalidConfig(array $config, ?string $expectedMessage = null): void { $this->assertConfigurationIsInvalid( $config, @@ -71,15 +70,6 @@ public static function provideInvalidConfig(): iterable '"answear_fan_courier" must be configured.', ]; - yield [ - [ - [ - 'clientId' => 'test', - ], - ], - '"answear_fan_courier" must be configured.', - ]; - yield [ [ [ @@ -113,7 +103,6 @@ public static function provideInvalidLogger(): iterable yield [ [ [ - 'clientId' => 'clientId', 'username' => 'username', 'password' => 'password', 'apiUrl' => 'apiUrl', @@ -129,7 +118,6 @@ public static function provideValidConfig(): iterable yield [ [ [ - 'clientId' => 'clientId', 'username' => 'username', 'password' => 'password', 'apiUrl' => 'apiUrl', @@ -140,10 +128,9 @@ public static function provideValidConfig(): iterable yield [ [ [ - 'clientId' => 123, 'username' => 'kimi', 'password' => 'password', - 'apiUrl' => 'www.softwear.co', + 'apiUrl' => 'api.fancourier.ro', ], ], ]; diff --git a/tests/Integration/Service/PickupPointServiceTest.php b/tests/Integration/Service/PickupPointServiceTest.php index b71b883..7f8bfd6 100644 --- a/tests/Integration/Service/PickupPointServiceTest.php +++ b/tests/Integration/Service/PickupPointServiceTest.php @@ -8,29 +8,37 @@ use Answear\FanCourierBundle\Client\RequestTransformer; use Answear\FanCourierBundle\ConfigProvider; use Answear\FanCourierBundle\DTO\PickupPointDTO; +use Answear\FanCourierBundle\Exception\RequestException; use Answear\FanCourierBundle\Logger\FanCourierLogger; +use Answear\FanCourierBundle\Serializer\Serializer; use Answear\FanCourierBundle\Service\PickupPointService; use Answear\FanCourierBundle\Tests\MockGuzzleTrait; use GuzzleHttp\Psr7\Response; use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Psr\Log\NullLogger; +use Psr\Log\LoggerInterface; class PickupPointServiceTest extends TestCase { use MockGuzzleTrait; private Client $client; + private LoggerInterface|MockObject $logger; public function setUp(): void { parent::setUp(); - $configProvider = new ConfigProvider('clientId', 'username', 'password', 'www.softwear.co'); + $this->logger = $this->createMock(LoggerInterface::class); + + $configProvider = new ConfigProvider('username', 'password', 'https://api.fancourier.ro'); + $serializer = new Serializer(); $this->client = new Client( - new RequestTransformer($configProvider), - new FanCourierLogger(new NullLogger()), - $this->setupGuzzleClient() + new RequestTransformer($configProvider, $serializer), + new FanCourierLogger($this->logger), + $configProvider, + $this->setupGuzzleClient(), ); } @@ -38,7 +46,9 @@ public function setUp(): void public function successfulFindPoints(): void { $service = $this->getService(); - $this->mockGuzzleResponse(new Response(200, [], $this->getSuccessfulBody())); + + $this->mockGuzzleResponse(new Response(200, [], $this->getSuccessfulLoginBody())); + $this->mockGuzzleResponse(new Response(200, [], $this->getSuccessfulPickupPointsBody())); $pickupPoints = $service->getAll(); @@ -46,22 +56,46 @@ public function successfulFindPoints(): void $this->assertPoint($pickupPoints[0]); } + #[Test] + public function failedLogin(): void + { + $service = $this->getService(); + + $this->mockGuzzleResponse(new Response(401, [])); + + $this->logger->expects(self::once()) + ->method('error') + ->with('[FANCOURIER] Exception - /login'); + + $this->expectException(RequestException::class); + + $service->getAll(); + } + private function assertPoint(PickupPointDTO $pickupPoint): void { $this->assertNotNull($pickupPoint); - $this->assertSame($pickupPoint->id, 'FAN0039'); + $this->assertSame($pickupPoint->id, 'F1000005'); + $this->assertSame($pickupPoint->code, 'FAN0039'); $this->assertSame($pickupPoint->name, 'FANbox Kaufland Theodor Pallady'); $this->assertSame($pickupPoint->routingLocation, 'FANbox Kaufland Theodor Pallady (Locker)'); $this->assertSame($pickupPoint->description, 'In dreapta intrarii principale'); - $this->assertSame($pickupPoint->county, 'Bucuresti'); - $this->assertSame($pickupPoint->locality, 'Bucuresti'); - $this->assertSame($pickupPoint->address, 'Bd. Theodor Pallady, Nr. 51'); - $this->assertSame($pickupPoint->zipCode, '32258'); - $this->assertSame($pickupPoint->locationReference, 'In dreapta intrarii principale'); + $this->assertSame($pickupPoint->address->county, 'Bucuresti'); + $this->assertSame($pickupPoint->address->locality, 'Bucuresti'); + $this->assertSame($pickupPoint->address->street, 'Bd. Theodor Pallady'); + $this->assertSame($pickupPoint->address->streetNo, '51'); + $this->assertSame($pickupPoint->address->zipCode, '032258'); + $this->assertSame($pickupPoint->address->reference, 'In dreapta intrarii principale'); $this->assertSame($pickupPoint->latitude, 44.40874); $this->assertSame($pickupPoint->longitude, 26.19726); $this->assertCount(7, $pickupPoint->schedule->schedules); $this->assertCount(3, $pickupPoint->drawer->drawers); + + $this->assertSame($pickupPoint->schedule->schedules[0]->firstHour, '00:00'); + $this->assertSame($pickupPoint->schedule->schedules[0]->secondHour, '23:59'); + + $this->assertSame($pickupPoint->drawer->drawers[0]->type, 'L'); + $this->assertSame($pickupPoint->drawer->drawers[0]->number, 4); } private function getService(): PickupPointService @@ -69,8 +103,13 @@ private function getService(): PickupPointService return new PickupPointService($this->client); } - private function getSuccessfulBody(): string + private function getSuccessfulLoginBody(): string + { + return file_get_contents(__DIR__ . '/data/exampleLoginResponse.json'); + } + + private function getSuccessfulPickupPointsBody(): string { - return file_get_contents(__DIR__ . '/data/exampleResponse.json'); + return file_get_contents(__DIR__ . '/data/examplePickupPointsResponse.json'); } } diff --git a/tests/Integration/Service/data/exampleLoginResponse.json b/tests/Integration/Service/data/exampleLoginResponse.json new file mode 100644 index 0000000..74ad98d --- /dev/null +++ b/tests/Integration/Service/data/exampleLoginResponse.json @@ -0,0 +1,7 @@ +{ + "status": "success", + "data": { + "token": "10000000|yaaTDcsMwFfdlrAnD0MtOkEnprn1NMqgS30RLH4C5gg", + "expiresAt": "2024-09-18 16:35:24" + } +} diff --git a/tests/Integration/Service/data/examplePickupPointsResponse.json b/tests/Integration/Service/data/examplePickupPointsResponse.json new file mode 100644 index 0000000..c50c77f --- /dev/null +++ b/tests/Integration/Service/data/examplePickupPointsResponse.json @@ -0,0 +1,69 @@ +{ + "status": "success", + "data": [ + { + "id": "F1000005", + "code": "FAN0039", + "name": "FANbox Kaufland Theodor Pallady", + "routingLocation": "FANbox Kaufland Theodor Pallady (Locker)", + "description": "In dreapta intrarii principale", + "address": { + "locality": "Bucuresti", + "county": "Bucuresti", + "street": "Bd. Theodor Pallady", + "streetNo": "51", + "zipCode": "032258", + "floor": "", + "reference": "In dreapta intrarii principale" + }, + "latitude": "44.40874", + "longitude": "26.19726", + "schedule": [ + { + "firstHour": "00:00", + "secondHour": "23:59" + }, + { + "firstHour": "00:00", + "secondHour": "23:59" + }, + { + "firstHour": "00:00", + "secondHour": "23:59" + }, + { + "firstHour": "00:00", + "secondHour": "23:59" + }, + { + "firstHour": "00:00", + "secondHour": "23:59" + }, + { + "firstHour": "00:00", + "secondHour": "23:59" + }, + { + "firstHour": "00:00", + "secondHour": "23:59" + } + ], + "drawer": [ + { + "type": "L", + "number": 4 + }, + { + "type": "M", + "number": 2 + }, + { + "type": "S", + "number": 9 + } + ], + "phones": null, + "email": null + } + ] +} diff --git a/tests/Integration/Service/data/exampleResponse.json b/tests/Integration/Service/data/exampleResponse.json deleted file mode 100644 index 6aba817..0000000 --- a/tests/Integration/Service/data/exampleResponse.json +++ /dev/null @@ -1,59 +0,0 @@ -[ - { - "Id": "FAN0039", - "Name": "FANbox Kaufland Theodor Pallady", - "RoutingLocation": "FANbox Kaufland Theodor Pallady (Locker)", - "Description": "In dreapta intrarii principale", - "County": "Bucuresti", - "Locality": "Bucuresti", - "Address": "Bd. Theodor Pallady, Nr. 51", - "ZipCode": "32258", - "LocationReference": "In dreapta intrarii principale", - "Latitude": 44.40874, - "Longitude": 26.19726, - "Schedule": [ - { - "startHour": "00: 00", - "stopHour": "23:59" - }, - { - "startHour": "00: 00", - "stopHour": "23: 59" - }, - { - "startHour": "00: 00", - "stopHour": "23: 59" - }, - { - "startHour": "00:00", - "stopHour": "23: 59" - }, - { - "startHour": "00: 00", - "stopHour": "23: 59" - }, - { - "startHour": "00: 00", - "stopHour": "23:59" - }, - { - "startHour": "00: 00", - "stopHour": "23: 59" - } - ], - "Drawer": [ - { - "number": 6, - "type": "L" - }, - { - "number": 3, - "type": "M" - }, - { - "number": 17, - "type": "S" - } - ] - } -] From dfe138fe4d3d950a6662ab2603c9ce21293232d9 Mon Sep 17 00:00:00 2001 From: Yevhenii Kovalenko Date: Thu, 19 Sep 2024 14:53:56 +0200 Subject: [PATCH 2/3] Create object in single line --- src/Response/GetPickupPointsResponse.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Response/GetPickupPointsResponse.php b/src/Response/GetPickupPointsResponse.php index c15172e..39eed39 100644 --- a/src/Response/GetPickupPointsResponse.php +++ b/src/Response/GetPickupPointsResponse.php @@ -27,9 +27,6 @@ public static function fromArray(array $data): self $data['data'], ); - return new self( - $data['status'], - $pickupPoints, - ); + return new self($data['status'], $pickupPoints); } } From fb47e897fbada87a1d387ddd022c3601fefde9ae Mon Sep 17 00:00:00 2001 From: Yevhenii Kovalenko Date: Fri, 20 Sep 2024 09:17:18 +0200 Subject: [PATCH 3/3] Remove unnecessary normalizer --- composer.json | 15 ++++---- src/Resources/config/services.yaml | 2 +- .../Normalizer/EmptyObjectNormalizer.php | 35 ------------------- src/Serializer/Serializer.php | 3 +- 4 files changed, 9 insertions(+), 46 deletions(-) delete mode 100644 src/Serializer/Normalizer/EmptyObjectNormalizer.php diff --git a/composer.json b/composer.json index fb563c2..59bf20d 100755 --- a/composer.json +++ b/composer.json @@ -4,15 +4,14 @@ "type": "symfony-bundle", "license": "MIT", "require": { - "php": ">=8.1|^8.2", + "php": ">=8.1", "ext-json": "*", - "guzzlehttp/guzzle": "^6.5|^7.9.2", - "psr/log": "^1.1.4", - "symfony/http-kernel": "6.4.*", - "symfony/property-access": "6.4.*", - "symfony/property-info": "6.4.*", - "symfony/serializer": "6.4.*", - "webmozart/assert": "^1.11" + "guzzlehttp/guzzle": "^6.0 || ^7.0", + "psr/log": "^1.1", + "symfony/http-kernel": "^6.1", + "symfony/property-info": "^6.1", + "symfony/serializer": "^6.1", + "webmozart/assert": "^1.3" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.63.2", diff --git a/src/Resources/config/services.yaml b/src/Resources/config/services.yaml index e8e2dec..18e3ef3 100755 --- a/src/Resources/config/services.yaml +++ b/src/Resources/config/services.yaml @@ -12,4 +12,4 @@ services: Answear\FanCourierBundle\Logger\FanCourierLogger: shared: false - Answear\FanCourierBundle\Client\RequestTransformerInterface: '@Answear\FanCourierBundle\Client\RequestTransformer' \ No newline at end of file + Answear\FanCourierBundle\Client\RequestTransformerInterface: '@Answear\FanCourierBundle\Client\RequestTransformer' diff --git a/src/Serializer/Normalizer/EmptyObjectNormalizer.php b/src/Serializer/Normalizer/EmptyObjectNormalizer.php deleted file mode 100644 index 51bdd4d..0000000 --- a/src/Serializer/Normalizer/EmptyObjectNormalizer.php +++ /dev/null @@ -1,35 +0,0 @@ - true, - ]; - } - - public function normalize(mixed $object, ?string $format = null, array $context = []): array - { - return []; - } - - public function supportsNormalization($data, $format = null): bool - { - return is_object($data) && $this->isEmptyClass($data); - } - - private function isEmptyClass($object): bool - { - $reflectionClass = new \ReflectionClass($object); - - return empty($reflectionClass->getProperties()); - } -} diff --git a/src/Serializer/Serializer.php b/src/Serializer/Serializer.php index 098786d..ab90f86 100644 --- a/src/Serializer/Serializer.php +++ b/src/Serializer/Serializer.php @@ -5,7 +5,6 @@ namespace Answear\FanCourierBundle\Serializer; use Answear\FanCourierBundle\Request\RequestInterface; -use Answear\FanCourierBundle\Serializer\Normalizer\EmptyObjectNormalizer; use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Normalizer; @@ -31,7 +30,7 @@ private function getSerializer(): SymfonySerializer if (!isset($this->serializer)) { $this->serializer = new SymfonySerializer( [ - new EmptyObjectNormalizer(), + new Normalizer\CustomNormalizer(), new Normalizer\PropertyNormalizer( null, null,