621 lines
19 KiB
PHP
621 lines
19 KiB
PHP
<?php
|
|
/**
|
|
* Copyright seit 2024 Webshop System
|
|
*
|
|
* Zentrale Konfigurationsverwaltung (Key-Value)
|
|
* Vollständig PrestaShop-kompatibel mit erweiterten Funktionen
|
|
*
|
|
* @author Webshop System
|
|
* @license GPL v3
|
|
*/
|
|
|
|
class Configuration extends ObjectModel
|
|
{
|
|
public $id;
|
|
|
|
/** @var string Key */
|
|
public $name;
|
|
|
|
public $id_shop_group;
|
|
public $id_shop;
|
|
|
|
/** @var string|array<string> Value */
|
|
public $value;
|
|
|
|
/** @var string Object creation date */
|
|
public $date_add;
|
|
|
|
/** @var string Object last modification date */
|
|
public $date_upd;
|
|
|
|
/**
|
|
* @see ObjectModel::$definition
|
|
*/
|
|
public static $definition = [
|
|
'table' => 'configuration',
|
|
'primary' => 'id_configuration',
|
|
'multilang' => true,
|
|
'fields' => [
|
|
'name' => ['type' => self::TYPE_STRING, 'validate' => 'isConfigName', 'required' => true, 'size' => 254],
|
|
'id_shop_group' => ['type' => self::TYPE_NOTHING, 'validate' => 'isUnsignedId'],
|
|
'id_shop' => ['type' => self::TYPE_NOTHING, 'validate' => 'isUnsignedId'],
|
|
'value' => ['type' => self::TYPE_STRING, 'size' => 65535],
|
|
'date_add' => ['type' => self::TYPE_DATE, 'validate' => 'isDate'],
|
|
'date_upd' => ['type' => self::TYPE_DATE, 'validate' => 'isDate'],
|
|
],
|
|
];
|
|
|
|
/** @var array|null Configuration cache */
|
|
protected static $_cache = null;
|
|
|
|
/** @var array|null Configuration cache with optimised key order */
|
|
protected static $_new_cache_shop = null;
|
|
protected static $_new_cache_group = null;
|
|
protected static $_new_cache_global = null;
|
|
protected static $_initialized = false;
|
|
|
|
/** @var array Vars types */
|
|
protected static $types = [];
|
|
|
|
protected $webserviceParameters = [
|
|
'fields' => [
|
|
'value' => [],
|
|
],
|
|
];
|
|
|
|
/**
|
|
* Default configuration data
|
|
*/
|
|
protected static $data = [
|
|
'WS_COUNTRY_DEFAULT' => 1,
|
|
'WS_LANG_DEFAULT' => 1,
|
|
'WS_TIMEZONE' => 'Europe/Berlin',
|
|
'WS_LOCALE_LANGUAGE' => 'de',
|
|
'WS_LOCALE_COUNTRY' => 'DE',
|
|
'WS_COOKIE_LIFETIME_BO' => 24,
|
|
'WS_COOKIE_LIFETIME_FO' => 24,
|
|
'WS_COOKIE_SAMESITE' => 'Lax',
|
|
'WS_SSL_ENABLED' => false,
|
|
];
|
|
|
|
/**
|
|
* Get fields lang
|
|
*/
|
|
public function getFieldsLang()
|
|
{
|
|
if (!is_array($this->value)) {
|
|
return true;
|
|
}
|
|
|
|
return parent::getFieldsLang();
|
|
}
|
|
|
|
/**
|
|
* Return ID a configuration key.
|
|
*/
|
|
public static function getIdByName($key, $idShopGroup = null, $idShop = null)
|
|
{
|
|
if ($idShop === null) {
|
|
$idShop = Shop::getContextShopID(true);
|
|
}
|
|
if ($idShopGroup === null) {
|
|
$idShopGroup = Shop::getContextShopGroupID(true);
|
|
}
|
|
|
|
return self::getIdByNameFromGivenContext($key, $idShopGroup, $idShop);
|
|
}
|
|
|
|
/**
|
|
* Get ID by name from given context
|
|
*/
|
|
public static function getIdByNameFromGivenContext(string $key, ?int $idShopGroup, ?int $idShop): int
|
|
{
|
|
$sql = 'SELECT `' . bqSQL(self::$definition['primary']) . '`
|
|
FROM `' . _DB_PREFIX_ . bqSQL(self::$definition['table']) . '`
|
|
WHERE name = \'' . pSQL($key) . '\'
|
|
' . Configuration::sqlRestriction($idShopGroup, $idShop);
|
|
|
|
return (int) Db::getInstance()->getValue($sql);
|
|
}
|
|
|
|
/**
|
|
* Is the configuration loaded.
|
|
*/
|
|
public static function configurationIsLoaded()
|
|
{
|
|
return self::$_initialized;
|
|
}
|
|
|
|
/**
|
|
* Reset static cache
|
|
*/
|
|
public static function resetStaticCache()
|
|
{
|
|
self::$_cache = null;
|
|
self::$_new_cache_shop = null;
|
|
self::$_new_cache_group = null;
|
|
self::$_new_cache_global = null;
|
|
self::$_initialized = false;
|
|
}
|
|
|
|
/**
|
|
* Load all configuration data.
|
|
*/
|
|
public static function loadConfiguration()
|
|
{
|
|
$sql = 'SELECT c.`name`, cl.`id_lang`, IF(cl.`id_lang` IS NULL, c.`value`, cl.`value`) AS value, c.id_shop_group, c.id_shop
|
|
FROM `' . _DB_PREFIX_ . bqSQL(self::$definition['table']) . '` c
|
|
LEFT JOIN `' . _DB_PREFIX_ . bqSQL(self::$definition['table']) . '_lang` cl ON (c.`' . bqSQL(
|
|
self::$definition['primary']
|
|
) . '` = cl.`' . bqSQL(self::$definition['primary']) . '`)';
|
|
$db = Db::getInstance();
|
|
$results = $db->executeS($sql);
|
|
if ($results) {
|
|
foreach ($results as $row) {
|
|
$lang = ($row['id_lang']) ? $row['id_lang'] : 0;
|
|
self::$types[$row['name']] = (bool) $lang;
|
|
|
|
if (!isset(self::$_cache[self::$definition['table']][$lang])) {
|
|
self::$_cache[self::$definition['table']][$lang] = [
|
|
'global' => [],
|
|
'group' => [],
|
|
'shop' => [],
|
|
];
|
|
}
|
|
|
|
if ($row['value'] === null) {
|
|
$row['value'] = '';
|
|
}
|
|
|
|
if ($row['id_shop']) {
|
|
self::$_cache[self::$definition['table']][$lang]['shop'][$row['id_shop']][$row['name']] = $row['value'];
|
|
self::$_new_cache_shop[$row['name']][$lang][$row['id_shop']] = $row['value'];
|
|
} elseif ($row['id_shop_group']) {
|
|
self::$_cache[self::$definition['table']][$lang]['group'][$row['id_shop_group']][$row['name']] = $row['value'];
|
|
self::$_new_cache_group[$row['name']][$lang][$row['id_shop_group']] = $row['value'];
|
|
} else {
|
|
self::$_cache[self::$definition['table']][$lang]['global'][$row['name']] = $row['value'];
|
|
self::$_new_cache_global[$row['name']][$lang] = $row['value'];
|
|
}
|
|
}
|
|
self::$_initialized = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get a single configuration value (in one language only).
|
|
*/
|
|
public static function get($key, $idLang = null, $idShopGroup = null, $idShop = null, $default = false)
|
|
{
|
|
// Init the cache on demand
|
|
if (!self::$_initialized) {
|
|
Configuration::loadConfiguration();
|
|
}
|
|
|
|
$idLang = self::isLangKey($key) ? (int) $idLang : 0;
|
|
|
|
if (self::$_new_cache_shop === null) {
|
|
$idShop = 0;
|
|
} elseif ($idShop === null || !Shop::isFeatureActive()) {
|
|
$idShop = Shop::getContextShopID(true);
|
|
}
|
|
|
|
if (self::$_new_cache_group === null) {
|
|
$idShopGroup = 0;
|
|
} elseif ($idShopGroup === null || !Shop::isFeatureActive()) {
|
|
$idShopGroup = Shop::getContextShopGroupID(true);
|
|
}
|
|
|
|
if ($idShop && Configuration::hasKey($key, $idLang, null, $idShop)) {
|
|
return self::$_new_cache_shop[$key][$idLang][$idShop];
|
|
} elseif ($idShopGroup && Configuration::hasKey($key, $idLang, $idShopGroup)) {
|
|
return self::$_new_cache_group[$key][$idLang][$idShopGroup];
|
|
} elseif (Configuration::hasKey($key, $idLang)) {
|
|
return self::$_new_cache_global[$key][$idLang];
|
|
}
|
|
|
|
return $default;
|
|
}
|
|
|
|
/**
|
|
* Get global value
|
|
*/
|
|
public static function getGlobalValue($key, $idLang = null)
|
|
{
|
|
return self::get($key, $idLang, 0, 0);
|
|
}
|
|
|
|
/**
|
|
* Get config in multiple langs
|
|
*/
|
|
public static function getConfigInMultipleLangs($key, $idShopGroup = null, $idShop = null)
|
|
{
|
|
$languages = Language::getLanguages(false);
|
|
$res = [];
|
|
|
|
foreach ($languages as $lang) {
|
|
$res[$lang['id_lang']] = self::get($key, $lang['id_lang'], $idShopGroup, $idShop);
|
|
}
|
|
|
|
return $res;
|
|
}
|
|
|
|
/**
|
|
* Get multi shop values
|
|
*/
|
|
public static function getMultiShopValues($key, $idLang = null)
|
|
{
|
|
$shops = Shop::getShops(false, null, true);
|
|
$res = [];
|
|
|
|
foreach ($shops as $shop) {
|
|
$res[$shop['id_shop']] = self::get($key, $idLang, $shop['id_shop_group'], $shop['id_shop']);
|
|
}
|
|
|
|
return $res;
|
|
}
|
|
|
|
/**
|
|
* Get multiple
|
|
*/
|
|
public static function getMultiple($keys, $idLang = null, $idShopGroup = null, $idShop = null)
|
|
{
|
|
if (!is_array($keys)) {
|
|
return false;
|
|
}
|
|
|
|
$res = [];
|
|
foreach ($keys as $key) {
|
|
$res[$key] = self::get($key, $idLang, $idShopGroup, $idShop);
|
|
}
|
|
|
|
return $res;
|
|
}
|
|
|
|
/**
|
|
* Has key
|
|
*/
|
|
public static function hasKey($key, $idLang = null, $idShopGroup = null, $idShop = null)
|
|
{
|
|
if (!$idLang) {
|
|
$idLang = 0;
|
|
}
|
|
|
|
if ($idShop && isset(self::$_new_cache_shop[$key][$idLang][$idShop])) {
|
|
return true;
|
|
} elseif ($idShopGroup && isset(self::$_new_cache_group[$key][$idLang][$idShopGroup])) {
|
|
return true;
|
|
} elseif (isset(self::$_new_cache_global[$key][$idLang])) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Set configuration value
|
|
*/
|
|
public static function set($key, $values, $idShopGroup = null, $idShop = null)
|
|
{
|
|
if (!$key) {
|
|
return false;
|
|
}
|
|
|
|
if ($idShop === null) {
|
|
$idShop = Shop::getContextShopID(true);
|
|
}
|
|
if ($idShopGroup === null) {
|
|
$idShopGroup = Shop::getContextShopGroupID(true);
|
|
}
|
|
|
|
if (!is_array($values)) {
|
|
$values = [$values];
|
|
}
|
|
|
|
if (self::isLangKey($key)) {
|
|
$res = true;
|
|
foreach ($values as $idLang => $value) {
|
|
$res &= self::updateValue($key, $value, false, $idShopGroup, $idShop, $idLang);
|
|
}
|
|
} else {
|
|
$res = self::updateValue($key, $values[0], false, $idShopGroup, $idShop);
|
|
}
|
|
|
|
return $res;
|
|
}
|
|
|
|
/**
|
|
* Update global value
|
|
*/
|
|
public static function updateGlobalValue($key, $values, $html = false)
|
|
{
|
|
return self::updateValue($key, $values, $html, 0, 0);
|
|
}
|
|
|
|
/**
|
|
* Update value
|
|
*/
|
|
public static function updateValue($key, $values, $html = false, $idShopGroup = null, $idShop = null, $idLang = null)
|
|
{
|
|
if (!$key) {
|
|
return false;
|
|
}
|
|
|
|
if ($idShop === null) {
|
|
$idShop = Shop::getContextShopID(true);
|
|
}
|
|
if ($idShopGroup === null) {
|
|
$idShopGroup = Shop::getContextShopGroupID(true);
|
|
}
|
|
|
|
// Update cache
|
|
if (self::isLangKey($key)) {
|
|
if ($idLang === null) {
|
|
$idLang = Context::getContext()->language->id;
|
|
}
|
|
if (self::$_new_cache_global !== null) {
|
|
self::$_new_cache_global[$key][$idLang] = $values;
|
|
}
|
|
if (self::$_new_cache_group !== null && $idShopGroup) {
|
|
self::$_new_cache_group[$key][$idLang][$idShopGroup] = $values;
|
|
}
|
|
if (self::$_new_cache_shop !== null && $idShop) {
|
|
self::$_new_cache_shop[$key][$idLang][$idShop] = $values;
|
|
}
|
|
} else {
|
|
if (self::$_new_cache_global !== null) {
|
|
self::$_new_cache_global[$key][0] = $values;
|
|
}
|
|
if (self::$_new_cache_group !== null && $idShopGroup) {
|
|
self::$_new_cache_group[$key][0][$idShopGroup] = $values;
|
|
}
|
|
if (self::$_new_cache_shop !== null && $idShop) {
|
|
self::$_new_cache_shop[$key][0][$idShop] = $values;
|
|
}
|
|
}
|
|
|
|
// Update database
|
|
$sql = 'SELECT `' . bqSQL(self::$definition['primary']) . '`
|
|
FROM `' . _DB_PREFIX_ . bqSQL(self::$definition['table']) . '`
|
|
WHERE name = \'' . pSQL($key) . '\'
|
|
' . Configuration::sqlRestriction($idShopGroup, $idShop);
|
|
|
|
$configuration = Db::getInstance()->getRow($sql);
|
|
|
|
if ($configuration) {
|
|
$result = true;
|
|
if (self::isLangKey($key)) {
|
|
$sql = 'UPDATE `' . _DB_PREFIX_ . bqSQL(self::$definition['table']) . '_lang`
|
|
SET value = \'' . pSQL($values, $html) . '\'
|
|
WHERE `' . bqSQL(self::$definition['primary']) . '` = ' . (int) $configuration[self::$definition['primary']] . '
|
|
AND `id_lang` = ' . (int) $idLang;
|
|
$result &= Db::getInstance()->execute($sql);
|
|
} else {
|
|
$sql = 'UPDATE `' . _DB_PREFIX_ . bqSQL(self::$definition['table']) . '`
|
|
SET value = \'' . pSQL($values, $html) . '\', date_upd = NOW()
|
|
WHERE `' . bqSQL(self::$definition['primary']) . '` = ' . (int) $configuration[self::$definition['primary']];
|
|
$result &= Db::getInstance()->execute($sql);
|
|
}
|
|
} else {
|
|
$result = self::insertNewConfiguration($key, $values, $html, $idShopGroup, $idShop, $idLang);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Insert new configuration
|
|
*/
|
|
protected static function insertNewConfiguration($key, $values, $html, $idShopGroup, $idShop, $idLang)
|
|
{
|
|
$newConfig = new Configuration();
|
|
$newConfig->name = $key;
|
|
$newConfig->id_shop_group = $idShopGroup;
|
|
$newConfig->id_shop = $idShop;
|
|
|
|
if (self::isLangKey($key)) {
|
|
$newConfig->value = $values;
|
|
$newConfig->id_lang = $idLang;
|
|
} else {
|
|
$newConfig->value = $values;
|
|
}
|
|
|
|
return $newConfig->add();
|
|
}
|
|
|
|
/**
|
|
* Delete by name
|
|
*/
|
|
public static function deleteByName($key)
|
|
{
|
|
$sql = 'DELETE FROM `' . _DB_PREFIX_ . bqSQL(self::$definition['table']) . '`
|
|
WHERE name = \'' . pSQL($key) . '\'';
|
|
$result = Db::getInstance()->execute($sql);
|
|
|
|
if (self::isLangKey($key)) {
|
|
$sql = 'DELETE FROM `' . _DB_PREFIX_ . bqSQL(self::$definition['table']) . '_lang`
|
|
WHERE `' . bqSQL(self::$definition['primary']) . '` NOT IN
|
|
(SELECT `' . bqSQL(self::$definition['primary']) . '` FROM `' . _DB_PREFIX_ . bqSQL(self::$definition['table']) . '`)';
|
|
$result &= Db::getInstance()->execute($sql);
|
|
}
|
|
|
|
// Update cache
|
|
if (self::$_new_cache_global !== null && isset(self::$_new_cache_global[$key])) {
|
|
unset(self::$_new_cache_global[$key]);
|
|
}
|
|
if (self::$_new_cache_group !== null && isset(self::$_new_cache_group[$key])) {
|
|
unset(self::$_new_cache_group[$key]);
|
|
}
|
|
if (self::$_new_cache_shop !== null && isset(self::$_new_cache_shop[$key])) {
|
|
unset(self::$_new_cache_shop[$key]);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Delete from context
|
|
*/
|
|
public static function deleteFromContext($key, ?int $idShopGroup = null, ?int $idShop = null)
|
|
{
|
|
if ($idShop === null) {
|
|
$idShop = Shop::getContextShopID(true);
|
|
}
|
|
if ($idShopGroup === null) {
|
|
$idShopGroup = Shop::getContextShopGroupID(true);
|
|
}
|
|
|
|
self::deleteFromGivenContext($key, $idShopGroup, $idShop);
|
|
}
|
|
|
|
/**
|
|
* Delete from given context
|
|
*/
|
|
public static function deleteFromGivenContext(string $key, ?int $idShopGroup, ?int $idShop): void
|
|
{
|
|
$sql = 'DELETE FROM `' . _DB_PREFIX_ . bqSQL(self::$definition['table']) . '`
|
|
WHERE name = \'' . pSQL($key) . '\'
|
|
' . Configuration::sqlRestriction($idShopGroup, $idShop);
|
|
Db::getInstance()->execute($sql);
|
|
}
|
|
|
|
/**
|
|
* Delete by ID
|
|
*/
|
|
public static function deleteById(int $configurationId): void
|
|
{
|
|
$sql = 'DELETE FROM `' . _DB_PREFIX_ . bqSQL(self::$definition['table']) . '`
|
|
WHERE `' . bqSQL(self::$definition['primary']) . '` = ' . (int) $configurationId;
|
|
Db::getInstance()->execute($sql);
|
|
|
|
$sql = 'DELETE FROM `' . _DB_PREFIX_ . bqSQL(self::$definition['table']) . '_lang`
|
|
WHERE `' . bqSQL(self::$definition['primary']) . '` = ' . (int) $configurationId;
|
|
Db::getInstance()->execute($sql);
|
|
}
|
|
|
|
/**
|
|
* Has context
|
|
*/
|
|
public static function hasContext($key, $idLang, $context)
|
|
{
|
|
if (is_array($context)) {
|
|
$idShop = (int) $context['shop_id'];
|
|
$idShopGroup = (int) $context['shop_group_id'];
|
|
} else {
|
|
$idShop = Shop::getContextShopID(true);
|
|
$idShopGroup = Shop::getContextShopGroupID(true);
|
|
}
|
|
|
|
if ($idShop && Configuration::hasKey($key, $idLang, null, $idShop)) {
|
|
return true;
|
|
} elseif ($idShopGroup && Configuration::hasKey($key, $idLang, $idShopGroup)) {
|
|
return true;
|
|
} elseif (Configuration::hasKey($key, $idLang)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Is overriden by current context
|
|
*/
|
|
public static function isOverridenByCurrentContext($key)
|
|
{
|
|
$idContextLang = Context::getContext()->language->id;
|
|
$currentShopId = Shop::getContextShopID(true);
|
|
$currentShopGroupId = Shop::getContextShopGroupID(true);
|
|
|
|
if ($currentShopId && Configuration::hasKey($key, $idContextLang, null, $currentShopId)) {
|
|
return true;
|
|
} elseif ($currentShopGroupId && Configuration::hasKey($key, $idContextLang, $currentShopGroupId)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Is lang key
|
|
*/
|
|
public static function isLangKey($key)
|
|
{
|
|
return isset(self::$types[$key]) && self::$types[$key];
|
|
}
|
|
|
|
/**
|
|
* Is catalog mode
|
|
*/
|
|
public static function isCatalogMode()
|
|
{
|
|
return (bool) self::get('PS_CATALOG_MODE');
|
|
}
|
|
|
|
/**
|
|
* Show prices
|
|
*/
|
|
public static function showPrices()
|
|
{
|
|
return !self::isCatalogMode();
|
|
}
|
|
|
|
/**
|
|
* SQL restriction
|
|
*/
|
|
protected static function sqlRestriction($idShopGroup, $idShop)
|
|
{
|
|
if ($idShop) {
|
|
return ' AND id_shop = ' . (int) $idShop;
|
|
} elseif ($idShopGroup) {
|
|
return ' AND id_shop_group = ' . (int) $idShopGroup . ' AND (id_shop IS NULL OR id_shop = 0)';
|
|
} else {
|
|
return ' AND (id_shop_group IS NULL OR id_shop_group = 0) AND (id_shop IS NULL OR id_shop = 0)';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get webservice object list
|
|
*/
|
|
public function getWebserviceObjectList($sqlJoin, $sqlFilter, $sqlSort, $sqlLimit)
|
|
{
|
|
$sql = 'SELECT DISTINCT main.`' . bqSQL(self::$definition['primary']) . '` as `' . bqSQL(self::$definition['primary']) . '` ' . $sqlJoin . ' WHERE 1 ' . $sqlFilter;
|
|
if ($sqlSort) {
|
|
$sql .= $sqlSort;
|
|
}
|
|
if ($sqlLimit) {
|
|
$sql .= $sqlLimit;
|
|
}
|
|
|
|
return Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql);
|
|
}
|
|
|
|
/**
|
|
* Get configuration (simple method)
|
|
*/
|
|
public static function get($key)
|
|
{
|
|
// Check cache first
|
|
if (isset(self::$data[$key])) {
|
|
return self::$data[$key];
|
|
}
|
|
|
|
// Load from database
|
|
if (!self::$_initialized) {
|
|
self::loadConfiguration();
|
|
}
|
|
|
|
return self::get($key, null, null, null, null);
|
|
}
|
|
|
|
/**
|
|
* Set configuration (simple method)
|
|
*/
|
|
public static function set($key, $value)
|
|
{
|
|
// Update cache
|
|
self::$data[$key] = $value;
|
|
|
|
// Update database
|
|
return self::set($key, [$value]);
|
|
}
|
|
}
|