Skip to content

Commit

Permalink
fix(checkout): fix delivery options not loading in ps 1.7 (#270)
Browse files Browse the repository at this point in the history
INT-596
  • Loading branch information
EdieLemoine authored Aug 16, 2024
1 parent 05afd1c commit 11c6a46
Show file tree
Hide file tree
Showing 9 changed files with 204 additions and 56 deletions.
16 changes: 11 additions & 5 deletions config/pdk.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@
use MyParcelNL\PrestaShop\Pdk\Webhook\Repository\PsWebhooksRepository;
use MyParcelNL\PrestaShop\Pdk\Webhook\Service\PsWebhookService;
use MyParcelNL\PrestaShop\Router\Contract\PsRouterServiceInterface;
use MyParcelNL\PrestaShop\Router\Service\PsRouterService;
use MyParcelNL\PrestaShop\Router\Service\Ps17RouterService;
use MyParcelNL\PrestaShop\Router\Service\Ps8RouterService;
use MyParcelNL\PrestaShop\Script\Service\PsScriptService;
use MyParcelNL\PrestaShop\Service\PsCarrierService;
use MyParcelNL\PrestaShop\Service\PsObjectModelService;
Expand All @@ -81,6 +82,7 @@
use function DI\factory;
use function DI\get;
use function DI\value;
use function MyParcelNL\PrestaShop\psVersionFactory;

return [
'defaultCutoffTime' => value('17:00'),
Expand Down Expand Up @@ -153,9 +155,10 @@
/**
* Miscellaneous
*/
ClientAdapterInterface::class => factory(function () {
return _PS_VERSION_ >= 8 ? Pdk::get(Guzzle7ClientAdapter::class) : Pdk::get(Guzzle5ClientAdapter::class);
}),
ClientAdapterInterface::class => psVersionFactory([
['class' => Guzzle7ClientAdapter::class, 'version' => 8],
['class' => Guzzle5ClientAdapter::class],
]),

LoggerInterface::class => get(PsLogger::class),
MigrationServiceInterface::class => get(PsMigrationService::class),
Expand All @@ -177,5 +180,8 @@
PsConfigurationServiceInterface::class => get(Ps17PsConfigurationService::class),
PsObjectModelServiceInterface::class => get(PsObjectModelService::class),
PsOrderServiceInterface::class => get(PsOrderService::class),
PsRouterServiceInterface::class => get(PsRouterService::class),
PsRouterServiceInterface::class => psVersionFactory([
['class' => Ps8RouterService::class, 'version' => 8],
['class' => Ps17RouterService::class],
]),
];
5 changes: 4 additions & 1 deletion src/Hooks/HasPdkCheckoutDeliveryOptionsHooks.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ public function hookDisplayBeforeCarrier(array $params)
try {
return $this->renderDeliveryOptions();
} catch (Throwable $e) {
Logger::error('Failed to render delivery options', ['exception' => $e, 'params' => $params]);
Logger::error('Failed to render delivery options', [
'exception' => $e->getMessage(),
'params' => $params,
]);

return false;
}
Expand Down
40 changes: 9 additions & 31 deletions src/Pdk/Base/PsPdkBootstrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace MyParcelNL\PrestaShop\Pdk\Base;

use Context;
use DI\Definition\Helper\FactoryDefinitionHelper;
use FileLogger;
use Module;
Expand All @@ -19,9 +18,6 @@
use Psr\Log\LogLevel;
use ReflectionClass;
use ReflectionMethod;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Routing\Loader\YamlFileLoader;
use Symfony\Component\Routing\Router;
use function DI\factory;
use function DI\value;

Expand Down Expand Up @@ -173,14 +169,18 @@ protected function getConfig(string $version, string $name, string $path): array
private function resolvePrestaShopServices(): array
{
return [
'ps.version' => value(_PS_VERSION_),
'ps.container' => factory(function () {
return Pdk::get('moduleInstance')
->getContainer();
}),

'getPsService' => factory(function () {
return static function (string $serviceName) {
/** @var MyParcelNL $module */
$module = Pdk::get('moduleInstance');
/** @var \Psr\Container\ContainerInterface $container */
$container = Pdk::get('ps.container');

return $module
->getContainer()
->get($serviceName);
return $container->get($serviceName);
};
}),

Expand All @@ -196,28 +196,6 @@ private function resolvePrestaShopServices(): array
return Pdk::get('getPsService')('prestashop.core.admin.tab.repository');
}),

'ps.router' => factory(function () {
/** @var MyParcelNL $module */
$module = Pdk::get('moduleInstance');
$container = $module->getContainer();

if (_PS_VERSION_ <= 8) {
return $container->get('router');
}

$controller = Context::getContext()->controller;

if ('order' === $controller->php_self) {
$routesDirectory = _PS_ROOT_DIR_ . '/modules/myparcelnl/config';
$locator = new FileLocator([$routesDirectory]);
$loader = new YamlFileLoader($locator);

return new Router($loader, 'routes.yml');
}

return $container->get('prestashop.router');
}),

'ps.twig' => factory(function () {
return Pdk::get('getPsService')('twig');
}),
Expand Down
1 change: 0 additions & 1 deletion src/Pdk/Frontend/Service/PsFrontendRenderService.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ final class PsFrontendRenderService extends FrontendRenderService
* @param \MyParcelNL\Pdk\App\Cart\Model\PdkCart $cart
*
* @return string
* @throws \MyParcelNL\Pdk\Base\Exception\InvalidCastException
*/
public function renderDeliveryOptions(PdkCart $cart): string
{
Expand Down
28 changes: 28 additions & 0 deletions src/Router/Service/Ps17RouterService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace MyParcelNL\PrestaShop\Router\Service;

use Context;

final class Ps17RouterService extends PsRouterService
{
/**
* @param string $route
*
* @return string
*/
protected function generateRoute(string $route): string
{
/** @var \LinkCore $link */
$link = Context::getContext()->link;

if (! defined('_PS_ADMIN_DIR_')) {
// Do not generate admin links in the frontend. There are currently no frontend endpoints anyway.
return '';
}

return $link->getAdminLink('MyParcelNLAdminSettings', true, ['route' => $route]);
}
}
65 changes: 65 additions & 0 deletions src/Router/Service/Ps8RouterService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

declare(strict_types=1);

namespace MyParcelNL\PrestaShop\Router\Service;

use Context;
use MyParcelNL\Pdk\Facade\Pdk;
use MyParcelNL\Pdk\Storage\Contract\StorageInterface;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Routing\Loader\YamlFileLoader;
use Symfony\Component\Routing\Router;

final class Ps8RouterService extends PsRouterService
{
/**
* @var \Symfony\Component\Routing\Router
*/
private Router $router;

/**
* @param \MyParcelNL\Pdk\Storage\Contract\StorageInterface $storage
*
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/
public function __construct(StorageInterface $storage)
{
parent::__construct($storage);
$this->router = $this->getRouter();
}

/**
* @param string $route
*
* @return string
*/
protected function generateRoute(string $route): string
{
return $this->router->generate($route);
}

/**
* @return \Symfony\Component\Routing\Router
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/
private function getRouter(): Router
{
/** @var \Psr\Container\ContainerInterface $container */
$container = Pdk::get('ps.container');

$controller = Context::getContext()->controller;

if ('order' === $controller->php_self) {
$routesDirectory = _PS_ROOT_DIR_ . '/modules/myparcelnl/config';
$locator = new FileLocator([$routesDirectory]);
$loader = new YamlFileLoader($locator);

return new Router($loader, 'routes.yml');
}

return $container->get('prestashop.router');
}
}
27 changes: 9 additions & 18 deletions src/Router/Service/PsRouterService.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,17 @@
namespace MyParcelNL\PrestaShop\Router\Service;

use MyParcelNL\Pdk\Base\Repository\Repository;
use MyParcelNL\Pdk\Facade\Pdk;
use MyParcelNL\Pdk\Storage\MemoryCacheStorage;
use MyParcelNL\PrestaShop\Router\Contract\PsRouterServiceInterface;
use MyParcelNL\Sdk\src\Support\Str;

final class PsRouterService extends Repository implements PsRouterServiceInterface
abstract class PsRouterService extends Repository implements PsRouterServiceInterface
{
/**
* @var \Symfony\Component\Routing\Router
*/
private $router;

/**
* @param \MyParcelNL\Pdk\Storage\MemoryCacheStorage $storage
* @param string $route
*
* @return mixed
*/
public function __construct(MemoryCacheStorage $storage)
{
parent::__construct($storage);
$this->router = Pdk::get('ps.router');
}
abstract protected function generateRoute(string $route): string;

/**
* @param string $route
Expand All @@ -33,7 +24,7 @@ public function __construct(MemoryCacheStorage $storage)
*/
public function getBaseUrl(string $route): string
{
return Str::before($this->generateRoute($route), '?');
return Str::before($this->generateRouteCached($route), '?');
}

/**
Expand All @@ -45,7 +36,7 @@ public function getRouteToken(string $route): string
{
$query = [];

parse_str(parse_url($this->generateRoute($route), PHP_URL_QUERY) ?? '', $query);
parse_str(parse_url($this->generateRouteCached($route), PHP_URL_QUERY) ?? '', $query);

return $query['_token'] ?? '';
}
Expand All @@ -55,10 +46,10 @@ public function getRouteToken(string $route): string
*
* @return string
*/
private function generateRoute(string $route): string
private function generateRouteCached(string $route): string
{
return $this->retrieve("route_$route", function () use ($route) {
return $this->router->generate($route);
return $this->generateRoute($route);
});
}
}
34 changes: 34 additions & 0 deletions src/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@

namespace MyParcelNL\PrestaShop;

use DI\Definition\Helper\FactoryDefinitionHelper;
use MyParcelNL\Pdk\Base\Pdk;
use MyParcelNL\Pdk\Facade\Pdk as PdkFacade;
use MyParcelNL\PrestaShop\Pdk\Base\PsPdkBootstrapper;
use MyParcelNL\PrestaShop\Tests\Bootstrap\MockPsPdkBootstrapper;
use MyParcelNL\Sdk\src\Support\Arr;
use function DI\factory;

if (! function_exists('\MyParcelNL\PrestaShop\bootPdk')) {
/**
Expand Down Expand Up @@ -39,3 +43,33 @@ function bootPdk(
MockPsPdkBootstrapper::boot(...func_get_args());
}
}

/**
* @template-covariant T
* @param array{version: string, operator: string, class: class-string<T>}[] $entries
*
* @return \DI\Definition\Helper\FactoryDefinitionHelper
*/
function psVersionFactory(array $entries): FactoryDefinitionHelper
{
return factory(function () use ($entries) {
$psVersion = PdkFacade::get('ps.version');
$fallback = Arr::first($entries, static function ($entry) {
return ! isset($entry['version']);
});

foreach ($entries as $item) {
if (! isset($item['version'])) {
continue;
}

$operator = $item['operator'] ?? '>=';

if (version_compare($psVersion, (string) $item['version'], $operator)) {
return PdkFacade::get($item['class']);
}
}

return PdkFacade::get($fallback['class']);
});
}
44 changes: 44 additions & 0 deletions tests/Unit/FunctionsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php
/** @noinspection StaticClosureCanBeUsedInspection */

declare(strict_types=1);

use MyParcelNL\Pdk\Facade\Pdk;
use MyParcelNL\PrestaShop\Pdk\Account\Repository\PsPdkAccountRepository;
use MyParcelNL\PrestaShop\Pdk\Cart\Repository\PsPdkCartRepository;
use MyParcelNL\PrestaShop\Pdk\Order\Repository\PsPdkOrderNoteRepository;
use MyParcelNL\PrestaShop\Pdk\Settings\Repository\PsPdkSettingsRepository;
use MyParcelNL\PrestaShop\Tests\Uses\UsesMockPsPdkInstance;
use function DI\value;
use function MyParcelNL\Pdk\Tests\mockPdkProperties;
use function MyParcelNL\Pdk\Tests\usesShared;
use function MyParcelNL\PrestaShop\psVersionFactory;

usesShared(new UsesMockPsPdkInstance([
// Must have an initial value to use mockPdkProperties
'someProperty' => value(null),
]));

it('gets class based on prestashop version number', function (string $version, string $expectedClass) {
mockPdkProperties([
'ps.version' => value($version),

'someProperty' => psVersionFactory([
['class' => PsPdkAccountRepository::class, 'version' => 8],
['class' => PsPdkCartRepository::class, 'version' => '1.7', 'operator' => '>=',],
['class' => PsPdkSettingsRepository::class, 'version' => '1.6', 'operator' => '<'],
['class' => PsPdkOrderNoteRepository::class],
]),
]);

$result = Pdk::get('someProperty');

expect($result)->toBeInstanceOf($expectedClass);
})->with([
'version 9.999.999' => ['9.999.999', PsPdkAccountRepository::class],
'version 8.2.0' => ['8.2.0', PsPdkAccountRepository::class],
'version 1.7.0' => ['1.7.0', PsPdkCartRepository::class],
'version 1.6.0' => ['1.6.0', PsPdkOrderNoteRepository::class],
'version 1.5.999' => ['1.5.999', PsPdkSettingsRepository::class],
'version 1.0.0' => ['1.0.0', PsPdkSettingsRepository::class],
]);

0 comments on commit 11c6a46

Please sign in to comment.