<?php
declare(strict_types=1);
/*
* (c) shopware AG <info@shopware.com>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Swag\AmazonPay\Components\Button;
use Psr\Log\LoggerInterface;
use Shopware\Core\PlatformRequest;
use Shopware\Storefront\Page\Account\Login\AccountLoginPageLoadedEvent;
use Shopware\Storefront\Page\Account\Profile\AccountProfilePageLoadedEvent;
use Shopware\Storefront\Page\Checkout\Cart\CheckoutCartPageLoadedEvent;
use Shopware\Storefront\Page\Checkout\Offcanvas\OffcanvasCartPageLoadedEvent;
use Shopware\Storefront\Page\Checkout\Register\CheckoutRegisterPageLoadedEvent;
use Shopware\Storefront\Page\PageLoadedEvent;
use Shopware\Storefront\Page\Product\ProductPageLoadedEvent;
use Swag\AmazonPay\Components\Button\Login\Hydrator\AmazonLoginButtonPayloadHydratorInterfaceV3;
use Swag\AmazonPay\Components\Button\Pay\Hydrator\AmazonPayButtonPayloadHydratorInterfaceV2;
use Swag\AmazonPay\Components\Button\Validation\AbstractExcludedProductValidator;
use Swag\AmazonPay\Components\Client\ClientProviderInterface;
use Swag\AmazonPay\Components\Config\ConfigServiceInterface;
use Swag\AmazonPay\Components\Config\Struct\AmazonPayConfigStruct;
use Swag\AmazonPay\Components\Config\Validation\Exception\ConfigValidationException;
use Swag\AmazonPay\Installer\RuleInstaller;
use Swag\AmazonPay\Storefront\Page\Extension\AmazonLoginButtonExtension;
use Swag\AmazonPay\Storefront\Page\Extension\AmazonPayButtonExtension;
use Swag\AmazonPay\Storefront\Page\Extension\ExtensionService;
use Swag\AmazonPay\Util\Helper\AmazonPayPaymentMethodHelperInterface;
use Swag\AmazonPay\Util\Language\LanguageProviderInterface;
use Symfony\Component\Routing\RouterInterface;
class ButtonProvider implements ButtonProviderInterface
{
/**
* @var ConfigServiceInterface
*/
private $configService;
/**
* @var RouterInterface
*/
private $router;
/**
* @var LanguageProviderInterface
*/
private $languageProvider;
/**
* @var AmazonPayConfigStruct
*/
private $pluginConfig;
/**
* @var AmazonPayPaymentMethodHelperInterface
*/
private $paymentMethodHelper;
/**
* @var ClientProviderInterface
*/
private $clientProvider;
/**
* @var AmazonPayButtonPayloadHydratorInterfaceV2
*/
private $payButtonPayloadHydrator;
/**
* @var AmazonLoginButtonPayloadHydratorInterfaceV3
*/
private $loginButtonPayloadHydrator;
/**
* @var LoggerInterface
*/
private $logger;
/**
* @var AbstractExcludedProductValidator
*/
private $excludedProductValidator;
/**
* @var string
*/
private $shopwareVersion;
/**
* @var ExtensionService
*/
private $extensionService;
public function __construct(
ConfigServiceInterface $configService,
LanguageProviderInterface $languageProvider,
RouterInterface $router,
AmazonPayPaymentMethodHelperInterface $paymentMethodHelper,
ClientProviderInterface $clientProvider,
AmazonPayButtonPayloadHydratorInterfaceV2 $payButtonPayloadHydrator,
AmazonLoginButtonPayloadHydratorInterfaceV3 $loginButtonPayloadHydrator,
LoggerInterface $logger,
AbstractExcludedProductValidator $excludedProductValidator,
string $shopwareVersion,
ExtensionService $extensionService
) {
$this->configService = $configService;
$this->router = $router;
$this->languageProvider = $languageProvider;
$this->paymentMethodHelper = $paymentMethodHelper;
$this->clientProvider = $clientProvider;
$this->payButtonPayloadHydrator = $payButtonPayloadHydrator;
$this->loginButtonPayloadHydrator = $loginButtonPayloadHydrator;
$this->logger = $logger;
$this->excludedProductValidator = $excludedProductValidator;
$this->shopwareVersion = $shopwareVersion;
$this->extensionService = $extensionService;
}
public function getAmazonPayButton(PageLoadedEvent $event): ?AmazonPayButtonExtension
{
if ($this->isAmazonPayButtonAvailable($event) === false) {
return null;
}
if ($this->excludedProductValidator->eventContainsExcludedProducts($event)) {
return null;
}
$oneClickCheckout = true;
$buttonExtension = new AmazonPayButtonExtension();
$this->extensionService->setBaseButtonExtensionValues(
$buttonExtension,
$this->getCheckoutLanguage($event),
$event->getRequest()->isSecure(),
$event->getSalesChannelContext()->getSalesChannel()->getId()
);
$buttonExtension->setProductType(AmazonPayButtonExtension::PRODUCT_TYPE_PAY_AND_SHIP);
if (\version_compare($this->shopwareVersion, '6.4.0', '>=')) {
$buttonExtension->setClearCartUrl(
$this->router->generate(
'frontend.swag.amazon.pay.clear.cart'
)
);
} else {
$buttonExtension->setClearCartUrl(
$this->router->generate(
'sales-channel-api.action.swag.amazon.pay.clear.cart',
[
'version' => PlatformRequest::API_VERSION,
]
)
);
}
$buttonExtension->setAddLineItemUrl($this->router->generate('frontend.checkout.line-item.add'));
// Per default the placement is set to Swag\AmazonPay\Storefront\Page\Extension\AbstractAmazonButtonExtension::BUTTON_PLACEMENT_OTHER
if ($event instanceof CheckoutCartPageLoadedEvent || $event instanceof OffcanvasCartPageLoadedEvent) {
$buttonExtension->setPlacement(AmazonPayButtonExtension::BUTTON_PLACEMENT_CART);
}
if ($event instanceof ProductPageLoadedEvent) {
$buttonExtension->setPlacement(AmazonPayButtonExtension::BUTTON_PLACEMENT_PRODUCT);
}
$salesChannelContext = $event->getSalesChannelContext();
$salesChannelId = $salesChannelContext->getSalesChannel()->getId();
try {
$payload = $this->payButtonPayloadHydrator->hydratePayload(
$salesChannelId,
$salesChannelContext->getContext(),
$oneClickCheckout
);
$payloadJson = (string) \json_encode($payload, \JSON_UNESCAPED_SLASHES | \JSON_FORCE_OBJECT);
$signature = $this->getButtonSignature(
$salesChannelId,
$payloadJson
);
} catch (\Throwable $e) {
$this->logger->error('Could not get button signature', ['Exception' => $e->getMessage()]);
return null;
}
$buttonExtension->setPayload($payloadJson);
$buttonExtension->setSignature($signature);
return $buttonExtension;
}
/**
* @param AccountLoginPageLoadedEvent|AccountProfilePageLoadedEvent $event
*/
public function getAmazonLoginButton(PageLoadedEvent $event): ?AmazonLoginButtonExtension
{
if ($this->isAmazonLoginButtonAvailable($event) === false) {
return null;
}
$salesChannelContext = $event->getSalesChannelContext();
$salesChannelId = $salesChannelContext->getSalesChannel()->getId();
try {
$payloadJson = (string) \json_encode(
$this->loginButtonPayloadHydrator->hydrate($salesChannelId, $salesChannelContext->getContext(), $event),
\JSON_UNESCAPED_SLASHES
);
$signature = $this->getButtonSignature($salesChannelId, $payloadJson);
} catch (\Throwable $e) {
$this->logger->error('Could not get button signature', ['Exception' => $e->getMessage()]);
return null;
}
$buttonExtension = new AmazonLoginButtonExtension();
$this->extensionService->setBaseButtonExtensionValues(
$buttonExtension,
$this->getCheckoutLanguage($event),
$event->getRequest()->isSecure(),
$event->getSalesChannelContext()->getSalesChannel()->getId()
);
$buttonExtension->setPlacement(AmazonPayButtonExtension::BUTTON_PLACEMENT_OTHER);
$buttonExtension->setPayload($payloadJson);
$buttonExtension->setSignature($signature);
return $buttonExtension;
}
private function isAmazonLoginButtonAvailable(PageLoadedEvent $event): bool
{
$salesChannel = $event->getSalesChannelContext()->getSalesChannel();
try {
$this->pluginConfig = $this->configService->getPluginConfig($salesChannel->getId());
} catch (ConfigValidationException $e) {
return false;
}
if (!$this->pluginConfig->isDisplayLoginButtonOnRegistrationPage()) {
return false;
}
return true;
}
private function isAmazonPayButtonAvailable(PageLoadedEvent $event): bool
{
$currencyIsoCode = $event->getSalesChannelContext()->getCurrency()->getIsoCode();
if (!\in_array($currencyIsoCode, RuleInstaller::VALID_CURRENCIES, true)) {
return false;
}
// Payment method inactive or unassigned to sales channel
if ($this->paymentMethodHelper->isAmazonPayActive($event->getSalesChannelContext()) === false) {
return false;
}
$salesChannel = $event->getSalesChannelContext()->getSalesChannel();
// Invalid plugin configuration
try {
$this->pluginConfig = $this->configService->getPluginConfig($salesChannel->getId());
} catch (ConfigValidationException $e) {
return false;
}
if ($event instanceof ProductPageLoadedEvent && !$this->pluginConfig->isDisplayButtonOnProductPage()) {
return false;
}
if ($event instanceof CheckoutRegisterPageLoadedEvent && !$this->pluginConfig->isDisplayButtonOnCheckoutRegisterPage()) {
return false;
}
return true;
}
private function getCheckoutLanguage(PageLoadedEvent $event): string
{
$salesChannel = $event->getSalesChannelContext()->getSalesChannel();
return $this->languageProvider->getAmazonPayButtonLanguage(
$salesChannel->getLanguageId(),
$event->getContext()
);
}
private function getButtonSignature(string $salesChannelId, string $payload): string
{
$client = $this->clientProvider->getClient($salesChannelId);
return $client->generateButtonSignature($payload);
}
}