diff --git a/config.xml b/config.xml index 9f019c75..2540e089 100644 --- a/config.xml +++ b/config.xml @@ -2,7 +2,7 @@ psgdpr - + diff --git a/psgdpr.php b/psgdpr.php index 9d82a284..8d4f3f57 100755 --- a/psgdpr.php +++ b/psgdpr.php @@ -50,6 +50,16 @@ class Psgdpr extends Module 'accountCustomerForm' => 'psgdpr_customer_form', ]; + /** + * Hook a module registers on to declare itself to the GDPR consent settings. + */ + private const CONSENT_REGISTRATION_HOOK = 'registerGDPRConsent'; + + /** + * Placeholder consent message a module gets until the merchant writes its own. + */ + private const DEFAULT_CONSENT_MESSAGE = 'Enim quis fugiat consequat elit minim nisi eu occaecat occaecat deserunt aliquip nisi ex deserunt.'; + /** * @var array */ @@ -59,6 +69,7 @@ class Psgdpr extends Module 'actionAdminControllerSetMedia', 'additionalCustomerFormFields', 'actionCustomerAccountAdd', + 'actionModuleRegisterHookAfter', ]; private $presetMessageAccountCreation = [ @@ -87,7 +98,7 @@ public function __construct() { $this->name = 'psgdpr'; $this->tab = 'administration'; - $this->version = '2.0.3'; + $this->version = '2.0.4'; $this->author = 'PrestaShop'; $this->need_instance = 0; @@ -153,6 +164,7 @@ public function install(): bool $this->registerHook($this->hooksUsedByModule); $this->executeQuerySql(self::SQL_QUERY_TYPE_UNINSTALL); $this->executeQuerySql(self::SQL_QUERY_TYPE_INSTALL); + $this->getRegisteredModules(); } catch (PrestaShopException $e) { /** @var LegacyLogger $legacyLogger */ $legacyLogger = $this->get('prestashop.adapter.legacy.logger'); @@ -502,6 +514,31 @@ private function loadRegisteredModules(): array }, $moduleList); } + /** + * Register the consent as soon as a module declares itself on our hook, so that its + * consent checkbox works without waiting for the configuration page to be opened. + * + * @param array $params + * + * @return void + */ + public function hookActionModuleRegisterHookAfter(array $params): void + { + if (!isset($params['hook_name'], $params['object']) + || strcasecmp($params['hook_name'], self::CONSENT_REGISTRATION_HOOK) !== 0 + ) { + return; + } + + $module = $params['object']; + + if (!$module instanceof Module || (int) $module->id === (int) $this->id) { + return; + } + + $this->addModuleConsent(['id_module' => (int) $module->id]); + } + /** * Get a module list of module trying to register to GDPR * @@ -509,7 +546,7 @@ private function loadRegisteredModules(): array */ private function getRegisteredModules() { - $modulesRegistered = Hook::getHookModuleExecList('registerGDPRConsent'); + $modulesRegistered = Hook::getHookModuleExecList(self::CONSENT_REGISTRATION_HOOK); if (empty($modulesRegistered)) { return; @@ -531,34 +568,43 @@ private function getRegisteredModules() */ private function addModuleConsent(array $module): void { - /** @var LangRepository $langRepository */ - $langRepository = $this->get('prestashop.core.admin.lang.repository'); + $moduleId = (int) $module['id_module']; + $db = Db::getInstance(); + + // Deliberately written with the legacy layer. A consent row has to be created while a module + // is being installed, and while the shop installer runs, and in both cases the Doctrine + // repositories are out of reach: the container either does not exist yet, or it was compiled + // before this module was installed so LoadServicesFromModulesPass never registered its + // services. Module::get() returns null in the first case and throws ServiceNotFoundException + // in the second, and neither one is a PrestaShopException that install() could catch. + if ($db->getValue('SELECT id_gdpr_consent FROM `' . _DB_PREFIX_ . 'psgdpr_consent` WHERE id_module = ' . $moduleId)) { + return; + } - /** @var ConsentRepository $consentRepository */ - $consentRepository = $this->get('PrestaShop\Module\Psgdpr\Repository\ConsentRepository'); + $now = date('Y-m-d H:i:s'); - $languages = $langRepository->findAll(); - $shopId = $this->context->shop->id; - $consentExistForModule = $consentRepository->findModuleConsentExist($module['id_module']); + $inserted = $db->insert('psgdpr_consent', [ + 'id_module' => $moduleId, + 'active' => 1, + 'date_add' => pSQL($now), + 'date_upd' => pSQL($now), + ]); - if (true === $consentExistForModule) { + if (!$inserted) { return; } - $psgdprConsent = new PsgdprConsent(); - $psgdprConsent->setModuleId($module['id_module']); - $psgdprConsent->setActive(true); - - /** @var Lang $language */ - foreach ($languages as $language) { - $psgdprConsentLang = new PsgdprConsentLang(); - $psgdprConsentLang->setLang($language); - $psgdprConsentLang->setMessage('Enim quis fugiat consequat elit minim nisi eu occaecat occaecat deserunt aliquip nisi ex deserunt.'); - $psgdprConsentLang->setShopId($shopId); - $psgdprConsent->addConsentLang($psgdprConsentLang); - } + $consentId = (int) $db->Insert_ID(); + $shopId = (int) $this->context->shop->id; - $consentRepository->createOrUpdateConsent($psgdprConsent); + foreach (Language::getLanguages(false) as $language) { + $db->insert('psgdpr_consent_lang', [ + 'id_gdpr_consent' => $consentId, + 'id_lang' => (int) $language['id_lang'], + 'id_shop' => $shopId, + 'message' => pSQL(self::DEFAULT_CONSENT_MESSAGE), + ]); + } } /** diff --git a/upgrade/upgrade-2.0.4.php b/upgrade/upgrade-2.0.4.php new file mode 100644 index 00000000..72949228 --- /dev/null +++ b/upgrade/upgrade-2.0.4.php @@ -0,0 +1,35 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0) + */ +if (!defined('_PS_VERSION_')) { + exit; +} + +/** + * @param Psgdpr $module + * + * @return bool + */ +function upgrade_module_2_0_4($module) +{ + // Consent rows used to be created only while rendering the configuration page. + // Listening to hook registrations creates them as soon as a module declares itself. + return $module->registerHook('actionModuleRegisterHookAfter'); +}