add Basic Shopware API

add Tests
This commit is contained in:
Marko 2022-06-28 17:20:37 +02:00
parent b5085fc848
commit 460411ab43
13 changed files with 2328 additions and 247 deletions

6
.env.test Normal file
View File

@ -0,0 +1,6 @@
# define your env variables for the test env here
KERNEL_CLASS='App\Kernel'
APP_SECRET='$ecretf0rt3st'
SYMFONY_DEPRECATIONS_HELPER=999999
PANTHER_APP_ENV=panther
PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots

10
.gitignore vendored
View File

@ -52,3 +52,13 @@
# Embedded web-server pid file # Embedded web-server pid file
/.web-server-pid /.web-server-pid
###> symfony/phpunit-bridge ###
.phpunit.result.cache
/phpunit.xml
###< symfony/phpunit-bridge ###
###> phpunit/phpunit ###
/phpunit.xml
.phpunit.result.cache
###< phpunit/phpunit ###

View File

@ -87,12 +87,7 @@
<path value="$PROJECT_DIR$/vendor/webmozart/assert" /> <path value="$PROJECT_DIR$/vendor/webmozart/assert" />
<path value="$PROJECT_DIR$/vendor/api-platform/core" /> <path value="$PROJECT_DIR$/vendor/api-platform/core" />
<path value="$PROJECT_DIR$/vendor/willdurand/negotiation" /> <path value="$PROJECT_DIR$/vendor/willdurand/negotiation" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-icu" />
<path value="$PROJECT_DIR$/vendor/symfony/form" />
<path value="$PROJECT_DIR$/vendor/symfony/options-resolver" />
<path value="$PROJECT_DIR$/vendor/sensio/framework-extra-bundle" /> <path value="$PROJECT_DIR$/vendor/sensio/framework-extra-bundle" />
<path value="$PROJECT_DIR$/vendor/symfony/http-client" />
<path value="$PROJECT_DIR$/vendor/symfony/http-client-contracts" />
<path value="$PROJECT_DIR$/vendor/ralouphie/getallheaders" /> <path value="$PROJECT_DIR$/vendor/ralouphie/getallheaders" />
<path value="$PROJECT_DIR$/vendor/psr/http-factory" /> <path value="$PROJECT_DIR$/vendor/psr/http-factory" />
<path value="$PROJECT_DIR$/vendor/psr/http-client" /> <path value="$PROJECT_DIR$/vendor/psr/http-client" />
@ -101,7 +96,47 @@
<path value="$PROJECT_DIR$/vendor/guzzlehttp/guzzle" /> <path value="$PROJECT_DIR$/vendor/guzzlehttp/guzzle" />
<path value="$PROJECT_DIR$/vendor/guzzlehttp/psr7" /> <path value="$PROJECT_DIR$/vendor/guzzlehttp/psr7" />
<path value="$PROJECT_DIR$/vendor/vin-sw/shopware-sdk" /> <path value="$PROJECT_DIR$/vendor/vin-sw/shopware-sdk" />
<path value="$PROJECT_DIR$/vendor/symfony/options-resolver" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-icu" />
<path value="$PROJECT_DIR$/vendor/symfony/form" />
<path value="$PROJECT_DIR$/vendor/masterminds/html5" />
<path value="$PROJECT_DIR$/vendor/myclabs/deep-copy" />
<path value="$PROJECT_DIR$/vendor/phar-io/version" />
<path value="$PROJECT_DIR$/vendor/phar-io/manifest" />
<path value="$PROJECT_DIR$/vendor/phpspec/prophecy" />
<path value="$PROJECT_DIR$/vendor/theseer/tokenizer" />
<path value="$PROJECT_DIR$/vendor/symfony/css-selector" />
<path value="$PROJECT_DIR$/vendor/symfony/dom-crawler" />
<path value="$PROJECT_DIR$/vendor/symfony/browser-kit" />
<path value="$PROJECT_DIR$/vendor/symfony/phpunit-bridge" />
<path value="$PROJECT_DIR$/vendor/phpunit/php-file-iterator" />
<path value="$PROJECT_DIR$/vendor/phpunit/phpunit" />
<path value="$PROJECT_DIR$/vendor/phpunit/php-timer" />
<path value="$PROJECT_DIR$/vendor/phpunit/php-text-template" />
<path value="$PROJECT_DIR$/vendor/phpunit/php-invoker" />
<path value="$PROJECT_DIR$/vendor/phpunit/php-code-coverage" />
<path value="$PROJECT_DIR$/vendor/sebastian/exporter" />
<path value="$PROJECT_DIR$/vendor/sebastian/diff" />
<path value="$PROJECT_DIR$/vendor/sebastian/type" />
<path value="$PROJECT_DIR$/vendor/sebastian/code-unit" />
<path value="$PROJECT_DIR$/vendor/sebastian/global-state" />
<path value="$PROJECT_DIR$/vendor/sebastian/resource-operations" />
<path value="$PROJECT_DIR$/vendor/sebastian/complexity" />
<path value="$PROJECT_DIR$/vendor/sebastian/recursion-context" />
<path value="$PROJECT_DIR$/vendor/sebastian/version" />
<path value="$PROJECT_DIR$/vendor/sebastian/environment" />
<path value="$PROJECT_DIR$/vendor/sebastian/object-enumerator" />
<path value="$PROJECT_DIR$/vendor/sebastian/object-reflector" />
<path value="$PROJECT_DIR$/vendor/sebastian/cli-parser" />
<path value="$PROJECT_DIR$/vendor/sebastian/code-unit-reverse-lookup" />
<path value="$PROJECT_DIR$/vendor/sebastian/comparator" />
<path value="$PROJECT_DIR$/vendor/sebastian/lines-of-code" />
</include_path> </include_path>
</component> </component>
<component name="PhpProjectSharedConfiguration" php_language_level="8.1" /> <component name="PhpProjectSharedConfiguration" php_language_level="8.1" />
<component name="PhpUnit">
<phpunit_settings>
<PhpUnitSettings configuration_file_path="$PROJECT_DIR$/phpunit.xml.dist" custom_loader_path="$PROJECT_DIR$/vendor/autoload.php" use_configuration_file="true" />
</phpunit_settings>
</component>
</project> </project>

10
.idea/phpunit.xml Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PHPUnit">
<option name="directories">
<list>
<option value="$PROJECT_DIR$/tests" />
</list>
</option>
</component>
</project>

View File

@ -23,7 +23,6 @@
"symfony/flex": "^2", "symfony/flex": "^2",
"symfony/form": "6.1.*", "symfony/form": "6.1.*",
"symfony/framework-bundle": "6.1.*", "symfony/framework-bundle": "6.1.*",
"symfony/http-client": "6.1.*",
"symfony/property-access": "6.1.*", "symfony/property-access": "6.1.*",
"symfony/property-info": "6.1.*", "symfony/property-info": "6.1.*",
"symfony/proxy-manager-bridge": "6.1.*", "symfony/proxy-manager-bridge": "6.1.*",
@ -36,9 +35,13 @@
"vin-sw/shopware-sdk": "^1.4" "vin-sw/shopware-sdk": "^1.4"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^9.5",
"symfony/browser-kit": "6.1.*",
"symfony/css-selector": "6.1.*",
"symfony/debug-bundle": "6.1.*", "symfony/debug-bundle": "6.1.*",
"symfony/maker-bundle": "^1.43", "symfony/maker-bundle": "^1.43",
"symfony/monolog-bundle": "^3.0", "symfony/monolog-bundle": "^3.0",
"symfony/phpunit-bridge": "^6.1",
"symfony/stopwatch": "6.1.*", "symfony/stopwatch": "6.1.*",
"symfony/web-profiler-bundle": "6.1.*" "symfony/web-profiler-bundle": "6.1.*"
}, },

2232
composer.lock generated

File diff suppressed because it is too large Load Diff

42
phpunit.xml.dist Normal file
View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- https://phpunit.readthedocs.io/en/latest/configuration.html -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="tests/bootstrap.php"
convertDeprecationsToExceptions="false"
>
<php>
<ini name="display_errors" value="1" />
<ini name="error_reporting" value="-1" />
<server name="APP_ENV" value="test" force="true" />
<server name="SHELL_VERBOSITY" value="-1" />
<server name="SYMFONY_PHPUNIT_REMOVE" value="" />
<server name="SYMFONY_PHPUNIT_VERSION" value="9.5" />
</php>
<testsuites>
<testsuite name="Project Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">src</directory>
</include>
</coverage>
<listeners>
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener" />
</listeners>
<!-- Run `composer require symfony/panther` before enabling this extension -->
<!--
<extensions>
<extension class="Symfony\Component\Panther\ServerExtension" />
</extensions>
-->
</phpunit>

View File

@ -3,28 +3,25 @@
namespace App\Command; namespace App\Command;
use App\Controller\ShopwareController; use App\Controller\ShopwareController;
use App\Entity\Orders;
use App\Repository\OrdersRepository; use App\Repository\OrdersRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Doctrine\ORM\Mapping as ORM;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Vin\ShopwareSdk\Client\AdminAuthenticator; use Vin\ShopwareSdk\Client\AdminAuthenticator;
use Vin\ShopwareSdk\Client\GrantType\ClientCredentialsGrantType; use Vin\ShopwareSdk\Client\GrantType\ClientCredentialsGrantType;
use Vin\ShopwareSdk\Data\Context; use Vin\ShopwareSdk\Data\Context;
use Vin\ShopwareSdk\Data\Criteria; use Vin\ShopwareSdk\Data\Criteria;
use Vin\ShopwareSdk\Data\Entity\EntityCollection;
use Vin\ShopwareSdk\Data\Entity\Order\OrderDefinition; use Vin\ShopwareSdk\Data\Entity\Order\OrderDefinition;
use Vin\ShopwareSdk\Data\Entity\Product\ProductDefinition; use Vin\ShopwareSdk\Data\Filter\EqualsAnyFilter;
use Vin\ShopwareSdk\Data\Filter\EqualsFilter; use Vin\ShopwareSdk\Data\Filter\EqualsFilter;
use Vin\ShopwareSdk\Factory\RepositoryFactory; use Vin\ShopwareSdk\Factory\RepositoryFactory;
@ -36,60 +33,74 @@ use Vin\ShopwareSdk\Factory\RepositoryFactory;
class SwGetOrdersCommand extends Command class SwGetOrdersCommand extends Command
{ {
private $ordersRepository; private $ordersRepository;
private $client;
private $logger; private $logger;
private $orderData;
public function __construct(OrdersRepository $ordersRepository, HttpClientInterface $client, LoggerInterface $logger ) public function __construct(OrdersRepository $ordersRepository, LoggerInterface $logger )
{ {
$this->ordersRepository = $ordersRepository; $this->ordersRepository = $ordersRepository;
$this->client = $client;
$this->logger = $logger; $this->logger = $logger;
parent::__construct(); parent::__construct();
} }
protected function configure(): void protected function configure(): void
{ {
$this // $this
->addArgument('arg1', InputArgument::OPTIONAL, 'Argument description') // ->addArgument('arg1', InputArgument::OPTIONAL, 'Argument description')
->addOption('option1', null, InputOption::VALUE_NONE, 'Option description') // ->addOption('option1', null, InputOption::VALUE_NONE, 'Option description')
; // ;
} }
protected function execute(InputInterface $input, OutputInterface $output): int protected function execute(InputInterface $input, OutputInterface $output): int
{ {
$io = new SymfonyStyle($input, $output); $io = new SymfonyStyle($input, $output);
$arg1 = $input->getArgument('arg1'); // $arg1 = $input->getArgument('arg1');
//
if ($arg1) { // if ($arg1) {
$io->note(sprintf('You passed an argument: %s', $arg1)); // $io->note(sprintf('You passed an argument: %s', $arg1));
} // }
//
if ($input->getOption('option1')) { // if ($input->getOption('option1')) {
// ... // // ...
} // }
//offene Bestellungen aus Datenbank holen //offene Bestellungen aus Datenbank holen
$orders = $this->getOrders(); $this->orderData = $this->getOrders();
if(!$orders) {
$io->error('Keine Bestellungen gefunden');
return Command::FAILURE;
}
//Bestelldetails aus SW holen //Bestelldetails aus SW holen
$this->getOrdersFromSW($orders); $this->getOrdersDataFromSW();
foreach ($this->orderData as $order) {
$io->info('Bestellung ID: '.$order->getId());
$io->info('Bestellung Order-ID: '.$order->getOrderId());
$io->info('Bestellung Data: '.var_export($order->getData(),1));
$this->saveOrdersData($order);
}
$io->success('Done!'); $io->success('Done!');
return Command::SUCCESS; return Command::SUCCESS;
} }
/**
* @return array
*/
private function getOrders():array private function getOrders():array
{ {
return $this->ordersRepository->findAll(); return $this->ordersRepository->findAll();
} }
/**
* @return \Vin\ShopwareSdk\Data\AccessToken|void
*/
private function shopwareAuth(){ private function shopwareAuth(){
try{ try{
@ -99,21 +110,16 @@ class SwGetOrdersCommand extends Command
}catch (\Exception $e){ }catch (\Exception $e){
$this->logger->error($e->getMessage()); $this->logger->error($e->getMessage());
} }
} }
/** /**
* @throws TransportExceptionInterface * holt alle fehlende Bestelldetails aus SW
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws DecodingExceptionInterface
* @throws ClientExceptionInterface
* @throws \Exception
*/ */
private function getOrdersFromSW(array $ordersArr):void private function getOrdersDataFromSW(): void
{ {
foreach ($this->orderData as $value) {
// Bei Shopware API anmelden
$context = new Context($_ENV['SHOPWARE_API_URL'], $this->shopwareAuth()); $context = new Context($_ENV['SHOPWARE_API_URL'], $this->shopwareAuth());
// Create the repository for the entity // Create the repository for the entity
@ -121,19 +127,33 @@ class SwGetOrdersCommand extends Command
// Create the criteria // Create the criteria
$criteria = new Criteria(); $criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('orderNumber', '9f002cc7de704a6ab31e1b410547cb97')); $criteria->addFilter(new EqualsFilter('id', $value->getOrderId()));
$criteria->addAssociation('order.orderDetails.product'); //Beziehungen zu Produkten holen
$criteria->addAssociation('lineItems');
// Using this criteria and the context object that you create from authentication step, you can retrieving the result try {
$orders = $orderRepository->search($criteria, $context); $orders = $orderRepository->search($criteria, $context);
$value->setData((array)$orders->getEntities());
} catch (\Exception $e) {
var_dump($orders); $this->logger->error($e->getMessage());
}
}
} }
/**
* @param $orderData
* @return void
*/
private function saveOrdersData($orderData): void
{
$orderData->setStatus = 1;
$this->ordersRepository->add($orderData,true);
}
} }

View File

@ -5,6 +5,8 @@ namespace App\Repository;
use App\Entity\Orders; use App\Entity\Orders;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ManagerRegistry;
use Symfony\Component\Validator\Validator\ValidatorInterface;
/** /**
* @extends ServiceEntityRepository<Orders> * @extends ServiceEntityRepository<Orders>
@ -16,13 +18,21 @@ use Doctrine\Persistence\ManagerRegistry;
*/ */
class OrdersRepository extends ServiceEntityRepository class OrdersRepository extends ServiceEntityRepository
{ {
public function __construct(ManagerRegistry $registry) private ValidatorInterface $validator;
public function __construct(ManagerRegistry $registry,ValidatorInterface $validator)
{ {
parent::__construct($registry, Orders::class); parent::__construct($registry, Orders::class);
$this->validator = $validator;
} }
public function add(Orders $entity, bool $flush = false): void public function add(Orders $entity, bool $flush = false): void
{ {
$errors = $this->validator->validate($entity);
if (count($errors) > 0) {
var_dump($errors);
}
$this->getEntityManager()->persist($entity); $this->getEntityManager()->persist($entity);
if ($flush) { if ($flush) {
@ -30,6 +40,18 @@ class OrdersRepository extends ServiceEntityRepository
} }
} }
public function update(Orders $entity, bool $flush = false): void
{
$order = $this->getEntityManager()->find(Orders::class, $entity->getId());
if(!$order) {
throw $this->createNotFoundException('Order not found: '.$entity->getId());
}
}
public function remove(Orders $entity, bool $flush = false): void public function remove(Orders $entity, bool $flush = false): void
{ {
$this->getEntityManager()->remove($entity); $this->getEntityManager()->remove($entity);

View File

@ -61,6 +61,20 @@
"config/packages/nelmio_cors.yaml" "config/packages/nelmio_cors.yaml"
] ]
}, },
"phpunit/phpunit": {
"version": "9.5",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "9.3",
"ref": "a6249a6c4392e9169b87abf93225f7f9f59025e6"
},
"files": [
".env.test",
"phpunit.xml.dist",
"tests/bootstrap.php"
]
},
"sensio/framework-extra-bundle": { "sensio/framework-extra-bundle": {
"version": "6.2", "version": "6.2",
"recipe": { "recipe": {
@ -149,6 +163,21 @@
"config/packages/monolog.yaml" "config/packages/monolog.yaml"
] ]
}, },
"symfony/phpunit-bridge": {
"version": "6.1",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "5.3",
"ref": "97cb3dc7b0f39c7cfc4b7553504c9d7b7795de96"
},
"files": [
".env.test",
"bin/phpunit",
"phpunit.xml.dist",
"tests/bootstrap.php"
]
},
"symfony/routing": { "symfony/routing": {
"version": "6.1", "version": "6.1",
"recipe": { "recipe": {

16
tests/OrdersTest.php Normal file
View File

@ -0,0 +1,16 @@
<?php
namespace App\Tests;
use ApiPlatform\Core\Bridge\Symfony\Bundle\Test\ApiTestCase;
class OrdersTest extends ApiTestCase
{
public function testSomething(): void
{
$response = static::createClient()->request('GET', '/');
$this->assertResponseIsSuccessful();
$this->assertJsonContains(['@id' => '/']);
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace App\Tests\Shopware;
use PHPUnit\Framework\TestCase;
class OrdersTest extends TestCase
{
public function testSomething(): void
{
$this->assertTrue(true);
}
}

11
tests/bootstrap.php Normal file
View File

@ -0,0 +1,11 @@
<?php
use Symfony\Component\Dotenv\Dotenv;
require dirname(__DIR__).'/vendor/autoload.php';
if (file_exists(dirname(__DIR__).'/config/bootstrap.php')) {
require dirname(__DIR__).'/config/bootstrap.php';
} elseif (method_exists(Dotenv::class, 'bootEnv')) {
(new Dotenv())->bootEnv(dirname(__DIR__).'/.env');
}