Files
masimmo.pl/modules/ps_mbo/ps_mbo.php
2024-11-20 09:09:44 +01:00

1246 lines
45 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* 2007-2020 PrestaShop and Contributors
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2020 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
if (!defined('_PS_VERSION_')) {
exit;
}
$autoloadPath = __DIR__ . '/vendor/autoload.php';
if (file_exists($autoloadPath)) {
require_once $autoloadPath;
}
use Doctrine\Common\Cache\CacheProvider;
use PrestaShop\Module\Mbo\Distribution\AuthenticationProvider;
use PrestaShop\Module\Mbo\Distribution\Client;
use PrestaShop\Module\Mbo\Helpers\Config;
use PrestaShop\Module\Mbo\Service\View\ContextBuilder;
use PrestaShop\Module\Mbo\Tab\TabCollectionProvider;
use PrestaShop\PrestaShop\Adapter\SymfonyContainer;
use PrestaShop\PsAccountsInstaller\Installer\Installer;
use Ramsey\Uuid\Uuid;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Dotenv\Dotenv;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
class ps_mbo extends Module
{
const TABS_WITH_RECOMMENDED_MODULES_BUTTON = [
'AdminOrders', // Orders> Orders
'AdminInvoices', // Orders > Invoices
'AdminSlip', // Orders > Credit Slips
'AdminDeliverySlip', // Orders > Delivery Slips
'AdminProducts', // Catalog > Products
'AdminFeatures', // Catalog > Attributes & Features > Features
'AdminManufacturers', // Catalog > Brands & Suppliers > Brands
'AdminCartRules', // Catalog > Discounts > Cart Rules
'AdminCustomers', // Customers > Customers
'AdminCustomerThreads', // Customer Service> Customers Service
'AdminStats', // Stats> Stats
'AdminCmsContent', // Pages
'AdminImages', // Image
'AdminShipping', // Shipping > Preferences
'AdminStatuses', // Shop Parameters > Order Settings > Statuses
'AdminGroups', // Shop Parameters > Customer Settings > Groups
'AdminContacts', // Shop Parameters > Contact > Contact
'AdminMeta', // Shop Parameters > Traffic & SEO > SEO & URLs
'AdminSearchConf', // Shop Parameters > Search > Search
'AdminAdminPreferences', // Advanced Parameters > Administration
'AdminEmails', // Advanced Parameters > E-mail
];
const TABS_WITH_RECOMMENDED_MODULES_AFTER_CONTENT = [
'AdminMarketing',
'AdminPayment',
'AdminCarriers',
];
const CORE_TABS_RENAMED = [
'AdminModulesCatalog' => [
'old_name' => 'Modules catalog',
'new_name' => 'Marketplace',
],
'AdminParentModulesCatalog' => [
'old_name' => 'Modules catalog',
'new_name' => 'Marketplace',
],
'AdminAddonsCatalog' => [
'old_name' => 'Module selection',
'new_name' => 'Modules in the spotlight',
'trans_domain' => 'Modules.Mbo.Modulesselection',
],
];
const ADMIN_CONTROLLERS = [
'AdminPsMboModule' => [
'name' => 'Marketplace',
'visible' => true,
'class_name' => 'AdminPsMboModule',
'parent_class_name' => 'AdminParentModulesCatalog',
'core_reference' => 'AdminModulesCatalog',
'position' => 1,
],
'AdminPsMboAddons' => [
'name' => 'Module selection',
'wording' => 'Modules in the spotlight',
'wording_domain' => 'Modules.Mbo.Modulesselection',
'visible' => true,
'class_name' => 'AdminPsMboAddons',
'parent_class_name' => 'AdminParentModulesCatalog',
'core_reference' => 'AdminAddonsCatalog',
'position' => 2,
],
'AdminPsMboRecommended' => [
'name' => 'Module recommended',
'wording' => 'Recommended Modules and Services',
'wording_domain' => 'Modules.Mbo.Recommendedmodulesandservices',
'visible' => true,
'class_name' => 'AdminPsMboRecommended',
],
'AdminPsMboTheme' => [
'name' => 'Theme catalog',
'visible' => true,
'class_name' => 'AdminPsMboTheme',
'parent_class_name' => 'AdminParentThemes',
'core_reference' => 'AdminThemesCatalog',
],
'AdminPsMboUninstalledModules' => [
'name' => 'Uninstalled modules',
'wording' => 'Uninstalled modules',
'wording_domain' => 'Modules.Mbo.Modulesselection',
'visible' => true,
'position' => 2,
'class_name' => 'AdminPsMboUninstalledModules',
'parent_class_name' => 'AdminModulesSf',
],
];
const CONTROLLERS_WITH_CDC_SCRIPT = [
'AdminModulesNotifications',
'AdminModulesUpdates',
'AdminModulesManage',
'AdminPsMboModule',
'AdminModulesCatalog',
];
const HOOKS = [
'actionAdminControllerSetMedia',
'actionDispatcherBefore',
'actionEmployeeSave',
'actionGeneralPageSave',
'actionObjectEmployeeUpdateAfter',
'actionObjectShopUrlUpdateAfter',
'displayDashboardTop',
];
public $configurationList = [
'PS_MBO_SHOP_ADMIN_UUID' => '', // 'ADMIN' because there will be only one for all shops in a multishop context
];
/**
* @var ContainerInterface
*/
protected $container;
/**
* @var string
*/
public $moduleCacheDir;
/**
* @var CacheProvider
*/
public $cacheProvider;
/**
* Constructor.
*/
public function __construct()
{
$this->name = 'ps_mbo';
$this->version = '3.1.3';
$this->author = 'PrestaShop';
$this->tab = 'administration';
$this->module_key = '6cad5414354fbef755c7df4ef1ab74eb';
$this->need_instance = 0;
$this->ps_versions_compliancy = [
'min' => '1.7.7.0',
'max' => '1.7.8.99',
];
parent::__construct();
$this->moduleCacheDir = sprintf('%s/var/modules/%s/', rtrim(_PS_ROOT_DIR_, '/'), $this->name);
$this->displayName = $this->l('PrestaShop Marketplace in your Back Office');
$this->description = $this->l('Browse the Addons marketplace directly from your back office to better meet your needs.');
$this->loadEnv();
}
/**
* Install Module.
*
* @return bool
*/
public function install()
{
return parent::install()
&& $this->registerHook(static::HOOKS);
}
/**
* {@inheritDoc}
*/
public function uninstall()
{
if (!parent::uninstall()) {
return false;
}
/**
* @var AuthenticationProvider $authenticationProvider
*/
$authenticationProvider = $this->get('mbo.cdc.distribution_authentication_provider');
$authenticationProvider->clearCache();
$lockFiles = ['registerShop', 'updateShop'];
foreach ($lockFiles as $lockFile) {
if (file_exists($this->moduleCacheDir . $lockFile . '.lock')) {
unlink($this->moduleCacheDir . $lockFile . '.lock');
}
}
foreach (array_keys($this->configurationList) as $name) {
Configuration::deleteByName($name);
}
// This will reset cached configuration values (uuid, mail, ...) to avoid reusing them
Config::resetConfigValues();
return true;
}
/**
* Enable Module.
*
* @return bool
*/
public function enable($force_all = false)
{
$result = parent::enable($force_all)
&& $this->organizeCoreTabs()
&& $this->installTabs();
$this->registerShop();
$this->postponeTabsTranslations();
return (bool) $result;
}
/**
* This method is here if we need to rename some Core tabs.
*
* @return bool
*/
public function organizeCoreTabs($restore = false)
{
$return = true;
$coreTabsRenamed = static::CORE_TABS_RENAMED;
if (true === (bool) version_compare(_PS_VERSION_, '1.7.8', '<')) {
unset($coreTabsRenamed['AdminAddonsCatalog']);
}
// Rename tabs
foreach ($coreTabsRenamed as $className => $names) {
$tabId = Tab::getIdFromClassName($className);
if ($tabId !== false) {
$tabNameByLangId = [];
if ($restore) {
$name = $names['old_name'];
$transDomain = 'Admin.Navigation.Menu';
} else {
$name = $names['new_name'];
$transDomain = isset($names['trans_domain']) ? $names['trans_domain'] : 'Modules.Mbo.Global';
}
foreach (Language::getIDs(false) as $langId) {
$langId = (int) $langId;
$language = new Language($langId);
$tabNameByLangId[$langId] = (string) $this->trans(
$name,
[],
$transDomain,
!empty($language->locale) ? $language->locale : $language->language_code // can't use getLocale because not existing in 1.7.5
);
}
$tab = new Tab($tabId);
$tab->name = $tabNameByLangId;
if (true === (bool) version_compare(_PS_VERSION_, '1.7.8', '>=')) {
$tab->wording = $name;
$tab->wording_domain = $transDomain;
}
$return &= $tab->save();
}
}
// Change tabs positions
$return &= $this->changeTabPosition('AdminParentModulesCatalog', $restore ? 1 : 0);
$return &= $this->changeTabPosition('AdminModulesSf', $restore ? 0 : 1);
return (bool) $return;
}
public function changeTabPosition($className, $newPosition)
{
$return = true;
$tabId = Tab::getIdFromClassName($className);
if ($tabId !== false) {
$tab = new Tab($tabId);
$tab->position = $newPosition;
$return &= $tab->save();
}
return $return;
}
/**
* Install all Tabs.
*
* @return bool
*/
public function installTabs()
{
foreach (static::ADMIN_CONTROLLERS as $adminTab) {
if (false === $this->installTab($adminTab)) {
return false;
}
}
return true;
}
/**
* Install Tab.
* Used in upgrade script.
*
* @param array $tabData
*
* @return bool
*/
public function installTab(array $tabData)
{
$tabNameByLangId = array_fill_keys(
Language::getIDs(false),
$tabData['name']
);
if (isset($tabData['core_reference'])) {
$tabCoreId = Tab::getIdFromClassName($tabData['core_reference']);
if ($tabCoreId !== false) {
$tabCore = new Tab($tabCoreId);
$tabNameByLangId = $tabCore->name;
$tabCore->active = false;
$tabCore->save();
}
}
$idParent = empty($tabData['parent_class_name']) ? -1 : Tab::getIdFromClassName($tabData['parent_class_name']);
$tab = Tab::getInstanceFromClassName($tabData['class_name']);
if (!Validate::isLoadedObject($tab)) {
$tab = new Tab();
$tab->class_name = $tabData['class_name'];
}
$tab->module = $this->name;
$tab->position = Tab::getNewLastPosition($idParent);
$tab->id_parent = $idParent;
$tab->name = $tabNameByLangId;
if (
true === (bool) version_compare(_PS_VERSION_, '1.7.8', '>=') &&
!empty($tabData['wording']) &&
!empty($tabData['wording_domain'])
) {
$tab->wording = $tabData['wording'];
$tab->wording_domain = $tabData['wording_domain'];
}
if (!Validate::isLoadedObject($tab) && false === (bool) $tab->add()) {
return false;
}
if (Validate::isLoadedObject($tab)) {
$position = 0;
if (isset($tabData['position'])) {
$position = $tabData['position'];
}
$tab->cleanPositions($tab->id_parent);
$tab->save();
$this->putTabInPosition($tab, $position);
}
return true;
}
/**
* Disable Module.
*
* @return bool
*/
public function disable($force_all = false)
{
$result = parent::disable($force_all)
&& $this->organizeCoreTabs(true)
&& $this->uninstallTabs();
// Unregister from online services
$this->unregisterShop();
return $result;
}
/**
* Uninstall all Tabs.
*
* @return bool
*/
public function uninstallTabs()
{
foreach (static::ADMIN_CONTROLLERS as $adminTab) {
if (false === $this->uninstallTab($adminTab)) {
return false;
}
}
return true;
}
/**
* Uninstall Tab.
* Can be used in upgrade script.
*
* @param array $tabData
*
* @return bool
*/
public function uninstallTab(array $tabData)
{
$tabId = Tab::getIdFromClassName($tabData['class_name']);
$tab = new Tab($tabId);
if (false === Validate::isLoadedObject($tab)) {
return false;
}
if (false === (bool) $tab->delete()) {
return false;
}
if (isset($tabData['core_reference'])) {
$tabCoreId = Tab::getIdFromClassName($tabData['core_reference']);
$tabCore = new Tab($tabCoreId);
if (Validate::isLoadedObject($tabCore)) {
$tabCore->active = true;
}
if (false === (bool) $tabCore->save()) {
return false;
}
}
return true;
}
/**
* Hook actionAdminControllerSetMedia.
*/
public function hookActionAdminControllerSetMedia()
{
// has to be loaded in header to prevent flash of content
$this->context->controller->addJs($this->getPathUri() . 'views/js/recommended-modules.js?v=' . $this->version);
$this->context->controller->addCSS($this->getPathUri() . 'views/css/catalog.css?v=' . $this->version, 'all', null, false);
if (Tools::getValue('controller') === 'AdminPsMboModule') {
$this->context->controller->addJs($this->getPathUri() . 'views/js/upload_module_with_cdc.js?v=' . $this->version);
}
if (
$this->shouldAttachRecommendedModulesButton()
|| $this->shouldAttachRecommendedModulesAfterContent()
) {
if (
true === (bool) version_compare(_PS_VERSION_, '1.7.8', '>=')
) {
$this->context->controller->addCSS($this->getPathUri() . 'views/css/recommended-modules-since-1.7.8.css');
}
if (
true === (bool) version_compare(_PS_VERSION_, '1.7.8', '<')
) {
$this->context->controller->addCSS($this->getPathUri() . 'views/css/recommended-modules-lower-1.7.8.css');
}
if (Tools::getValue('controller') !== 'AdminProducts') {
$this->context->controller->addJs(
rtrim(__PS_BASE_URI__, '/')
. str_ireplace(
_PS_CORE_DIR_,
'',
_PS_BO_ALL_THEMES_DIR_
)
. 'default/js/bundle/module/module_card.js?v='
. _PS_VERSION_
);
}
}
$this->loadMediaForAdminControllerSetMedia();
}
/**
* Add JS and CSS file
*
* @return void
*/
protected function loadMediaForAdminControllerSetMedia()
{
if (in_array(Tools::getValue('controller'), self::CONTROLLERS_WITH_CDC_SCRIPT)) {
$this->context->controller->addJs('/js/jquery/plugins/growl/jquery.growl.js?v=' . $this->version);
$this->context->controller->addCSS($this->getPathUri() . 'views/css/module-catalog.css');
}
$accountsInstaller = $this->get('mbo.ps_accounts.installer');
$isPsAccountsEnabled = ($accountsInstaller instanceof Installer) && $accountsInstaller->isModuleEnabled();
if (
('AdminPsMboModule' === Tools::getValue('controller')) // Module catalog / Marketplace
|| $isPsAccountsEnabled // For Module manager
) {
$this->context->controller->addCSS($this->getPathUri() . 'views/css/connection-toolbar.css');
}
$this->loadCdcMedia();
}
private function loadCdcMedia()
{
$controllerName = Tools::getValue('controller');
if (!is_string($controllerName)) {
return;
}
if (
!in_array($controllerName, self::CONTROLLERS_WITH_CDC_SCRIPT)
) {
return;
}
$cdcJsFile = getenv('MBO_CDC_URL');
if (false === $cdcJsFile || !is_string($cdcJsFile) || empty($cdcJsFile)) {
$this->context->controller->addJs($this->getPathUri() . 'views/js/cdc-error.js');
return;
}
$this->context->controller->addJs($cdcJsFile);
}
/**
* Hook displayDashboardTop.
* Includes content just below the toolbar.
*
* @return string
*/
public function hookDisplayDashboardTop()
{
/** @var UrlGeneratorInterface $router */
$router = $this->get('router');
try {
$recommendedModulesUrl = $router->generate(
'admin_mbo_recommended_modules',
[
'tabClassName' => Tools::getValue('controller'),
]
);
} catch (Exception $exception) {
// Avoid fatal errors on ServiceNotFoundException
return '';
}
$shouldDisplayModuleManagerMessage = $this->shouldDisplayModuleManagerMessage();
$shopContext = null;
/** @var ContextBuilder $contextBuilder */
$contextBuilder = $this->get('mbo.cdc.context_builder');
if (null != $contextBuilder && $shouldDisplayModuleManagerMessage) {
$shopContext = $contextBuilder->getViewContext();
}
$this->smarty->assign([
'shouldAttachRecommendedModulesAfterContent' => $this->shouldAttachRecommendedModulesAfterContent(),
'shouldAttachRecommendedModulesButton' => $this->shouldAttachRecommendedModulesButton(),
'shouldDisplayModuleManagerMessage' => $this->shouldDisplayModuleManagerMessage(),
'shouldUseLegacyTheme' => $this->isAdminLegacyContext(),
'recommendedModulesTitleTranslated' => $this->getRecommendedModulesButtonTitle(),
'recommendedModulesDescriptionTranslated' => $this->getRecommendedModulesDescription(),
'recommendedModulesCloseTranslated' => $this->trans('Close', [], 'Admin.Actions'),
'recommendedModulesUrl' => $recommendedModulesUrl,
'shopContext' => json_encode($shopContext),
]);
return $this->fetch('module:ps_mbo/views/templates/hook/recommended-modules.tpl');
}
/**
* Hook actionDispatcherBefore.
*/
public function hookActionDispatcherBefore()
{
$controllerName = Tools::getValue('controller');
$this->translateTabsIfNeeded();
// Registration failed on install, retry it
if (in_array($controllerName, static::CONTROLLERS_WITH_CDC_SCRIPT)) {
$this->ensureShopIsRegistered();
$this->ensureShopIsUpdated();
}
}
/**
* Hook actionGeneralPageSave.
*/
public function hookActionGeneralPageSave(array $params)
{
if (isset($params['route']) && $params['route'] === 'admin_preferences_save') {
// User may have updated the SSL configuration
$this->updateShop();
}
}
/**
* Hook actionEmployeeSave.
*/
public function hookActionEmployeeSave(array $params)
{
$controllerName = Tools::getValue('controller');
if (
(isset($params['route']) && $params['route'] === 'admin_employees_edit')
|| ('AdminEmployees' === $controllerName)
) {
// User may have updated the employee language
$this->postponeTabsTranslations();
}
}
/**
* Hook actionObjectEmployeeUpdateAfter.
*/
public function hookActionObjectEmployeeUpdateAfter(array $params)
{
$controllerName = Tools::getValue('controller');
if (
(isset($params['route']) && $params['route'] === 'admin_employees_edit')
|| ('AdminEmployees' === $controllerName)
) {
// User may have updated the employee language
$this->postponeTabsTranslations();
}
}
/**
* Hook actionGeneralPageSave.
*/
public function hookActionObjectShopUrlUpdateAfter(array $params)
{
if ($params['object']->main) {
// Clear cache to be sure to load correctly the shop with good data whe building the service later
\Cache::clean('Shop::setUrl_' . (int) $params['object']->id_shop);
if (Config::isUsingSecureProtocol()) {
$url = 'https://' . preg_replace('#https?://#', '', $params['object']->domain_ssl);
} else {
$url = 'http://' . preg_replace('#https?://#', '', $params['object']->domain);
}
$this->updateShop([
'shop_url' => $url,
]);
}
return true;
}
private function shouldDisplayModuleManagerMessage(): bool
{
if (!in_array(
Tools::getValue('controller'),
[
'AdminModulesManage',
'AdminModulesNotifications',
'AdminModulesUpdates',
]
)) {
return false;
}
try {
$requestStack = $this->get('request_stack');
if (!$requestStack || !($request = $requestStack->getCurrentRequest())) {
throw new Exception('Unable to get request');
}
} catch (Exception $e) {
// ErrorHelper::reportError($e);
return false;
}
// because admin_employee_index and admin_employee_edit are in the same controller AdminEmployees
return in_array($request->get('_route'), [
'admin_module_manage',
'admin_module_notification',
'admin_module_updates',
]);
}
/**
* Indicates if the recommended modules should be attached after content in this page
*
* @return bool
*/
private function shouldAttachRecommendedModulesAfterContent()
{
// AdminLogin should not call TabCollectionProvider
if (Validate::isLoadedObject($this->context->employee)) {
/** @var TabCollectionProvider $tabCollectionProvider */
$tabCollectionProvider = $this->get('mbo.tab.collection.provider');
if ($tabCollectionProvider->isTabCollectionCached()) {
return $tabCollectionProvider->getTabCollection()->getTab(Tools::getValue('controller'))->shouldDisplayAfterContent()
|| 'AdminCarriers' === Tools::getValue('controller');
}
}
return in_array(Tools::getValue('controller'), static::TABS_WITH_RECOMMENDED_MODULES_AFTER_CONTENT, true);
}
/**
* Customize title button recommended modules
*
* @return string
*/
private function getRecommendedModulesButtonTitle()
{
switch (Tools::getValue('controller')) {
case 'AdminSlip':
case 'AdminInvoices':
$title = $this->trans('Simplify accounting', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminDeliverySlip':
$title = $this->trans('Make shipping easier', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminOrders':
$title = $this->trans('Boost sales', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminFeatures':
$title = $this->trans('Optimize product creation', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminSpecificPriceRule':
case 'AdminCartRules':
$title = $this->trans('Create a discount strategy', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminManufacturers':
$title = $this->trans('Promote brands', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminProducts':
$title = $this->trans('Optimize product catalog', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminStats':
$title = $this->trans('Improve data strategy', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminContacts':
case 'AdminCustomerThreads':
case 'AdminCustomers':
$title = $this->trans('Improve customer experience', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminCmsContent':
$title = $this->trans('Customize pages', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminImages':
$title = $this->trans('Improve visuals', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminCarriers':
$title = $this->trans('Make your deliveries easier', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminShipping':
$title = $this->trans('Improve shipping', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminPayment':
$title = $this->trans('Improve the checkout experience', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminStatuses':
$title = $this->trans('Optimize order management', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminGroups':
$title = $this->trans('Improve customer targeting', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminContacts':
$title = $this->trans('Improve customer experience', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminSearchConf':
case 'AdminMeta':
$title = $this->trans('Improve SEO', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminAdminPreferences':
$title = $this->trans('Simplify store management', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminEmails':
$title = $this->trans('Automate emails', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
default:
$title = $this->trans('Recommended modules', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
}
return $title;
}
/**
* Customize description of modal button recommended modules
*
* @return string
*/
private function getRecommendedModulesDescription()
{
switch (Tools::getValue('controller')) {
case 'AdminEmails':
$description = $this->trans('Send automatic emails and notifications to your customers with ease.<br>
Here\'s a selection of modules,<strong> compatible with your store</strong>, to help you achieve your goals.', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminAdminPreferences':
$description = $this->trans('Simplify the daily management of your store and save time.<br>
Here\'s a selection of modules,<strong> compatible with your store</strong>, to help you achieve your goals.', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminSearchConf':
case 'AdminMeta':
$description = $this->trans('Rank higher in search results so more people can find you.<br>
Here\'s a selection of modules,<strong> compatible with your store</strong>, to help you achieve your goals.', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminContacts':
case 'AdminCustomers':
case 'AdminCustomerThreads':
$description = $this->trans('Create memorable experiences and turn visitors into customers.<br>
Here\'s a selection of modules,<strong> compatible with your store</strong>, to help you achieve your goals.', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminGroups':
$description = $this->trans('Manage groups and better target your customers in your marketing.<br>
Here\'s a selection of modules,<strong> compatible with your store</strong>, to help you achieve your goals.', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminStatuses':
$description = $this->trans('Save time: delete, edit, and manage your orders in bulk.<br>
Here\'s a selection of modules,<strong> compatible with your store</strong>, to help you achieve your goals.', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminPayment':
$description = $this->trans('Offer the payment methods your customers expect and improve your checkout process so you never miss a sale.<br>
Here\'s a selection of modules,<strong> compatible with your store</strong>, to help you achieve your goals.', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminShipping':
$description = $this->trans('Optimize your logistics and meet your customers\' delivery expectations.<br>
Here\'s a selection of modules,<strong> compatible with your store</strong>, to help you achieve your goals.', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminCarriers':
$description = $this->trans('Make your deliveries easier by choosing the right carriers.<br>
Here\'s a selection of modules,<strong> compatible with your store</strong>, to help you achieve your goals.', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminImages':
$description = $this->trans('Use quality and eye-catching visuals while preserving your stores performance.<br>
Here\'s a selection of modules,<strong> compatible with your store</strong>, to help you achieve your goals.', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminCmsContent':
$description = $this->trans('Customize your store pages and highlight special offers.<br>
Here\'s a selection of modules,<strong> compatible with your store</strong>, to help you achieve your goals.', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminSpecificPriceRule':
case 'AdminCartRules':
$description = $this->trans('Drive more sales and increase customer retention with a well-planned discount strategy.<br>
Here\'s a selection of modules,<strong> compatible with your store</strong>, to help you achieve your goals.', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminManufacturers':
$description = $this->trans('Promote the brands you distribute and allow your visitors to browse the products of their favorite brands.<br>
Here\'s a selection of modules,<strong> compatible with your store</strong>, to help you achieve your goals.', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminFeatures':
$description = $this->trans('Save time on product creation and easily manage combinations.<br>
Here\'s a selection of modules,<strong> compatible with your store</strong>, to help you achieve your goals.', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminDeliverySlip':
$description = $this->trans('Save time in preparing and shipping your orders.<br>
Here\'s a selection of modules,<strong> compatible with your store</strong>, to help you achieve your goals.', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminSlip':
case 'AdminInvoices':
$description = $this->trans('Keep your records organized and stay on top of your accounting.<br>
Here\'s a selection of modules,<strong> compatible with your store</strong>, to help you achieve your goals.', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminOrders':
$description = $this->trans('Get new customers and keep them coming back.<br>
Here\'s a selection of modules,<strong> compatible with your store</strong>, to help you achieve your goals.', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminProducts':
$description = $this->trans('Make your products more visible and create product pages that convert.<br>
Here\'s a selection of modules, <strong>compatible with your store</strong>, to help you achieve your goals.', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
case 'AdminStats':
$description = $this->trans('Build a data-driven strategy and make more informed decisions.<br>
Here\'s a selection of modules,<strong> compatible with your store</strong>, to help you achieve your goals.', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
default:
$description = $this->trans('Here\'s a selection of modules,<strong> compatible with your store</strong>, to help you achieve your goals', [], 'Modules.Mbo.Recommendedmodulesandservices');
break;
}
return $description;
}
/**
* Indicates if the recommended modules button should be attached in this page
*
* @return bool
*/
private function shouldAttachRecommendedModulesButton()
{
return in_array(Tools::getValue('controller'), static::TABS_WITH_RECOMMENDED_MODULES_BUTTON, true);
}
/**
* Override of native function to always retrieve Symfony container instead of legacy admin container on legacy context.
*
* {@inheritdoc}
*/
public function get($serviceName)
{
if (null === $this->container) {
$this->container = SymfonyContainer::getInstance();
}
if (null === $this->container) {
throw new Exception('Cannot get a valid Sf Container');
}
return $this->container->get($serviceName);
}
public function isUsingNewTranslationSystem()
{
return false;
}
/**
* Update hooks in DB.
* Search current hooks registered in DB and compare them with the hooks declared in the module.
* If a hook is missing, it will be added. If a hook is not declared in the module, it will be removed.
*
* @return void
*/
public function updateHooks()
{
$hookData = (array) Db::getInstance()->executeS(
'
SELECT DISTINCT(phm.id_hook), name
FROM `' . _DB_PREFIX_ . 'hook_module` phm
JOIN `' . _DB_PREFIX_ . 'hook` ph ON ph.id_hook=phm.id_hook
WHERE `id_module` = ' . (int) $this->id
);
$oldHooks = [];
$newHooks = [];
// Iterate on DB hooks to get only the old ones
foreach ($hookData as $hook) {
if (!in_array(strtolower($hook['name']), array_map('strtolower', static::HOOKS))) {
$oldHooks[] = $hook;
}
}
// Iterate on module hooks to get only the new ones
foreach (static::HOOKS as $moduleHook) {
$isNew = true;
foreach ($hookData as $hookInDb) {
if (strtolower($moduleHook) === strtolower($hookInDb['name'])) {
$isNew = false;
break;
}
}
if ($isNew) {
$newHooks[] = $moduleHook;
}
}
foreach ($oldHooks as $oldHook) {
$this->unregisterHook($oldHook['id']);
}
// we iterate because registerHook accepts array only since 1.7.7.0
foreach ($newHooks as $newHook) {
$this->registerHook($newHook);
}
}
public function postponeTabsTranslations()
{
/**it'
* There is an issue for translating tabs during installation :
* Active modules translations files are loaded during the kernel boot. So the installing module translations are not known
* So, we postpone the tabs translations for the first time the module's code is executed.
*/
$lockFile = $this->moduleCacheDir . 'translate_tabs.lock';
if (!file_exists($lockFile)) {
if (!is_dir($this->moduleCacheDir)) {
mkdir($this->moduleCacheDir, 0777, true);
}
$f = fopen($lockFile, 'w+');
fclose($f);
}
}
private function translateTabsIfNeeded()
{
try {
if (Tools::getValue('controller') === 'AdminCommon') {
return; // Avoid early translation by notifications controller
}
$lockFile = $this->moduleCacheDir . 'translate_tabs.lock';
if (!file_exists($lockFile)) {
return;
}
$languages = Language::getLanguages(false);
// Because the wording and wording_domain are introduced since PS v1.7.8.0 and we cannot use them
if (true === (bool) version_compare(_PS_VERSION_, '1.7.8', '>=')) {
$this->translateTabs();
}
@unlink($lockFile);
} catch (\Exception $e) {
// Do nothing
}
}
private function translateTabs()
{
$moduleTabs = Tab::getCollectionFromModule($this->name);
$languages = Language::getLanguages(false);
/**
* @var Tab $tab
*/
foreach ($moduleTabs as $tab) {
$this->translateTab($tab, $languages);
}
foreach (static::CORE_TABS_RENAMED as $coreTabClass => $coreTabRenamed) {
if (array_key_exists('trans_domain', $coreTabRenamed)) {
$tab = Tab::getInstanceFromClassName($coreTabClass);
$this->translateTab($tab, $languages);
}
}
}
private function translateTab($tab, $languages)
{
if (!$tab instanceof Tab) {
throw new \Exception('First argument of translateTab mut be a Tab instance');
}
if (!empty($tab->wording) && !empty($tab->wording_domain)) {
$tabNameByLangId = [];
foreach ($languages as $language) {
$tabNameByLangId[$language['id_lang']] = $this->trans(
$tab->wording,
[],
$tab->wording_domain,
$language['locale']
);
}
$tab->name = $tabNameByLangId;
$tab->save();
}
}
/**
* @return void
*/
private function loadEnv()
{
(new Dotenv())->load(__DIR__ . '/.env');
}
public function registerShop()
{
$this->installConfiguration();
$this->callServiceWithLockFile('registerShop');
}
public function updateShop(array $params = [])
{
$this->callServiceWithLockFile('updateShop', $params);
}
/**
* Unregister a shop of online services delivered by API.
* When the module is disabled or uninstalled, remove it from online services
*
* @return void
*/
private function unregisterShop()
{
try {
$authenticationProvider = $this->get('mbo.cdc.distribution_authentication_provider');
$distributionApi = $this->get('mbo.cdc.client.distribution_api');
if (
$authenticationProvider instanceof AuthenticationProvider
&& $distributionApi instanceof Client
) {
$distributionApi->setBearer($authenticationProvider->getMboJWT());
$distributionApi->unregisterShop();
}
} catch (Exception $exception) {
// Do nothing here, the exception is caught to avoid displaying an error to the client
// Furthermore, the operation can't be tried again later as the module is now disabled or uninstalled
}
}
/**
* Install configuration for each shop
*
* @return bool
*/
private function installConfiguration()
{
$result = true;
$this->configurationList['PS_MBO_SHOP_ADMIN_UUID'] = Uuid::uuid4()->toString();
foreach (Shop::getShops(false, null, true) as $shopId) {
foreach ($this->configurationList as $name => $value) {
if (false === Configuration::hasKey($name, null, null, (int) $shopId)) {
$result = $result && (bool) Configuration::updateValue(
$name,
$value,
false,
null,
(int) $shopId
);
}
}
}
return $result;
}
private function callServiceWithLockFile(string $method, array $params = [])
{
$lockFile = $this->moduleCacheDir . $method . '.lock';
try {
// If the module is installed via command line or somehow the ADMIN_DIR is not defined,
// we ignore the shop registration, so it will be done at any action on the backoffice
if (php_sapi_name() === 'cli' || !defined('_PS_ADMIN_DIR_')) {
throw new Exception();
}
/** @var Client $distributionApi */
$distributionApi = $this->get('mbo.cdc.client.distribution_api');
if (!method_exists($distributionApi, $method)) {
return;
}
/**
* @var AuthenticationProvider $authenticationProvider
*/
$authenticationProvider = $this->get('mbo.cdc.distribution_authentication_provider');
$distributionApi->setBearer($authenticationProvider->getMboJWT());
$distributionApi->{$method}($params);
if (file_exists($lockFile)) {
unlink($lockFile);
}
} catch (Exception $exception) {
// Create the lock file
if (!file_exists($lockFile)) {
if (!is_dir($this->moduleCacheDir)) {
mkdir($this->moduleCacheDir, 0777, true);
}
$f = fopen($lockFile, 'w+');
fclose($f);
}
}
}
private function ensureShopIsRegistered()
{
if (!file_exists($this->moduleCacheDir . 'registerShop.lock')) {
return;
}
$this->registerShop();
}
private function ensureShopIsUpdated()
{
if (!file_exists($this->moduleCacheDir . 'updateShop.lock')) {
return;
}
$this->updateShop();
}
private function putTabInPosition(Tab $tab, int $position)
{
// Check tab position in DB
$dbTabPosition = Db::getInstance()->getValue(
'
SELECT `position`
FROM `' . _DB_PREFIX_ . 'tab`
WHERE `id_tab` = ' . (int) $tab->id
);
if ((int) $dbTabPosition === $position) {
// Nothing to do, tab is already in the right position
return;
}
Db::getInstance()->execute(
'
UPDATE `' . _DB_PREFIX_ . 'tab`
SET `position` = `position`+1
WHERE `id_parent` = ' . (int) $tab->id_parent . ' AND `position` >= ' . $position . ' AND `id_tab` <> ' . (int) $tab->id
);
Db::getInstance()->execute(
'
UPDATE `' . _DB_PREFIX_ . 'tab`
SET `position` = ' . $position . '
WHERE `id_tab` = ' . (int) $tab->id
);
}
}