1
0
mirror of synced 2024-11-23 21:26:01 +03:00
This commit is contained in:
Pavel 2020-09-25 18:06:41 +03:00
commit f1d0ecaa39
19 changed files with 753 additions and 0 deletions

9
.editorconfig Normal file
View File

@ -0,0 +1,9 @@
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 4
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

15
.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
/vendor
/bin
composer.lock
composer.phar
coverage.xml
test-report.xml
phpunit.xml
.phpunit.result.cache
.idea
.DS_Store
.settings
.buildpath
.project
.swp
/nbproject

17
.travis.yml Normal file
View File

@ -0,0 +1,17 @@
language: php
cache:
directories:
- $HOME/.composer/cache
php:
- '7.4'
before_script:
- flags="-o"
- composer install $flags
script: php ./vendor/phpunit/phpunit/phpunit -c phpunit.xml.dist
after_success:
- bash <(curl -s https://codecov.io/bash)

7
LICENSE Normal file
View File

@ -0,0 +1,7 @@
Copyright © 2020 RetailDriver
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

3
README.md Normal file
View File

@ -0,0 +1,3 @@
# AliExpress TOP API client
API client implementation for AliExpress TOP.

38
composer.json Normal file
View File

@ -0,0 +1,38 @@
{
"name": "retailcrm/aliexpress-top-client",
"description": "API client implementation for AliExpress TOP.",
"type": "library",
"keywords": ["API", "retailCRM", "REST"],
"homepage": "http://www.retailcrm.ru/",
"authors": [
{
"name": "RetailDriver LLC",
"email": "integration@retailcrm.ru"
}
],
"support": {
"email": "support@retailcrm.ru"
},
"autoload": {
"psr-4": { "RetailCrm\\": "src/" }
},
"require": {
"php": ">=7.4.0",
"ext-curl": "*",
"ext-json": "*",
"psr/http-client": "^1.0",
"symfony/serializer": "^5.1",
"symfony/validator": "^5.1",
"devanych/di-container": "^2.1",
"doctrine/annotations": "^1.10",
"doctrine/cache": "^1.10",
"symfony/property-access": "^5.1"
},
"require-dev": {
"phpunit/phpunit": "^9.3",
"phpmd/phpmd": "^2.9",
"squizlabs/php_codesniffer": "^3.5",
"guzzlehttp/guzzle": "^7.1"
},
"license": "MIT"
}

36
phpunit.xml.dist Normal file
View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- https://phpunit.de/manual/current/en/appendixes.configuration.html -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/6.5/phpunit.xsd"
backupGlobals="false"
colors="false"
bootstrap="tests/bootstrap.php"
backupStaticAttributes="false"
convertErrorsToExceptions="false"
convertNoticesToExceptions="false"
convertWarningsToExceptions="false"
processIsolation="true"
stopOnError="false"
stopOnFailure="false"
stopOnIncomplete="false"
stopOnSkipped="false"
stopOnRisky="false"
>
<testsuites>
<testsuite name="Project Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>src</directory>
</whitelist>
</filter>
<logging>
<log type="coverage-clover" target="coverage.xml"/>
<log type="junit" target="test-report.xml"/>
</logging>
</phpunit>

View File

@ -0,0 +1,66 @@
<?php
/**
* PHP version 7.4
*
* @category Environment
* @package RetailCrm\Component
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://help.retailcrm.ru
*/
namespace RetailCrm\Component;
use Psr\Container\ContainerInterface;
use RetailCrm\Factory\ClientFactory;
use RetailCrm\TopClient\Client;
/**
* Class Environment
*
* @category Environment
* @package RetailCrm\Component
* @author RetailDriver LLC <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see https://help.retailcrm.ru
*/
class Environment
{
public const PROD = 'PROD';
public const DEV = 'DEV';
public const TEST = 'TEST';
private ContainerInterface $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
/**
* @return \Psr\Container\ContainerInterface
*/
public function getContainer(): ContainerInterface
{
return $this->container;
}
/**
* @param string $serviceUrl
*
* @return \RetailCrm\TopClient\Client
* @throws \RetailCrm\Component\Exception\ValidationException
*/
public function createClient(string $serviceUrl): Client
{
$factory = $this->container->get(ClientFactory::class);
if (!($factory instanceof ClientFactory)) {
throw new \RuntimeException('Invalid factory definition in the provided container');
}
return $factory->create($serviceUrl);
}
}

View File

@ -0,0 +1,58 @@
<?php
/**
* PHP version 7.4
*
* @category ValidationException
* @package RetailCrm\Component\Exception
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://help.retailcrm.ru
*/
namespace RetailCrm\Component\Exception;
use Symfony\Component\Validator\ConstraintViolationListInterface;
use Throwable;
/**
* Class ValidationException
*
* @category ValidationException
* @package RetailCrm\Component\Exception
* @author RetailDriver LLC <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see https://help.retailcrm.ru
*/
class ValidationException extends \Exception
{
private ?ConstraintViolationListInterface $violations;
/**
* ValidationException constructor.
*
* @param string $message
* @param \Symfony\Component\Validator\ConstraintViolationListInterface|null $violations
* @param int $code
* @param \Throwable|null $previous
*/
public function __construct(
$message = "",
?ConstraintViolationListInterface $violations = null,
$code = 0,
Throwable $previous = null
) {
parent::__construct($message, $code, $previous);
$this->violations = $violations;
}
/**
* @return \Symfony\Component\Validator\ConstraintViolationListInterface|null
*/
public function getViolations(): ?ConstraintViolationListInterface
{
return $this->violations;
}
}

View File

@ -0,0 +1,55 @@
<?php
/**
* PHP version 7.4
*
* @category ClientFactory
* @package RetailCrm\Factory
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://help.retailcrm.ru
*/
namespace RetailCrm\Factory;
use RetailCrm\Interfaces\HttpClientAwareInterface;
use RetailCrm\Interfaces\ValidatorAwareInterface;
use RetailCrm\TopClient\Client;
use RetailCrm\Traits\HttpClientAwareTrait;
use RetailCrm\Traits\ValidatorAwareTrait;
use Symfony\Component\Serializer\SerializerAwareInterface;
use Symfony\Component\Serializer\SerializerAwareTrait;
/**
* Class ClientFactory
*
* @category ClientFactory
* @package RetailCrm\Factory
* @author RetailDriver LLC <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see https://help.retailcrm.ru
*/
class ClientFactory implements HttpClientAwareInterface, SerializerAwareInterface, ValidatorAwareInterface
{
use HttpClientAwareTrait;
use SerializerAwareTrait;
use ValidatorAwareTrait;
/**
* @param string $serviceUrl
*
* @return \RetailCrm\TopClient\Client
* @throws \RetailCrm\Component\Exception\ValidationException
*/
public function create(string $serviceUrl): Client
{
$client = new Client($serviceUrl);
$client->setHttpClient($this->httpClient);
$client->setSerializer($this->serializer);
$client->setValidator($this->validator);
$client->validateSelf();
return $client;
}
}

View File

@ -0,0 +1,42 @@
<?php
/**
* PHP version 7.4
*
* @category EnvironmentAwareFactoryInterface
* @package RetailCrm\Factory
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://help.retailcrm.ru
*/
namespace RetailCrm\Factory;
use Psr\Http\Client\ClientInterface;
use RetailCrm\Component\Environment;
/**
* Interface EnvironmentAwareFactoryInterface
*
* @category EnvironmentAwareFactoryInterface
* @package RetailCrm\Factory
* @author RetailDriver LLC <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see https://help.retailcrm.ru
*/
interface EnvironmentAwareFactoryInterface
{
/**
* @param string $environmentType
*
* @return \RetailCrm\Factory\EnvironmentAwareFactoryInterface
*/
public static function withEnv(string $environmentType = Environment::DEV): EnvironmentAwareFactoryInterface;
/**
* @return \RetailCrm\Component\Environment
*/
public function create(ClientInterface $httpClient): Environment;
}

View File

@ -0,0 +1,116 @@
<?php
/**
* PHP version 7.4
*
* @category EnvironmentFactory
* @package RetailCrm\Factory
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://help.retailcrm.ru
*/
namespace RetailCrm\Factory;
use Devanych\Di\Container;
use Psr\Container\ContainerInterface;
use Psr\Http\Client\ClientInterface;
use RetailCrm\TopClient\Client;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\SerializerAwareTrait;
use Symfony\Component\Validator\Validation;
use RetailCrm\Component\Environment;
use Symfony\Component\Validator\Validator\TraceableValidator;
use Symfony\Component\Validator\Validator\ValidatorInterface;
/**
* Class EnvironmentFactory
*
* @category EnvironmentFactory
* @package RetailCrm\Factory
* @author RetailDriver LLC <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see https://help.retailcrm.ru
*/
class EnvironmentFactory implements EnvironmentAwareFactoryInterface
{
public string $env;
public ClientInterface $httpClient;
/**
* @param string $environmentType
*
* @return \RetailCrm\Factory\EnvironmentAwareFactoryInterface
*/
public static function withEnv(string $environmentType = Environment::DEV): EnvironmentAwareFactoryInterface
{
$factory = new self();
$factory->env = $environmentType;
return $factory;
}
/**
* @param \Psr\Http\Client\ClientInterface $httpClient
*
* @return \RetailCrm\Component\Environment
*/
public function create(ClientInterface $httpClient): Environment
{
$this->httpClient = $httpClient;
$container = new Container();
switch ($this->env) {
case Environment::PROD:
$this->setProdServices($container);
break;
case Environment::DEV:
case Environment::TEST:
$this->setProdServices($container);
$this->setDevServices($container);
break;
default:
throw new \RuntimeException(sprintf('Invalid environment type: %s', $this->env));
}
return new Environment($container);
}
/**
* @param Container $container
*/
protected function setProdServices(Container $container): void
{
$container->set('httpClient', $this->httpClient);
$container->set('validator', Validation::createValidatorBuilder()->enableAnnotationMapping()->getValidator());
$container->set('serializer', new Serializer(
[new ObjectNormalizer()],
[new XmlEncoder(), new JsonEncoder()]
));
$container->set(ClientFactory::class, function (ContainerInterface $container): ClientFactory {
$factory = new ClientFactory();
$factory->setHttpClient($container->get('httpClient'));
$factory->setSerializer($container->get('serializer'));
$factory->setValidator($container->get('validator'));
return $factory;
});
}
/**
* @param Container $container
*/
protected function setDevServices(Container $container): void
{
$validator = $container->get('validator');
if ($validator instanceof ValidatorInterface) {
$container->set('validator', new TraceableValidator($validator));
}
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* PHP version 7.4
*
* @category ClientAwareInterface
* @package RetailCrm\Interfaces
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://help.retailcrm.ru
*/
namespace RetailCrm\Interfaces;
use Psr\Http\Client\ClientInterface;
/**
* Interface HttpClientAwareInterface
*
* @category HttpClientAwareInterface
* @package RetailCrm\Interfaces
* @author RetailDriver LLC <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see https://help.retailcrm.ru
*/
interface HttpClientAwareInterface
{
/**
* @param \Psr\Http\Client\ClientInterface $httpClient
*
* @return mixed
*/
public function setHttpClient(ClientInterface $httpClient): void;
}

View File

@ -0,0 +1,34 @@
<?php
/**
* PHP version 7.4
*
* @category ValidatorAwareInterface
* @package RetailCrm\Interfaces
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://help.retailcrm.ru
*/
namespace RetailCrm\Interfaces;
use Symfony\Component\Validator\Validator\ValidatorInterface;
/**
* Interface ValidatorAwareInterface
*
* @category ValidatorAwareInterface
* @package RetailCrm\Interfaces
* @author RetailDriver LLC <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see https://help.retailcrm.ru
*/
interface ValidatorAwareInterface
{
/**
* @param \Symfony\Component\Validator\Validator\ValidatorInterface $validator
*/
public function setValidator(ValidatorInterface $validator): void;
}

85
src/TopClient/Client.php Normal file
View File

@ -0,0 +1,85 @@
<?php
/**
* PHP version 7.4
*
* @category Client
* @package RetailCrm\TopClient
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://help.retailcrm.ru
*/
namespace RetailCrm\TopClient;
use RetailCrm\Component\Exception\ValidationException;
use RetailCrm\Interfaces\HttpClientAwareInterface;
use RetailCrm\Interfaces\ValidatorAwareInterface;
use RetailCrm\Traits\HttpClientAwareTrait;
use RetailCrm\Traits\ValidatorAwareTrait;
use Symfony\Component\Serializer\SerializerAwareInterface;
use Symfony\Component\Serializer\SerializerAwareTrait;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Class Client
*
* @category Client
* @package RetailCrm\TopClient
* @author RetailDriver LLC <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see https://help.retailcrm.ru
*/
class Client implements SerializerAwareInterface, HttpClientAwareInterface, ValidatorAwareInterface
{
use ValidatorAwareTrait;
use HttpClientAwareTrait;
use SerializerAwareTrait;
public const OVERSEAS_ENDPOINT = 'https://api.taobao.com/router/rest';
public const CHINESE_ENDPOINT = 'https://eco.taobao.com/router/rest';
public const AVAILABLE_ENDPOINTS = [self::OVERSEAS_ENDPOINT, self::CHINESE_ENDPOINT];
/**
* @Assert\Url()
* @Assert\Choice(choices=Client::AVAILABLE_ENDPOINTS, message="Choose a valid endpoint.")
*/
protected string $serviceUrl;
/**
* Client constructor.
*
* @param string serviceUrl
*/
public function __construct(string $serviceUrl)
{
$this->serviceUrl = $serviceUrl;
}
/**
* @throws \RetailCrm\Component\Exception\ValidationException
*/
public function validateSelf(): void
{
$violations = $this->validator->validate($this);
if ($violations->count()) {
throw new ValidationException("Invalid client data", $violations);
}
}
/**
* @param mixed $item
*
* @throws \RetailCrm\Component\Exception\ValidationException
*/
private function validate($item): void
{
$violations = $this->validator->validate($item);
if ($violations->count()) {
throw new ValidationException("Invalid data", $item);
}
}
}

View File

@ -0,0 +1,43 @@
<?php
/**
* PHP version 7.4
*
* @category HttpClientAwareTrait
* @package RetailCrm\Traits
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://help.retailcrm.ru
*/
namespace RetailCrm\Traits;
use Psr\Http\Client\ClientInterface;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Trait HttpClientAwareTrait
*
* @category HttpClientAwareTrait
* @package RetailCrm\Traits
* @author RetailDriver LLC <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see https://help.retailcrm.ru
*/
trait HttpClientAwareTrait
{
/**
* @Assert\NotNull(message="HTTP client should be provided")
*/
protected ClientInterface $httpClient;
/**
* @param \Psr\Http\Client\ClientInterface $httpClient
*/
public function setHttpClient(ClientInterface $httpClient): void
{
$this->httpClient = $httpClient;
}
}

View File

@ -0,0 +1,43 @@
<?php
/**
* PHP version 7.4
*
* @category ValidatorAwareTrait
* @package RetailCrm\Traits
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://help.retailcrm.ru
*/
namespace RetailCrm\Traits;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Validator\ValidatorInterface;
/**
* Trait ValidatorAwareTrait
*
* @category ValidatorAwareTrait
* @package RetailCrm\Traits
* @author RetailDriver LLC <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see https://help.retailcrm.ru
*/
trait ValidatorAwareTrait
{
/**
* @Assert\NotNull(message="Validator should be provided")
*/
protected ValidatorInterface $validator;
/**
* @param \Symfony\Component\Validator\Validator\ValidatorInterface $validator
*/
public function setValidator(ValidatorInterface $validator): void
{
$this->validator = $validator;
}
}

View File

@ -0,0 +1,40 @@
<?php
/**
* PHP version 7.4
*
* @category EnvironmentTest
* @package Component
* @author RetailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://help.retailcrm.ru
*/
namespace Component;
use GuzzleHttp\Client as HttpClient;
use PHPUnit\Framework\TestCase;
use RetailCrm\Factory\EnvironmentFactory;
use RetailCrm\TopClient\Client;
/**
* Class EnvironmentTest
*
* @category EnvironmentTest
* @package Component
* @author RetailDriver LLC <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see https://help.retailcrm.ru
*/
class EnvironmentTest extends TestCase
{
public function testCreateClient()
{
$client = EnvironmentFactory::withEnv()
->create(new HttpClient())
->createClient(Client::OVERSEAS_ENDPOINT);
self::assertInstanceOf(Client::class, $client);
}
}

10
tests/bootstrap.php Normal file
View File

@ -0,0 +1,10 @@
<?php
if (function_exists('date_default_timezone_set')
&& function_exists('date_default_timezone_get')
) {
date_default_timezone_set(date_default_timezone_get());
}
$loader = include dirname(__DIR__) . '/vendor/autoload.php';
$loader->add('RetailCrm\\Test', __DIR__);