Skip to content

Commit 3bcd713

Browse files
committed
[UC-3] Add api client abstraction & add UserApi
1 parent d62c539 commit 3bcd713

7 files changed

Lines changed: 256 additions & 3 deletions

File tree

config/services.xml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8" ?>
22

33
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
4-
<services>
5-
</services>
4+
<imports>
5+
<import resource="services/*"/>
6+
</imports>
67
</container>

config/services/api.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
3+
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
4+
<services>
5+
<defaults autowire="false" autoconfigure="false"/>
6+
<service id="bit_bag.sylius_user_com_plugin.api.user_api" class="BitBag\SyliusUserComPlugin\Api\UserApi">
7+
<argument type="service" id="http_client"/>
8+
<argument type="service" id="monolog.logger"/>
9+
</service>
10+
</services>
11+
</container>

src/Api/AbstractClient.php

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace BitBag\SyliusUserComPlugin\Api;
6+
7+
use BitBag\SyliusUserComPlugin\Entity\UserComApiAwareInterface;
8+
use Psr\Log\LoggerInterface;
9+
use Symfony\Component\HttpFoundation\Response;
10+
use Symfony\Contracts\HttpClient\HttpClientInterface;
11+
use Symfony\Contracts\HttpClient\ResponseInterface;
12+
13+
abstract class AbstractClient
14+
{
15+
private const API_ENDPOINT_PREFIX = '/api/public/';
16+
17+
public function __construct(
18+
private readonly HttpClientInterface $client,
19+
private readonly LoggerInterface $logger,
20+
) {
21+
}
22+
23+
protected function request(
24+
string $path,
25+
string $method,
26+
array $options,
27+
): ?array {
28+
try {
29+
/** @var ResponseInterface $response */
30+
$response = $this->client->request(
31+
$method,
32+
$path,
33+
$options,
34+
);
35+
36+
$status = $response->getStatusCode();
37+
if ($status >= Response::HTTP_OK && $status < Response::HTTP_MULTIPLE_CHOICES) {
38+
return $response->toArray();
39+
}
40+
41+
throw new \Exception(
42+
sprintf(
43+
'Response status code : %s, response : %s',
44+
$status,
45+
$response->getContent(false),
46+
),
47+
);
48+
} catch (\Exception $e) {
49+
$this->logger->critical(sprintf(
50+
'User.com API request failed: %s',
51+
$e->getMessage(),
52+
), [
53+
'path' => $path,
54+
'method' => $method,
55+
'options' => $options,
56+
]);
57+
58+
return null;
59+
}
60+
}
61+
62+
protected function getApiEndpointUrl(
63+
UserComApiAwareInterface $resource,
64+
string $endpoint,
65+
string $query = null,
66+
) {
67+
$url = sprintf(
68+
'%s/%s/%s/',
69+
trim($resource->getUserComUrl(), '/'),
70+
trim(self::API_ENDPOINT_PREFIX, '/'),
71+
trim($endpoint, '/'),
72+
);
73+
74+
if (null === $query) {
75+
return $url;
76+
}
77+
78+
return sprintf('%s%s/', $url, $query);
79+
}
80+
81+
protected function buildOptions(
82+
UserComApiAwareInterface $resource,
83+
array $options = [],
84+
): array {
85+
$options['headers']['Accept'] = ' */*; version=2';
86+
$options['headers']['Authorization'] = $this->authorizeRequest($resource);
87+
88+
return $options;
89+
}
90+
91+
protected function authorizeRequest(
92+
UserComApiAwareInterface $resource,
93+
): string {
94+
return sprintf(
95+
'Token %s',
96+
$resource->getUserComApiKey(),
97+
);
98+
}
99+
}

src/Api/UserApi.php

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace BitBag\SyliusUserComPlugin\Api;
6+
7+
use BitBag\SyliusUserComPlugin\Entity\UserComApiAwareInterface;
8+
use Symfony\Component\HttpFoundation\Request;
9+
10+
final class UserApi extends AbstractClient implements UserApiInterface
11+
{
12+
const PARENT = 'parent';
13+
const USERS_LIST = 'users_list';
14+
15+
public function findUser(
16+
UserComApiAwareInterface $resource,
17+
string $value,
18+
string $field,
19+
): ?array {
20+
$url = $this->getApiEndpointUrl(
21+
$resource,
22+
self::FIND_USER_ENDPOINT,
23+
sprintf('?%s=%s', $field, $value),
24+
);
25+
26+
return $this->request(
27+
$url,
28+
Request::METHOD_GET,
29+
$this->buildOptions($resource),
30+
);
31+
}
32+
33+
public function getUser(UserComApiAwareInterface $resource, int $userId): ?array
34+
{
35+
$url = $this->getApiEndpointUrl($resource, sprintf(self::GET_USER_ENDPOINT, $userId));
36+
37+
return $this->request(
38+
$url,
39+
Request::METHOD_GET,
40+
$this->buildOptions($resource),
41+
);
42+
}
43+
44+
public function updateOrCreateUser(UserComApiAwareInterface $resource, array $data): ?array
45+
{
46+
return $this->request(
47+
$this->getApiEndpointUrl($resource, self::UPDATE_OR_CREATE_USER_ENDPOINT),
48+
Request::METHOD_POST,
49+
$this->buildOptions($resource, [
50+
'json' => $data,
51+
'headers' => [
52+
'Content-Type' => 'application/json',
53+
],
54+
]),
55+
);
56+
}
57+
58+
public function updateUser(UserComApiAwareInterface $resource, int $userId, array $data): ?array
59+
{
60+
$url = $this->getApiEndpointUrl($resource, sprintf(self::UPDATE_USER_ENDPOINT, $userId));
61+
62+
return $this->request(
63+
$url,
64+
Request::METHOD_PUT,
65+
$this->buildOptions($resource, ['json' => $data]),
66+
);
67+
}
68+
69+
public function createUser(UserComApiAwareInterface $resource, array $data): ?array
70+
{
71+
return $this->request(
72+
$this->getApiEndpointUrl($resource, self::CREATE_USER_ENDPOINT),
73+
Request::METHOD_POST,
74+
$this->buildOptions($resource, [
75+
'json' => $data,
76+
'headers' => [
77+
'Content-Type' => 'application/json',
78+
'User-Agent' => 'BitBag SyliusUserComPlugin',
79+
],
80+
]),
81+
);
82+
}
83+
84+
public function mergeUsers(UserComApiAwareInterface $resource, int $parentId, array $usersList): ?array
85+
{
86+
return $this->request(
87+
$this->getApiEndpointUrl($resource, self::MERGE_USERS_ENDPOINT),
88+
Request::METHOD_POST,
89+
$this->buildOptions($resource, [
90+
'json' => [
91+
self::PARENT => $parentId,
92+
self::USERS_LIST => $usersList,
93+
],
94+
]),
95+
);
96+
}
97+
}

src/Api/UserApiInterface.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace BitBag\SyliusUserComPlugin\Api;
6+
7+
use BitBag\SyliusUserComPlugin\Entity\UserComApiAwareInterface;
8+
9+
interface UserApiInterface
10+
{
11+
public const EMAIL_PROPERTY = 'email';
12+
13+
public const USER_KEY_PROPERTY = 'key';
14+
15+
public const FIND_USER_ENDPOINT = 'users/search';
16+
17+
public const UPDATE_OR_CREATE_USER_ENDPOINT = '/users/update_or_create/';
18+
19+
public const UPDATE_USER_ENDPOINT = '/users/%s';
20+
21+
public const GET_USER_ENDPOINT = '/users/%s';
22+
23+
public const CREATE_USER_ENDPOINT = '/users/';
24+
25+
public const MERGE_USERS_ENDPOINT = '/users/merge';
26+
27+
public function findUser(
28+
UserComApiAwareInterface $resource,
29+
string $value,
30+
string $field,
31+
): ?array;
32+
33+
public function updateOrCreateUser(UserComApiAwareInterface $resource, array $data): ?array;
34+
35+
public function updateUser(UserComApiAwareInterface $resource, int $userId, array $data): ?array;
36+
37+
public function createUser(UserComApiAwareInterface $resource, array $data): ?array;
38+
39+
public function mergeUsers(UserComApiAwareInterface $resource, int $parentId, array $usersList): ?array;
40+
}

tests/Application/config/packages/dev/monolog.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ monolog:
44
type: stream
55
path: "%kernel.logs_dir%/%kernel.environment%.log"
66
level: debug
7+
console:
8+
type: stream
9+
path: "%kernel.logs_dir%/%kernel.environment%.console.log"
10+
level: error
711
firephp:
812
type: firephp
913
level: info

tests/Application/src/Entity/ChannelInterface.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44

55
namespace Tests\BitBag\SyliusUserComPlugin\Entity;
66

7+
use BitBag\SyliusUserComPlugin\Entity\UserComApiAwareInterface;
78
use Sylius\Component\Core\Model\ChannelInterface as BaseChannelInterface;
89

9-
interface ChannelInterface extends BaseChannelInterface
10+
interface ChannelInterface extends BaseChannelInterface, UserComApiAwareInterface
1011
{
1112
}

0 commit comments

Comments
 (0)