Current File : /var/www/prestashop/modules/ps_mbo/ps_mbo.php |
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* 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 and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
if (!defined('_PS_VERSION_') || version_compare(_PS_VERSION_, '8.0.2', '<')) {
return;
}
$autoloadPath = __DIR__ . '/vendor/autoload.php';
if (file_exists($autoloadPath)) {
require_once $autoloadPath;
}
use PrestaShop\Module\Mbo\Accounts\Provider\AccountsDataProvider;
use PrestaShop\Module\Mbo\Addons\Subscriber\ModuleManagementEventSubscriber;
use PrestaShop\Module\Mbo\Api\Security\AdminAuthenticationProvider;
use PrestaShop\Module\Mbo\Helpers\Config;
use PrestaShop\PrestaShop\Adapter\SymfonyContainer;
use PrestaShopBundle\Event\ModuleManagementEvent;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Dotenv\Dotenv;
use PrestaShop\Module\Mbo\Helpers\ErrorHelper;
class ps_mbo extends Module
{
use PrestaShop\Module\Mbo\Traits\HaveTabs;
use PrestaShop\Module\Mbo\Traits\UseHooks;
use PrestaShop\Module\Mbo\Traits\HaveShopOnExternalService;
/**
* @var string
*/
public const VERSION = '4.12.0';
public const CONTROLLERS_WITH_CONNECTION_TOOLBAR = [
'AdminModulesManage',
'AdminModulesSf',
];
public const CONTROLLERS_WITH_CDC_SCRIPT = [
'AdminModulesNotifications',
'AdminModulesUpdates',
'AdminModulesManage',
];
public $configurationList = [
'PS_MBO_SHOP_ADMIN_UUID' => '', // 'ADMIN' because there will be only one for all shops in a multishop context
'PS_MBO_SHOP_ADMIN_MAIL' => '',
'PS_MBO_LAST_PS_VERSION_API_CONFIG' => '',
];
/**
* @var ContainerInterface
*/
protected $container;
/**
* @var \PrestaShop\Module\Mbo\DependencyInjection\ServiceContainer
*/
private $serviceContainer;
/**
* @var string
*/
public $imgPath;
/**
* @var string
*/
public $moduleCacheDir;
/**
* Constructor.
*/
public function __construct()
{
$this->name = 'ps_mbo';
$this->version = '4.12.0';
$this->author = 'PrestaShop';
$this->tab = 'administration';
$this->module_key = '6cad5414354fbef755c7df4ef1ab74eb';
$this->need_instance = 0;
$this->ps_versions_compliancy = [
'min' => '8.0.2',
'max' => '8.99.99',
];
parent::__construct();
$this->imgPath = $this->_path . 'views/img/';
$this->moduleCacheDir = sprintf('%s/var/modules/%s/', rtrim(_PS_ROOT_DIR_, '/'), $this->name);
$this->displayName = $this->trans('PrestaShop Marketplace in your Back Office', [], 'Modules.Mbo.Global');
$this->description = $this
->trans('Browse the Addons marketplace directly from your back office to better meet your needs.',
[],
'Modules.Mbo.Global'
);
if (self::checkModuleStatus()) {
$this->bootHooks();
}
$this->loadEnv();
}
/**
* Install Module.
*
* @return bool
*/
public function install(): bool
{
try {
$this->getService('mbo.ps_accounts.installer')->install();
} catch (Exception $e) {
ErrorHelper::reportError($e);
}
$this->installTables();
if (parent::install() && $this->registerHook($this->getHooksNames())) {
// Do come extra operations on modules' registration like modifying orders
$this->installHooks();
$this->getAdminAuthenticationProvider()->clearCache();
$this->getAdminAuthenticationProvider()->createApiUser();
$this->postponeTabsTranslations();
return true;
}
// If installation fails, we remove the tables previously created
$this->uninstallTables();
return false;
}
/**
* @inerhitDoc
*/
public function uninstall()
{
if (!parent::uninstall()) {
return false;
}
$this->getAdminAuthenticationProvider()->deletePossibleApiUser();
$this->getAdminAuthenticationProvider()->clearCache();
$lockFiles = ['registerShop', 'updateShop', 'createApiUser'];
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();
$this->uninstallTables();
/** @var \Symfony\Component\EventDispatcher\EventDispatcherInterface $eventDispatcher */
$eventDispatcher = $this->get('event_dispatcher');
if (!$eventDispatcher->hasListeners(ModuleManagementEvent::UNINSTALL)) {
return true;
}
// Execute them first
foreach ($eventDispatcher->getListeners(ModuleManagementEvent::UNINSTALL) as $listener) {
if ($listener[0] instanceof ModuleManagementEventSubscriber) {
$legacyModule = $this->get('prestashop.core.admin.module.repository')->getModule('ps_mbo');
$listener[0]->{(string)$listener[1]}(new ModuleManagementEvent($legacyModule));
}
}
//And then remove them
foreach ($eventDispatcher->getListeners(ModuleManagementEvent::UNINSTALL) as $listener) {
if ($listener[0] instanceof ModuleManagementEventSubscriber) {
$eventDispatcher->removeSubscriber($listener[0]);
break;
}
}
return true;
}
/**
* Enable Module.
*
* @param bool $force_all
*
* @return bool
*/
public function enable($force_all = false): bool
{
if (self::checkModuleStatus()) {
return true;
}
// Store previous context
$previousContextType = Shop::getContext();
$previousContextShopId = Shop::getContextShopID();
$allShops = Shop::getShops(true, null, true);
foreach ($allShops as $shop) {
if (!$this->enableByShop($shop)) {
return false;
}
}
// Restore previous context
Shop::setContext($previousContextType, $previousContextShopId);
// Install tab before registering shop, we need the tab to be active to create the good token
$this->updateTabs();
$this->postponeTabsTranslations();
// Register online services
$this->registerShop();
return true;
}
/**
* Disable Module.
*
* @param bool $force_all
*
* @return bool
*/
public function disable($force_all = false): bool
{
// Store previous context
$previousContextType = Shop::getContext();
$previousContextShopId = Shop::getContextShopID();
$allShops = Shop::getShops(true, null, true);
foreach ($allShops as $shop) {
if (!$this->disableByShop($shop)) {
return false;
}
}
// Restore previous context
Shop::setContext($previousContextType, $previousContextShopId);
// Unregister from online services
$this->unregisterShop();
return $this->handleTabAction('uninstall');
}
/**
* 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();
}
return $this->container->get($serviceName);
}
/**
* @param string $serviceName
*
* @return object|null
*/
public function getService($serviceName)
{
if ($this->serviceContainer === null) {
$this->serviceContainer = new \PrestaShop\Module\Mbo\DependencyInjection\ServiceContainer(
$this->name . str_replace('.', '', $this->version),
$this->getLocalPath()
);
}
return $this->serviceContainer->getService($serviceName);
}
/**
* @inerhitDoc
*/
public function isUsingNewTranslationSystem(): bool
{
return true;
}
/**
* Used to correctly check if the module is enabled or not whe registering services
*
* @return bool
*/
public static function checkModuleStatus(): bool
{
// First if the module have active=0 in the DB, the module is inactive
$result = Db::getInstance()->getRow('SELECT `active`
FROM `' . _DB_PREFIX_ . 'module`
WHERE `name` = "ps_mbo"');
if ($result && false === (bool) $result['active']) {
return false;
}
// If active = 1
//in the module table, the module must be associated to at least one shop to be considered as active
$result = Db::getInstance()->getRow('SELECT m.`id_module` as `active`, ms.`id_module` as `shop_active`
FROM `' . _DB_PREFIX_ . 'module` m
LEFT JOIN `' . _DB_PREFIX_ . 'module_shop` ms ON m.`id_module` = ms.`id_module`
WHERE `name` = "ps_mbo"');
if ($result) {
return $result['active'] && $result['shop_active'];
} else {
return false;
}
}
/**
* Get an existing or build an instance of AdminAuthenticationProvider
*
* @return \PrestaShop\Module\Mbo\Api\Security\AdminAuthenticationProvider
*
* @throws \Exception
*/
public function getAdminAuthenticationProvider(): AdminAuthenticationProvider
{
if (null === $this->container) {
$this->container = SymfonyContainer::getInstance();
}
return null !== $this->container && $this->container->has('mbo.security.admin_authentication.provider') ?
$this->get('mbo.security.admin_authentication.provider') :
new AdminAuthenticationProvider(
$this->get('doctrine.dbal.default_connection'),
$this->context,
$this->get('prestashop.core.crypto.hashing'),
$this->get('doctrine.cache.provider'),
$this->container->getParameter('database_prefix')
);
}
public function installTables(?string $table = null): bool
{
$sqlQueries = [];
if (null === $table || 'mbo_api_config' === $table) {
$sqlQueries[] = ' CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'mbo_api_config` (
`id_mbo_api_config` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`config_key` varchar(255) NULL,
`config_value` varchar(255) NULL,
`ps_version` varchar(255) NULL,
`mbo_version` varchar(255) NULL,
`applied` TINYINT(1) NOT NULL DEFAULT \'0\',
`date_add` datetime NOT NULL,
PRIMARY KEY (`id_mbo_api_config`)
) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=UTF8;';
}
foreach ($sqlQueries as $query) {
if (!Db::getInstance()->execute($query)) {
return false;
}
}
return true;
}
public function getAccountsDataProvider(): ?AccountsDataProvider
{
try {
return $this->getService('mbo.accounts.data_provider');
} catch (\Exception $e) {
ErrorHelper::reportError($e);
return null;
}
}
public function postponeTabsTranslations(): void
{
/**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 enableByShop(int $shopId)
{
// Force context to all shops
Shop::setContext(Shop::CONTEXT_SHOP, $shopId);
return parent::enable(true);
}
private function disableByShop(int $shopId)
{
// Force context to all shops
Shop::setContext(Shop::CONTEXT_SHOP, $shopId);
return parent::disable(true);
}
private function uninstallTables(): bool
{
$sqlQueries[] = 'DROP TABLE IF EXISTS `' . _DB_PREFIX_ . 'mbo_api_config`';
foreach ($sqlQueries as $query) {
if (!Db::getInstance()->execute($query)) {
return false;
}
}
return true;
}
/**
* @return void
*/
private function loadEnv(): void
{
$dotenv = new Dotenv(true);
$dotenv->loadEnv(__DIR__ . '/.env');
}
private function isPsAccountEnabled(): bool
{
$accountsInstaller = $this->get('mbo.ps_accounts.installer');
return null !== $accountsInstaller && $accountsInstaller->isModuleEnabled();
}
}