diff --git a/composer.json b/composer.json index 6448dc2..e8dc9d4 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,8 @@ "jms/serializer": "^3.9", "shieldon/psr-http": "^1.2", "doctrine/annotations": "^1.10", - "doctrine/cache": "^1.10" + "doctrine/cache": "^1.10", + "psr/log": "^1.1" }, "require-dev": { "phpunit/phpunit": "^9.3", diff --git a/src/Factory/ClientFactory.php b/src/Builder/ClientBuilder.php similarity index 74% rename from src/Factory/ClientFactory.php rename to src/Builder/ClientBuilder.php index f3b73a6..9e8c274 100644 --- a/src/Factory/ClientFactory.php +++ b/src/Builder/ClientBuilder.php @@ -3,36 +3,36 @@ /** * PHP version 7.3 * - * @category ClientFactory - * @package RetailCrm\Factory + * @category ClientBuilder + * @package RetailCrm\Builder * @author RetailCRM * @license MIT * @link http://retailcrm.ru * @see http://help.retailcrm.ru */ -namespace RetailCrm\Factory; +namespace RetailCrm\Builder; -use Psr\Container\ContainerInterface; use RetailCrm\Component\Constants; use RetailCrm\Component\ServiceLocator; +use RetailCrm\Factory\RequestFactory; use RetailCrm\Interfaces\AppDataInterface; use RetailCrm\Interfaces\AuthenticatorInterface; +use RetailCrm\Interfaces\BuilderInterface; use RetailCrm\Interfaces\ContainerAwareInterface; -use RetailCrm\Interfaces\FactoryInterface; use RetailCrm\TopClient\Client; use RetailCrm\Traits\ContainerAwareTrait; /** - * Class ClientFactory + * Class ClientBuilder * - * @category ClientFactory - * @package RetailCrm\Factory + * @category ClientBuilder + * @package RetailCrm\Builder * @author RetailDriver LLC * @license MIT * @link http://retailcrm.ru * @see https://help.retailcrm.ru */ -class ClientFactory implements ContainerAwareInterface, FactoryInterface +class ClientBuilder implements ContainerAwareInterface, BuilderInterface { use ContainerAwareTrait; @@ -43,24 +43,19 @@ class ClientFactory implements ContainerAwareInterface, FactoryInterface protected $authenticator; /** - * @param \Psr\Container\ContainerInterface $container - * - * @return \RetailCrm\Factory\ClientFactory + * @return static */ - public static function withContainer(ContainerInterface $container): ClientFactory + public static function create(): self { - $factory = new self(); - $factory->setContainer($container); - - return $factory; + return new self(); } /** * @param \RetailCrm\Interfaces\AppDataInterface $appData * - * @return ClientFactory + * @return ClientBuilder */ - public function setAppData(AppDataInterface $appData): ClientFactory + public function setAppData(AppDataInterface $appData): ClientBuilder { $this->appData = $appData; return $this; @@ -81,7 +76,7 @@ class ClientFactory implements ContainerAwareInterface, FactoryInterface * @return \RetailCrm\TopClient\Client * @throws \RetailCrm\Component\Exception\ValidationException */ - public function create(): Client + public function build(): Client { $client = new Client($this->appData, $this->authenticator); $client->setHttpClient($this->container->get(Constants::HTTP_CLIENT)); diff --git a/src/Factory/ContainerFactory.php b/src/Builder/ContainerBuilder.php similarity index 72% rename from src/Factory/ContainerFactory.php rename to src/Builder/ContainerBuilder.php index d24115a..4353d92 100644 --- a/src/Factory/ContainerFactory.php +++ b/src/Builder/ContainerBuilder.php @@ -3,27 +3,27 @@ /** * PHP version 7.3 * - * @category EnvironmentFactory - * @package RetailCrm\Factory + * @category ContainerBuilder + * @package RetailCrm\Builder * @author RetailCRM * @license MIT * @link http://retailcrm.ru * @see http://help.retailcrm.ru */ -namespace RetailCrm\Factory; +namespace RetailCrm\Builder; -use JMS\Serializer\GraphNavigatorInterface; -use JMS\Serializer\Handler\HandlerRegistry; -use JMS\Serializer\Serializer; -use JMS\Serializer\SerializerBuilder; -use JMS\Serializer\SerializerInterface; use Psr\Container\ContainerInterface; use Psr\Http\Client\ClientInterface; +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; use RetailCrm\Component\Constants; use RetailCrm\Component\DependencyInjection\Container; use RetailCrm\Component\Environment; use RetailCrm\Component\ServiceLocator; -use RetailCrm\Interfaces\FactoryInterface; +use RetailCrm\Factory\FileItemFactory; +use RetailCrm\Factory\RequestFactory; +use RetailCrm\Factory\SerializerFactory; +use RetailCrm\Interfaces\BuilderInterface; use RetailCrm\Service\RequestDataFilter; use RetailCrm\Service\RequestSigner; use Shieldon\Psr17\StreamFactory; @@ -32,55 +32,77 @@ use Symfony\Component\Validator\Validator\TraceableValidator; use Symfony\Component\Validator\Validator\ValidatorInterface; /** - * Class EnvironmentFactory + * Class ContainerBuilder * - * @category EnvironmentFactory - * @package RetailCrm\Factory + * @category ContainerBuilder + * @package RetailCrm\Builder * @author RetailDriver LLC * @license MIT * @link http://retailcrm.ru * @see https://help.retailcrm.ru */ -class ContainerFactory implements FactoryInterface +class ContainerBuilder implements BuilderInterface { /** * @var string $env */ - public $env; + private $env; /** * @var \Psr\Http\Client\ClientInterface $httpClient */ - public $httpClient; + private $httpClient; + + /** + * @var \Psr\Log\LoggerInterface $logger + */ + private $logger; + + /** + * @return static + */ + public static function create(): self + { + return new self(); + } /** * @param string $environmentType * - * @return ContainerFactory + * @return ContainerBuilder */ - public static function withEnv(string $environmentType = Environment::DEV): ContainerFactory + public function setEnv(string $environmentType = Environment::DEV): self { - $factory = new self(); - $factory->env = $environmentType; - - return $factory; + $this->env = $environmentType; + return $this; } /** * @param \Psr\Http\Client\ClientInterface $httpClient * - * @return \RetailCrm\Factory\ContainerFactory + * @return \RetailCrm\Builder\ContainerBuilder */ - public function withClient(ClientInterface $httpClient): ContainerFactory + public function setClient(ClientInterface $httpClient): ContainerBuilder { $this->httpClient = $httpClient; return $this; } + /** + * @param \Psr\Log\LoggerInterface $logger + * + * @return ContainerBuilder + */ + public function setLogger(LoggerInterface $logger): ContainerBuilder + { + $this->logger = $logger; + return $this; + } + /** * @return \Psr\Container\ContainerInterface */ - public function create(): ContainerInterface + public function build(): ContainerInterface { $container = new Container(); @@ -106,6 +128,7 @@ class ContainerFactory implements FactoryInterface protected function setProdServices(Container $container): void { $container->set(Constants::HTTP_CLIENT, $this->httpClient); + $container->set(Constants::LOGGER, $this->logger ?: new NullLogger()); $container->set( Constants::VALIDATOR, Validation::createValidatorBuilder()->enableAnnotationMapping()->getValidator() diff --git a/src/Component/AppData.php b/src/Component/AppData.php index cf3eb9f..3c3e4d5 100644 --- a/src/Component/AppData.php +++ b/src/Component/AppData.php @@ -64,20 +64,6 @@ class AppData implements AppDataInterface $this->appSecret = $appSecret; } - /** - * Constructor shortcut - * - * @param string $serviceUrl - * @param string $appKey - * @param string $appSecret - * - * @return \RetailCrm\Component\AppData - */ - public static function create(string $serviceUrl, string $appKey, string $appSecret): AppDataInterface - { - return new self($serviceUrl, $appKey, $appSecret); - } - /** * @return string */ diff --git a/src/Component/Constants.php b/src/Component/Constants.php index d960a7f..7487614 100644 --- a/src/Component/Constants.php +++ b/src/Component/Constants.php @@ -26,6 +26,7 @@ class Constants { public const HTTP_CLIENT = 'httpClient'; public const SERIALIZER = 'serializer'; + public const LOGGER = 'logger'; public const VALIDATOR = 'validator'; public const TOP_VERSION = 'top-sdk-php-20180326'; public const SIGN_TYPE_MD5 = 'md5'; diff --git a/src/Component/Logger/AbstractLogger.php b/src/Component/Logger/AbstractLogger.php new file mode 100644 index 0000000..fe6b4a1 --- /dev/null +++ b/src/Component/Logger/AbstractLogger.php @@ -0,0 +1,59 @@ + + * @license MIT + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ +namespace RetailCrm\Component\Logger; + +use Psr\Log\AbstractLogger as BaseAbstractLogger; + +/** + * Class AbstractLogger + * + * @category AbstractLogger + * @package RetailCrm\Component\Logger + * @author RetailDriver LLC + * @license MIT + * @link http://retailcrm.ru + * @see https://help.retailcrm.ru + */ +abstract class AbstractLogger extends BaseAbstractLogger +{ + /** + * @param mixed $level + * @param string $message + * @param array $context + * + * @return string + */ + protected function formatMessage($level, $message, $context = []) + { + return sprintf( + '[%s] %s %s', + $level, + $message, + $this->encodeContext($context) + ); + } + + /** + * @param array $context + * + * @return false|string + */ + protected function encodeContext(array $context = []) + { + try { + return json_encode($context, JSON_THROW_ON_ERROR); + } catch (\Exception $exception) { + return ''; + } + } +} diff --git a/src/Component/Logger/FileLogger.php b/src/Component/Logger/FileLogger.php new file mode 100644 index 0000000..4b6332f --- /dev/null +++ b/src/Component/Logger/FileLogger.php @@ -0,0 +1,49 @@ + + * @license MIT + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ +namespace RetailCrm\Component\Logger; + +/** + * Class FileLogger + * + * @category FileLogger + * @package RetailCrm\Component\Logger + * @author RetailDriver LLC + * @license MIT + * @link http://retailcrm.ru + * @see https://help.retailcrm.ru + */ +class FileLogger extends AbstractLogger +{ + /** @var string $ */ + private $fileName; + + /** + * FileLogger constructor. + * + * @param string $fileName + */ + public function __construct(string $fileName) + { + $this->fileName = $fileName; + } + + /** + * @param mixed $level + * @param string $message + * @param array $context + */ + public function log($level, $message, array $context = []) + { + error_log($this->formatMessage($level, $message, $context), 3, $this->fileName); + } +} diff --git a/src/Component/Logger/StdoutLogger.php b/src/Component/Logger/StdoutLogger.php new file mode 100644 index 0000000..2611256 --- /dev/null +++ b/src/Component/Logger/StdoutLogger.php @@ -0,0 +1,36 @@ + + * @license MIT + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ +namespace RetailCrm\Component\Logger; + +/** + * Class StdioLogger + * + * @category StdioLogger + * @package RetailCrm\Component\Logger + * @author RetailDriver LLC + * @license MIT + * @link http://retailcrm.ru + * @see https://help.retailcrm.ru + */ +class StdoutLogger extends AbstractLogger +{ + /** + * @param mixed $level + * @param string $message + * @param array $context + */ + public function log($level, $message, array $context = []) + { + fwrite(STDOUT, $this->formatMessage($level, $message, $context) . PHP_EOL); + } +} diff --git a/src/Interfaces/BuilderInterface.php b/src/Interfaces/BuilderInterface.php new file mode 100644 index 0000000..58279da --- /dev/null +++ b/src/Interfaces/BuilderInterface.php @@ -0,0 +1,32 @@ + + * @license MIT + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ + +namespace RetailCrm\Interfaces; + +/** + * Interface BuilderInterface + * + * @category BuilderInterface + * @package RetailCrm\Interfaces + * @author RetailDriver LLC + * @license MIT + * @link http://retailcrm.ru + * @see https://help.retailcrm.ru + */ +interface BuilderInterface +{ + /** + * @return object + */ + public function build(); +} diff --git a/src/Interfaces/ContainerAwareInterface.php b/src/Interfaces/ContainerAwareInterface.php index ef62e6a..ae8ab5d 100644 --- a/src/Interfaces/ContainerAwareInterface.php +++ b/src/Interfaces/ContainerAwareInterface.php @@ -32,7 +32,7 @@ interface ContainerAwareInterface * * @return mixed */ - public function setContainer(ContainerInterface $container): void; + public function setContainer(ContainerInterface $container); /** * @return \Psr\Container\ContainerInterface diff --git a/src/Traits/ContainerAwareTrait.php b/src/Traits/ContainerAwareTrait.php index 6d4fa28..2ebde7f 100644 --- a/src/Traits/ContainerAwareTrait.php +++ b/src/Traits/ContainerAwareTrait.php @@ -36,10 +36,13 @@ trait ContainerAwareTrait /** * @param \Psr\Container\ContainerInterface $container + * + * @return \RetailCrm\Traits\ContainerAwareTrait */ - public function setContainer(ContainerInterface $container): void + public function setContainer(ContainerInterface $container): self { $this->container = $container; + return $this; } /** diff --git a/tests/RetailCrm/Test/TestCase.php b/tests/RetailCrm/Test/TestCase.php index 97433da..b51abfb 100644 --- a/tests/RetailCrm/Test/TestCase.php +++ b/tests/RetailCrm/Test/TestCase.php @@ -4,10 +4,11 @@ namespace RetailCrm\Test; use DateTime; use Psr\Container\ContainerInterface; +use RetailCrm\Builder\ContainerBuilder; use RetailCrm\Component\AppData; use RetailCrm\Component\Authenticator\TokenAuthenticator; use RetailCrm\Component\Environment; -use RetailCrm\Factory\ContainerFactory; +use RetailCrm\Component\Logger\StdoutLogger; use RetailCrm\Factory\FileItemFactory; use RetailCrm\Interfaces\AppDataInterface; use RetailCrm\Interfaces\AuthenticatorInterface; @@ -22,7 +23,7 @@ use RetailCrm\Interfaces\AuthenticatorInterface; * @link http://retailcrm.ru * @see https://help.retailcrm.ru */ -class TestCase extends \PHPUnit\Framework\TestCase +abstract class TestCase extends \PHPUnit\Framework\TestCase { private $container; @@ -34,9 +35,11 @@ class TestCase extends \PHPUnit\Framework\TestCase protected function getContainer($recreate = false): ContainerInterface { if (null === $this->container || $recreate) { - $this->container = ContainerFactory::withEnv(Environment::TEST) - ->withClient(new \GuzzleHttp\Client()) - ->create(); + $this->container = ContainerBuilder::create() + ->setEnv(Environment::TEST) + ->setClient(new \GuzzleHttp\Client()) + ->setLogger(new StdoutLogger()) + ->build(); } return $this->container; diff --git a/tests/RetailCrm/Tests/Component/ClientFactoryTest.php b/tests/RetailCrm/Tests/Builder/ClientFactoryTest.php similarity index 62% rename from tests/RetailCrm/Tests/Component/ClientFactoryTest.php rename to tests/RetailCrm/Tests/Builder/ClientFactoryTest.php index 8a2f7c5..921a7f4 100644 --- a/tests/RetailCrm/Tests/Component/ClientFactoryTest.php +++ b/tests/RetailCrm/Tests/Builder/ClientFactoryTest.php @@ -3,40 +3,41 @@ /** * PHP version 7.4 * - * @category ClientFactoryTest - * @package RetailCrm\Tests\Component + * @category ClientBuilderTest + * @package RetailCrm\Tests\Builder * @author RetailCRM * @license MIT * @link http://retailcrm.ru * @see http://help.retailcrm.ru */ -namespace RetailCrm\Tests\Component; +namespace RetailCrm\Tests\Builder; use RetailCrm\Component\AppData; use RetailCrm\Component\Authenticator\TokenAuthenticator; use RetailCrm\Component\ServiceLocator; -use RetailCrm\Factory\ClientFactory; +use RetailCrm\Builder\ClientBuilder; use RetailCrm\Test\TestCase; use RetailCrm\TopClient\Client; /** - * Class ClientFactoryTest + * Class ClientBuilderTest * - * @category ClientFactoryTest - * @package RetailCrm\Tests\Component + * @category ClientBuilderTest + * @package RetailCrm\Tests\Builder * @author RetailDriver LLC * @license MIT * @link http://retailcrm.ru * @see https://help.retailcrm.ru */ -class ClientFactoryTest extends TestCase +class ClientBuilderTest extends TestCase { public function testCreateClient() { - $client = ClientFactory::withContainer($this->getContainer()) - ->setAppData(AppData::create(AppData::OVERSEAS_ENDPOINT, 'appKey', 'helloworld')) + $client = ClientBuilder::create() + ->setContainer($this->getContainer()) + ->setAppData(new AppData(AppData::OVERSEAS_ENDPOINT, 'appKey', 'helloworld')) ->setAuthenticator(new TokenAuthenticator('appKey', 'token')) - ->create(); + ->build(); self::assertInstanceOf(Client::class, $client); self::assertInstanceOf(ServiceLocator::class, $client->getServiceLocator());