docs: add docs
All checks were successful
CI / Get Changed Files (pull_request) Successful in 30s
Pull Request Labeler / labeler (pull_request_target) Successful in 15s
CI / Backend Tests (pull_request) Has been skipped
Label PRs based on size / Check PR size (pull_request) Successful in 29s
CI / eslint (pull_request) Has been skipped
CI / Checkstyle Main (pull_request) Has been skipped
CI / oxlint (pull_request) Has been skipped
CI / Docker frontend validation (pull_request) Has been skipped
CI / prettier (pull_request) Has been skipped
CI / Docker backend validation (pull_request) Has been skipped
CI / test-build (pull_request) Has been skipped
CI / Playwright (pull_request) Has been skipped
Claude PR Review / claude-code (pull_request) Successful in 1m42s

This commit is contained in:
Phan Huy Tran 2025-06-11 12:24:18 +02:00
commit 9cb813bf41
80 changed files with 4490 additions and 0 deletions

View file

@ -0,0 +1,139 @@
<?php declare(strict_types=1);
namespace Neusta\IntexClient\Connection\Model;
use GuzzleHttp\Exception\RequestException;
use Psr\Http\Message\ResponseInterface;
use Psr\Log\LoggerInterface;
use Neusta\IntexClientConfig\Model\Config\Config;
use Neusta\IntexClientConfig\Provider\JsonConfigProvider;
use \GuzzleHttp\Client as GuzzleHttpClient;
use \GuzzleHttp\Event\BeforeEvent;
use \GuzzleHttp\Event\CompleteEvent;
use function sprintf;
abstract class Connection
{
protected const HTTP_STATUS_CODE_OK = 200;
/**
* @var GuzzleHttpClient
*/
protected $httpClient;
/**
* @var Config
*/
protected $serverConfig;
/**
* @var LoggerInterface
*/
protected $logger;
public function __construct(JsonConfigProvider $configProvider, LoggerInterface $logger)
{
$this->logger = $logger;
$this->serverConfig = $configProvider->getConfig('server');
$this->httpClient = new GuzzleHttpClient(
$this->getHttpClientOptions()
);
$this->initHttpEventEmitter();
}
protected function authenticate(): bool
{
$result = false;
$response = $this->createPost(
$this->serverConfig->getAuthUri()
);
$statusCode = $response->getStatusCode();
if ($statusCode === self::HTTP_STATUS_CODE_OK) {
$this->logger->info('authentication successful');
$result = true;
} else {
$this->logger->info(
sprintf('authentication failed with Code: %s', $statusCode)
);
}
return $result;
}
protected function createPost(string $uri, array $options = []): ?ResponseInterface
{
$result = null;
$request = $this->httpClient->postAsync($uri, $options);
$request->then(
static function (ResponseInterface $response) {
$result = $response;
},
function (RequestException $exception) {
$this->logger->info(
sprintf('Crucial Error: %s \n Trace: %u', $exception->getMessage(), $exception->getTraceAsString())
);
}
);
return $result;
}
protected function createGet(string $uri, array $options = []): ?ResponseInterface
{
$result = null;
$request = $this->httpClient->getAsync($uri, $options);
$request->then(
static function (ResponseInterface $response) {
$result = $response;
},
function (RequestException $exception) {
$this->logger->info(
sprintf('Crucial Error: %s \n Trace: %u', $exception->getMessage(), $exception->getTraceAsString())
);
}
);
return $result;
}
protected function initHttpEventEmitter(): void
{
// initialize the EventEmitters to get a good Logging whether the Request was send
// or failed
$this->httpClient->getEmitter()->on('before', static function (BeforeEvent $event) {
$this->logger->info(
sprintf('About to send Request: %s', $event->getRequest())
);
});
$this->httpClient->getEmitter()->on('complete', static function (CompleteEvent $event) {
$this->logger->info(
sprintf('Request %s finished', $event->getRequest())
);
});
$this->httpClient->getEmitter()->on('error', static function (ErrorEvent $event) {
$this->logger->info(
sprintf('Request %s failed', $event->getRequest())
);
});
}
protected function getHttpClientOptions(): array
{
// Configure Base URL for all ongoing Requests and set Cookies to true,
// so we can handle the auth cookie over and over again without using authenticate() multiple times
return [
'base_url' => $this->serverConfig->getBaseUrl(),
'cookies' => true
];
}
}

View file

@ -0,0 +1,33 @@
<?php declare(strict_types=1);
namespace Neusta\IntexClient\Connection\Model;
use Neusta\IntexClientConfig\Model\Config\Config;
use Neusta\IntexClientConfig\Provider\JsonConfigProvider;
use Psr\Log\LoggerInterface;
use function json_decode;
class CustomerConnection extends Connection
{
/**
* @var Config
*/
private $customerConfig;
public function __construct(JsonConfigProvider $configProvider, LoggerInterface $logger)
{
parent::__construct($configProvider, $logger);
$this->customerConfig = $configProvider->getConfig('customer');
}
public function loadCustomerData(): array
{
$response = $this->createGet(
$this->customerConfig->getCustomerUri()
);
return json_decode($response->getBody(), true);
}
}

View file

@ -0,0 +1,28 @@
<?php declare(strict_types=1);
namespace Neusta\IntexCustomer\Controller;
use Neusta\IntexClient\Connection\Model\CustomerConnection;
class CustomerDataController
{
/**
* @var CustomerConnection
*/
private $connection;
public function __construct(\Neusta\IntexClient\Connection\Factory $connectionFactory, \Neusta\IntexCustomer\Handler\DataHandler $dataHandler)
{
$this->connection = $connectionFactory->create('customer');
$this->customerDataHandler = $dataHandler;
}
public function getCustomerData(): void
{
$customerData = $this->connection->loadCustomerData();
$this->customerDataHandler->saveCustomerData($customerData);
}
}

View file

@ -0,0 +1,27 @@
<?php declare(strict_types=1);
namespace Neusta\IntexClient\Connection;
use Neusta\IntexClient\Connection\Model\Connection;
use function class_exists;
use function sprintf;
use function ucwords;
use function strtolower;
class Factory
{
public static function create(string $connectionType): Connection
{
$connectionPath = sprintf(
'\Neusta\IntexClient\Model\Connection\%sConnection',
ucwords(strtolower($connectionType))
);
if (class_exists($connectionPath)) {
return new $connectionPath();
}
throw new \RuntimeException('Invalid Connection Type given');
}
}

View file

@ -0,0 +1,28 @@
<?xml version="1.0" ?>
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
<table name="neusta_intex_import" resource="default" engine="innodb"
comment="Neusta IntexImport Logging Table">
<column xsi:type="int" name="value_id" padding="11" unsigned="false" nullable="false" identity="true" comment="Value ID"/>
<column xsi:type="smallint" name="attribute_id" padding="5" unsigned="true" nullable="false" identity="false" default="0" comment="Attribute ID"/>
<column xsi:type="smallint" name="store_id" padding="5" unsigned="true" nullable="false" identity="false" default="0" comment="Store ID"/>
<column xsi:type="int" name="entity_id" padding="10" unsigned="true" nullable="false" identity="false" default="0" comment="Entity ID"/>
<column xsi:type="datetime" name="value" on_update="false" nullable="true" comment="Value"/>
<constraint xsi:type="primary" referenceId="PRIMARY">
<column name="value_id"/>
</constraint>
<constraint xsi:type="foreign" referenceId="CAT_PRD_ENTT_DTIME_ATTR_ID_EAV_ATTR_ATTR_ID" table="catalog_product_entity_datetime" column="attribute_id" referenceTable="eav_attribute" referenceColumn="attribute_id" onDelete="CASCADE"/>
<constraint xsi:type="foreign" referenceId="CAT_PRD_ENTT_DTIME_ENTT_ID_CAT_PRD_ENTT_ENTT_ID" table="catalog_product_entity_datetime" column="entity_id" referenceTable="catalog_product_entity" referenceColumn="entity_id" onDelete="CASCADE"/>
<constraint xsi:type="foreign" referenceId="CATALOG_PRODUCT_ENTITY_DATETIME_STORE_ID_STORE_STORE_ID" table="catalog_product_entity_datetime" column="store_id" referenceTable="store" referenceColumn="store_id" onDelete="CASCADE"/>
<constraint xsi:type="unique" referenceId="CATALOG_PRODUCT_ENTITY_DATETIME_ENTITY_ID_ATTRIBUTE_ID_STORE_ID">
<column name="entity_id"/>
<column name="attribute_id"/>
<column name="store_id"/>
</constraint>
<index referenceId="CATALOG_PRODUCT_ENTITY_DATETIME_ATTRIBUTE_ID" indexType="btree">
<column name="attribute_id"/>
</index>
<index referenceId="CATALOG_PRODUCT_ENTITY_DATETIME_STORE_ID" indexType="btree">
<column name="store_id"/>
</index>
</table>
</schema>

View file

@ -0,0 +1,39 @@
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
use Neusta\IntexClient\Connection\Factory;
use Neusta\IntexClient\Connection\Model\CustomerConnection;
class FactoryTest extends TestCase
{
/**
* @var Factory
*/
private $subject;
public function setUp()
{
$this->subject = new Factory();
}
/**
* @test
*/
public function createMustReturnInstanceOfCustomerConnectionWithValidIdentifierGiven()
{
$expectedInstance = $this->subject->create('customer');
self::assertInstanceOf(CustomerConnection::class, $expectedInstance);
}
/**
* @test
* @throws RuntimeException
*/
public function createMustThrowRuntimeExceptionIfInvalidIdentifierIsGiven()
{
$unexpectedInstance = $this->subject->create('fooBar');
self::expectException(RuntimeException::class);
}
}

View file

@ -0,0 +1,21 @@
{
"name": "neusta/m2-intex-client",
"license": "proprietary",
"description": "Client for Magento2 Intex Import/Export",
"type": "magento2-module",
"version": "0.0.1",
"require": {
"php": "~7.1.0|~7.2.0|~7.3.0",
"magento/framework": "~101.0",
"neusta/m2-intex-base": "0.0.1",
"guzzlehttp/guzzle": "6.3.*"
},
"autoload": {
"files": [
"registration.php"
],
"psr-4": {
"Neusta\\IntexClient\\": "src"
}
}
}

View file

@ -0,0 +1,33 @@
<?php
include(dirname(__FILE__).'/../bootstrap/Propel.php');
$t = new lime_test(13);
$t->comment('Empty Information');
$emptyComparedInformation = new ComparedNaturalModuleInformation(array());
$t->is($emptyComparedInformation->getCatalogSign(), ComparedNaturalModuleInformation::EMPTY_SIGN, 'Has no catalog sign');
$t->is($emptyComparedInformation->getSourceSign(), ComparedNaturalModuleInformation::SIGN_CREATE, 'Source has to be created');
$t->comment('Perfect Module');
$criteria = new Criteria();
$criteria->add(NaturalmodulenamePeer::NAME, 'SMTAB');
$moduleName = NaturalmodulenamePeer::doSelectOne($criteria);
$t->is($moduleName->getName(), 'SMTAB', 'Right modulename selected');
$comparedInformation = $moduleName->loadNaturalModuleInformation();
$t->is($comparedInformation->getSourceSign(), ComparedNaturalModuleInformation::SIGN_OK, 'Source sign shines global');
$t->is($comparedInformation->getCatalogSign(), ComparedNaturalModuleInformation::SIGN_OK, 'Catalog sign shines global');
$infos = $comparedInformation->getNaturalModuleInformations();
foreach($infos as $info)
{
$env = $info->getEnvironmentName();
$t->is($info->getSourceSign(), ComparedNaturalModuleInformation::SIGN_OK, 'Source sign shines at ' . $env);
if($env != 'SVNENTW')
{
$t->is($info->getCatalogSign(), ComparedNaturalModuleInformation::SIGN_OK, 'Catalog sign shines at ' . $info->getEnvironmentName());
}
else
{
$t->is($info->getCatalogSign(), ComparedNaturalModuleInformation::EMPTY_SIGN, 'Catalog sign is empty at ' . $info->getEnvironmentName());
}
}
?>