name = 'inpostizi'; $this->version = '2.2.3'; $this->author = 'InPost S.A.'; $this->tab = 'payments_gateways'; $this->ps_versions_compliancy = [ 'min' => '1.7.1.0', 'max' => '8.2.99', ]; parent::__construct(); $this->displayName = $this->l('InPost Pay'); } /** * @return false */ public function isUsingNewTranslationSystem() { return false; } /** * @return bool */ public function install() { if (70103 > PHP_VERSION_ID) { $this->_errors[] = $this->l('This module requires PHP 7.1.3 or later.'); return false; } try { (new DatabaseInstaller())->install($this); } catch (Exception $e) { $this->_errors[] = $this->l('Could not update the database schema.'); $this->getLogger()->critical('Installer error: {exception}.', [ 'exception' => $e, ]); return false; } $this->setUpRoutingLoaderResolver(); return parent::install() && $this->registerHook(HookExecutor::getHooksToInstall(_PS_VERSION_)); } /** * @return bool */ public function uninstall() { $this->setUpRoutingLoaderResolver(); return parent::uninstall(); } /** * @return array */ public function runUpgradeModule() { try { $result = parent::runUpgradeModule(); if (!$result['available_upgrade']) { return $result; } if ($result['success']) { $this->getLogger()->info('Upgraded module to version {version}.', [ 'version' => $result['upgraded_to'], ]); } else { $this->getLogger()->error('Could not upgrade module.', [ 'details' => $result, ]); } return $result; } catch (Throwable $e) { $this->getLogger()->critical('Upgrade error: {exception}.', [ 'exception' => $e, ]); throw $e; } } /** * @param int[] $shops shop IDs * * @return bool */ public function addCheckboxCurrencyRestrictionsForModule(array $shops = []) { if ([] === $shops) { $shops = Shop::getShops(true, null, true); } $data = []; foreach ($shops as $shopId) { foreach (Currency::cases() as $currency) { if (0 >= $currencyId = (int) \Currency::getIdByIsoCode($currency->value, $shopId)) { continue; } $data[] = [ 'id_module' => (int) $this->id, 'id_shop' => (int) $shopId, 'id_currency' => $currencyId, ]; } } return Db::getInstance()->insert('module_currency', $data); } public function getContent() { if ($this->isContainerCacheStale() && $this->isContainerConfigLoaded()) { $this->clearCacheAndRedirectBackToConfigPage(); } try { /** @var UrlGeneratorInterface $router */ $router = $this->get('router'); Tools::redirectAdmin($router->generate('admin_inpost_izi_config_general')); } catch (ServiceNotFoundException $e) { $this->handleConfigPageRequest(); } catch (RouteNotFoundException $e) { if ($this->isContainerConfigLoaded()) { throw $e; } $this->addFlash($this->l('To access the configuration page, the module must be active.')); Tools::redirectAdmin($router->generate('admin_module_manage')); } } /** * Handles hook calls. * * @param string $methodName * * @return mixed hook result */ public function __call($methodName, array $arguments) { $hookName = 0 === strpos($methodName, 'hook') ? lcfirst(Tools::substr($methodName, 4)) : $methodName; try { $parameters = $this->normalizeHookParameters(isset($arguments[0]) ? $arguments[0] : []); return $this ->get(HookExecutorInterface::class) ->execute($hookName, $parameters); } catch (ModuleErrorInterface $e) { throw $e; } catch (HookNotImplementedException $e) { $this->getLogger()->warning('Hook "{hookName}" is not implemented.', [ 'hookName' => $e->getHookName(), ]); return null; } catch (Throwable $e) { if ($this->isContainerCacheRelated($e)) { $this->getLogger()->error('Error executing hook "{hookName}": container cache is stale.', [ 'hookName' => $hookName, ]); return null; } $this->getLogger()->critical('Error executing hook "{hookName}": {exception}', [ 'hookName' => $hookName, 'exception' => $e, ]); if (_PS_MODE_DEV_ && $this->isDebugEnabled()) { throw $e; } return null; } } /** * @template T * * @param string|class-string $serviceName * * @phpstan-return ($serviceName is class-string ? T : object) * * @return T|object */ public function get($serviceName) { return $this->doGetContainer()->get($serviceName); } /** * @param string|null $hookName * * @return string */ public function renderWidget($hookName, array $configuration) { $configuration = $this->normalizeHookParameters($configuration); return $this->getWidget()->renderWidget($hookName, $configuration); } /** * @param string|null $hookName * * @return array */ public function getWidgetVariables($hookName, array $configuration) { $configuration = $this->normalizeHookParameters($configuration); return $this->getWidget()->getWidgetVariables($hookName, $configuration); } /** * @return Request * * @internal */ public function getCurrentRequest() { return $this->getRequestStack()->getCurrentRequest() ?: Request::createFromGlobals(); } /** * @return RequestStack * * @internal */ public function getRequestStack() { if (isset($this->requestStack)) { return $this->requestStack; } try { /** @var RequestStack $requestStack */ $requestStack = $this->get('request_stack'); if (null !== $requestStack->getCurrentRequest()) { return $this->requestStack = $requestStack; } } catch (ServiceNotFoundException $e) { } $this->requestStack = new RequestStack(); $this->requestStack->push(Request::createFromGlobals()); return $this->requestStack; } /** * @return LoggerInterface * * @internal */ public function getLogger() { try { return $this->get(self::$loggerServiceId); } catch (ContainerNotFoundException $e) { return $this->getLegacyContainer()->get(self::$loggerServiceId); } catch (Exception $e) { return new Psr\Log\NullLogger(); } } /** * @return ContainerInterface */ private function doGetContainer() { if (Tools::version_compare(_PS_VERSION_, '1.7.6')) { return $this->getLegacyContainer(); } if (Tools::version_compare(_PS_VERSION_, '1.7.7')) { return $this->getPS176Container(); } if (null !== $container = SymfonyContainer::getInstance()) { return $container; } try { return $this->getContainer(); } catch (PrestaShopContainerNotFoundException $e) { return $this->getFrontOfficeLegacyContainer(); } } /** * @return ContainerInterface */ private function getLegacyContainer() { if (!isset($this->legacyContainer)) { $this->legacyContainer = $this->createContainer(); } return $this->legacyContainer; } /** * @return ContainerInterface */ private function createContainer() { $cacheDir = sprintf('%s/inpost/izi/', rtrim(_PS_CACHE_DIR_, '/')); if (Tools::version_compare(_PS_VERSION_, '1.7.4')) { $className = sprintf('InPost\\Izi\\Container_%s', str_replace('.', '_', $this->version)); $resources = $this->getSf28ConfigResources(); } else { $type = $this->context->controller instanceof AdminControllerCore ? 'admin' : 'front'; $className = sprintf('InPost\\Izi\\%sContainer_%s', ucfirst($type), str_replace('.', '_', $this->version)); $resources = [sprintf('%s/config/%s/services.yml', rtrim($this->getLocalPath(), '/'), $type)]; } return (new ContainerFactory($cacheDir))->create($className, $resources); } /** * @return iterable */ private function getSf28ConfigResources() { yield sprintf('%s/config/services/sf28.yml', rtrim($this->getLocalPath(), '/')); yield static function (ContainerBuilder $container) { $container->addResource(new FileResource(__FILE__)); $container->addCompilerPass(new RegisterListenersPass('inpost.izi.event_dispatcher'), PassConfig::TYPE_BEFORE_REMOVING); $container->addCompilerPass(new ProvideServiceLocatorFactoriesPass('inpost.izi.service_locator')); $container->addCompilerPass(new TaggedIteratorsCollectorPass()); AnalyzeServiceReferencesPass::decorateRemovingPasses($container, 'inpost.izi.service_locator'); }; } /** * Accesses the public "routing.loader" service to provide a @see \Symfony\Component\Config\Loader\LoaderResolverInterface * to the routing configuration loader used by @see \PrestaShop\PrestaShop\Adapter\Module\Tab\ModuleTabRegister */ private function setUpRoutingLoaderResolver() { if (Tools::version_compare(_PS_VERSION_, '1.7.7')) { return; } try { $this->get('routing.loader'); } catch (Exception $e) { // ignore silently } } private function handleConfigPageRequest() { $request = $this->getCurrentRequest(); $request->query->remove('controllerUri'); $kernel = $this->getAdminKernel(); $response = $kernel->handle($request); $this->context->cookie->write(); $response->send(); if ($kernel instanceof TerminableInterface) { $kernel->terminate($request, $response); } exit; } /** * @return KernelInterface */ private function getAdminKernel() { if (isset($this->adminKernel)) { return $this->adminKernel; } global $kernel; if (!$kernel instanceof KernelInterface) { throw new RuntimeException('PS application kernel instance was not found.'); } $this->adminKernel = new AdminKernel($kernel, _PS_VERSION_); $this->adminKernel->boot(); $psContainer = $kernel->getContainer(); $this->adminKernel->getContainer()->set('prestashop.security.admin.provider', $psContainer->get('prestashop.security.admin.provider')); // In some very early 1.7 versions, the session may not have yet been started by PS application. $psContainer->get('session')->start(); return $this->adminKernel; } /** * @return bool */ private function isDebugEnabled() { try { return $this->get(AdvancedConfigurationInterface::class)->isDebugEnabled(); } catch (Exception $e) { return false; } } /** * {@see \Module::get()} does not check if {@see \Controller::$container} is set on PS 1.7.6. * * @return ContainerInterface */ private function getPS176Container() { if (isset($this->context->container)) { return $this->context->container; } if (null !== $container = SymfonyContainer::getInstance()) { return $container; } if ($this->context->controller instanceof Controller && null !== $container = $this->context->controller->getContainer()) { return $container; } return $this->getFrontOfficeLegacyContainer(); } /** * Access container before {@see \FrontController::$container} is set in {@see \Controller::init()}. * * @return ContainerInterface */ private function getFrontOfficeLegacyContainer() { if (!$this->context->controller instanceof FrontController || !class_exists(PrestaShopContainerBuilder::class)) { throw ContainerNotFoundException::create(); } try { return PrestaShopContainerBuilder::getContainer('front', _PS_MODE_DEV_); } catch (Exception $e) { throw ContainerNotFoundException::create($e); } } /** * @return array */ private function normalizeHookParameters(array $parameters) { if (!isset($parameters['request'])) { $parameters['request'] = $this->getCurrentRequest(); } if (!isset($parameters['cart'])) { $parameters['cart'] = $this->context->cart; } return $parameters; } /** * @return WidgetInterface */ private function getWidget() { if (isset($this->widget)) { return $this->widget; } return $this->widget = $this->get('inpost.izi.widget'); } /** * @return bool */ private function isContainerCacheRelated(Throwable $e) { if (!$e instanceof HookNotFoundException && !$e instanceof ServiceNotFoundException && !$e instanceof TypeError) { return false; } return $this->isContainerCacheStale(); } /** * @return bool */ private function isContainerCacheStale() { try { $container = $this->doGetContainer(); } catch (ContainerNotFoundException $e) { return false; // fingers crossed } if (!$container->hasParameter('inpost.izi.container_version')) { return true; } return $this->version !== $container->getParameter('inpost.izi.container_version'); } /** * @return bool whether PS automatically loads the module's container configuration */ private function isContainerConfigLoaded() { if ($this->active) { return true; } if (Tools::version_compare(_PS_VERSION_, '8.0.0')) { return true; } return $this->hasShopAssociations(); } private function clearCacheAndRedirectBackToConfigPage() { if (Tools::getValue('cache_cleared')) { $this->addFlash($this->l('An attempt to clear the cache may have failed. Please try to clear the cache manually.')); return; } $this->getLogger()->warning('Container cache is stale, attempting to clear.'); Tools::clearSf2Cache(); Tools::redirectAdmin($this->context->link->getAdminLink('AdminModules', true, null, [ 'configure' => $this->name, 'cache_cleared' => true, ])); } /** * @param string $message * @param string $type */ private function addFlash($message, $type = 'error') { try { /** @var Session $session */ $session = $this->get('session'); $session->getFlashBag()->add($type, $message); } catch (ServiceNotFoundException $e) { // ignore silently } } }