Skip to content

Commit

Permalink
Merge branch 'main' into next-36521/in-app-purchases
Browse files Browse the repository at this point in the history
  • Loading branch information
Bird87ZA authored and lernhart committed Dec 3, 2024
2 parents e5b9b31 + 4d78e47 commit 5ab40f7
Show file tree
Hide file tree
Showing 58 changed files with 2,208 additions and 283 deletions.
12 changes: 9 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,22 @@
"psr/http-factory": "^1.0",
"psr/http-factory-implementation": "*",
"psr/http-message": "^1.0 || ^2.0",
"psr/simple-cache": "^3.0"
"psr/simple-cache": "^3.0",
"strobotti/php-jwk": "^1.4"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.16",
"infection/infection": "^0.26.21",
"infection/infection": "^0.29",
"nyholm/psr7": "^1.7.0",
"nyholm/psr7-server": "^1.0",
"php-http/curl-client": "^2.2",
"phpstan/phpstan": "^1.10.14",
"phpunit/phpunit": "^10.1"
"phpunit/phpunit": "^11.4",
"async-aws/dynamo-db": "~3.2",
"symfony/polyfill-uuid": "^1.31"
},
"suggest": {
"async-aws/dynamo-db": "For using the DynamoDBRepository"
},
"autoload": {
"psr-4": {
Expand Down
11 changes: 9 additions & 2 deletions examples/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,16 @@
use Shopware\App\SDK\AppLifecycle;
use Shopware\App\SDK\Authentication\ResponseSigner;
use Shopware\App\SDK\Context\ContextResolver;
use Shopware\App\SDK\Context\InAppPurchase\InAppPurchaseProvider;
use Shopware\App\SDK\Context\InAppPurchase\SBPStoreKeyFetcher;
use Shopware\App\SDK\HttpClient\ClientFactory;
use Shopware\App\SDK\Response\ActionButtonResponse;
use Shopware\App\SDK\Response\PaymentResponse;
use Shopware\App\SDK\Registration\RegistrationService;
use Shopware\App\SDK\Shop\ShopResolver;
use Shopware\App\SDK\TaxProvider\CalculatedTax;
use Shopware\App\SDK\TaxProvider\TaxProviderResponseBuilder;
use Shopware\App\SDK\Test\MockShop;

require __DIR__ . '/../vendor/autoload.php';
require __DIR__ . '/helper.php';
Expand All @@ -38,7 +42,10 @@
$registrationService = new RegistrationService($app, $fileShopRepository);
$shopResolver = new ShopResolver($fileShopRepository);
$appLifecycle = new AppLifecycle($registrationService, $shopResolver, $fileShopRepository);
$contextResolver = new ContextResolver();
$inAppPurchaseProvider = new InAppPurchaseProvider(new SBPStoreKeyFetcher(
(new ClientFactory())->createClient(new MockShop('shopId', 'shopUrl', 'shopSecret'))
));
$contextResolver = new ContextResolver($inAppPurchaseProvider);
$signer = new ResponseSigner();

if (str_starts_with($serverRequest->getUri()->getPath(), '/register/authorize')) {
Expand Down Expand Up @@ -116,7 +123,7 @@
$signer = new ResponseSigner();

send($signer->signResponse(PaymentResponse::paid(), $shop));
} elseif(str_starts_with($serverRequest->getUri()->getPath(), '/module/test')) {
} elseif (str_starts_with($serverRequest->getUri()->getPath(), '/module/test')) {
$shop = $shopResolver->resolveShop($serverRequest);
$module = $contextResolver->assembleModule($serverRequest, $shop);

Expand Down
8 changes: 8 additions & 0 deletions infection.json5
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
},
"mutators": {
"@default": true,
"LogicalOrAllSubExprNegation": false, // these mutants are false friends
"LogicalOrSingleSubExprNegation": false, // these mutants are false friends
"CastFloat": {
ignore: [
'Shopware\\App\\SDK\\Context\\SalesChannelContext\\Currency::getTaxFreeFrom'
Expand All @@ -31,5 +33,11 @@
'Shopware\\App\\SDK\\Shop\\ShopResolver::resolveFromSource'
]
},
"TrueValue": {
ignore: [
// The retry mechanism is tested, the mutation is a false friend
'Shopware\\App\\SDK\\Context\\InAppPurchase\\InAppPurchaseProvider::decodePurchases',
]
}
}
}
2 changes: 1 addition & 1 deletion phpunit.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.1/phpunit.xsd"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/11.4/phpunit.xsd"
bootstrap="vendor/autoload.php"
cacheDirectory=".phpunit.cache"
executionOrder="depends,defects"
Expand Down
97 changes: 97 additions & 0 deletions src/Adapter/DynamoDB/DynamoDBRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php

declare(strict_types=1);

namespace Shopware\App\SDK\Adapter\DynamoDB;

use AsyncAws\DynamoDb\DynamoDbClient;
use AsyncAws\DynamoDb\Input\DeleteItemInput;
use AsyncAws\DynamoDb\Input\GetItemInput;
use AsyncAws\DynamoDb\Input\PutItemInput;
use Shopware\App\SDK\Shop\ShopInterface;
use Shopware\App\SDK\Shop\ShopRepositoryInterface;

/**
* @implements ShopRepositoryInterface<DynamoDBShop>
*/
class DynamoDBRepository implements ShopRepositoryInterface
{
public function __construct(private readonly DynamoDbClient $client, private readonly string $tableName)
{
}

public function createShopStruct(string $shopId, string $shopUrl, string $shopSecret): ShopInterface
{
return new DynamoDBShop($shopId, $shopUrl, $shopSecret);
}

public function createShop(ShopInterface $shop): void
{
$this->client->putItem(new PutItemInput([
'TableName' => $this->tableName,
'Item' => [
'id' => ['S' => $shop->getShopId()],
'active' => ['BOOL' => $shop->isShopActive() ? '1' : '0'],
'url' => ['S' => $shop->getShopUrl()],
'secret' => ['S' => $shop->getShopSecret()],
'clientId' => ['S' => (string) $shop->getShopClientId()],
'clientSecret' => ['S' => (string) $shop->getShopClientSecret()],
],
]));
}

public function getShopFromId(string $shopId): ShopInterface|null
{
$item = $this->client->getItem(new GetItemInput([
'TableName' => $this->tableName,
'Key' => [
'id' => ['S' => $shopId],
],
]))->getItem();

if (!$item) {
return null;
}

$shopClientId = $item['clientId']->getS();
$shopClientSecret = $item['clientSecret']->getS();

if ($shopClientSecret === '') {
$shopClientSecret = null;
}

if ($shopClientId === '') {
$shopClientId = null;
}

$active = $item['active']->getBool();

if ($active === null) {
$active = false;
}

return new DynamoDBShop(
$item['id']->getS() ?? '',
$item['url']->getS() ?? '',
$item['secret']->getS() ?? '',
$shopClientId,
$shopClientSecret,
$active,
);
}

public function updateShop(ShopInterface $shop): void
{
$this->createShop($shop);
}

public function deleteShop(string $shopId): void
{
$this->client->deleteItem(new DeleteItemInput([
'TableName' => $this->tableName,
'Key' => [
'id' => ['S' => $shopId],
],
]));
}
}
66 changes: 66 additions & 0 deletions src/Adapter/DynamoDB/DynamoDBShop.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

declare(strict_types=1);

namespace Shopware\App\SDK\Adapter\DynamoDB;

use Shopware\App\SDK\Shop\ShopInterface;

class DynamoDBShop implements ShopInterface
{
public function __construct(public string $shopId, public string $shopUrl, public string $shopSecret, public ?string $shopClientId = null, public ?string $shopClientSecret = null, public bool $active = false)
{
}

public function isShopActive(): bool
{
return $this->active;
}

public function getShopId(): string
{
return $this->shopId;
}

public function getShopUrl(): string
{
return $this->shopUrl;
}

public function getShopSecret(): string
{
return $this->shopSecret;
}

public function getShopClientId(): ?string
{
return $this->shopClientId;
}

public function getShopClientSecret(): ?string
{
return $this->shopClientSecret;
}

public function setShopApiCredentials(string $clientId, string $clientSecret): ShopInterface
{
$this->shopClientId = $clientId;
$this->shopClientSecret = $clientSecret;

return $this;
}

public function setShopUrl(string $url): ShopInterface
{
$this->shopUrl = $url;

return $this;
}

public function setShopActive(bool $active): ShopInterface
{
$this->active = $active;

return $this;
}
}
12 changes: 5 additions & 7 deletions src/Context/ActionSource.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,20 @@

namespace Shopware\App\SDK\Context;

use Shopware\App\SDK\Context\InAppPurchase\InAppPurchase;
use Shopware\App\SDK\Framework\Collection;

class ActionSource
{
/**
* @param string $url The shop url
* @param string $appVersion The installed App version
* @param string[] $inAppPurchases The active in-app-purchases
* @param Collection<InAppPurchase> $inAppPurchases The active in-app-purchases
*/
public function __construct(
public readonly string $url,
public readonly string $appVersion,
public readonly array $inAppPurchases = [],
public readonly Collection $inAppPurchases,
) {
}

public function hasInAppPurchase(string $inAppPurchase): bool
{
return \in_array($inAppPurchase, $this->inAppPurchases, true);
}
}
Loading

0 comments on commit 5ab40f7

Please sign in to comment.