Files
kupshop/class/class.Settings.php
2025-08-02 16:30:27 +02:00

772 lines
18 KiB
PHP

<?php
use KupShop\KupShopBundle\Config;
use KupShop\KupShopBundle\Context\LanguageContext;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\KupShopBundle\Util\Contexts;
use Query\Operator;
/**
* @property string $order_not_in_store Deprecated, use `order_availability` instead
*/
#[\AllowDynamicProperties]
class SettingsBase extends \KupShop\KupShopBundle\Template\ArrayAccess
{
use DatabaseCommunication;
public const ORDER_AVAILABILITY_ALL = 'all';
public const ORDER_AVAILABILITY_IN_STORE = 'in_store';
public const ORDER_AVAILABILITY_IN_STORE_OR_SUPPLIER_STORE = 'in_store_or_supplier_store';
/**
* Singleton instance.
*
* @var Settings
*/
private static $instance = [];
/**
* @var varchar(10)
*/
public $lang = 'czech';
/**
* @var enum('0','1')
*/
public $shop_status = '1';
/**
* Shop description.
*
* @var varchar
*/
public $shop_title;
public $shop_description;
public $shop_keywords;
public $index_title;
public $index_description;
public $index_keywords;
public $shop_firm_name;
public $shop_firm_owner;
public $shop_email;
public $shop_phone;
public $shop_fax;
public $shop_address;
public $shop_ico;
public $shop_dic;
public $shop_vat_payer = 'Y';
public $shop_orders_finished;
public $shop_due_days = 14;
public $review_automatic_confirm;
/**
* Bank account.
*
* @var varchar(6)
*/
public $bank_account_prefix;
public $bank_account_number;
public $bank_code;
public $bank_var_symbol;
public $bank_konst_symbol;
public $bank_name;
public $bank_iban;
public $bank_swift;
/**
* @var enum('Y','N')
*/
public $figure_photos = 'Y';
/**
* @var enum('Y','N')
*/
public $figure_prices = 'Y';
/**
* @var tinyint(2)
*/
public $cat_show_products = 20;
/**
* @var tinyint(2)
*/
public $cat_show_products_search;
/**
* @var enum('Y','N')
*/
public $cat_show_empty = 'Y';
/**
* @var enum('1','2')
*/
public $cat_show_style = 1;
/**
* @var int(4)
*/
public $delete_cart_logged = 0;
/**
* @var int(4)
*/
public $delete_cart_notlogged = 0;
/**
* @var char(3)
*/
public $currency = 'Kč';
/**
* @var int
*/
public $rate = 1;
/**
* @var enum('','status','delete')
*/
public $prod_do_after_order = 'status';
/** @var enum('Y','N') */
public $admin_ean_check = 'Y';
/**
* @var enum('Y','N')
*/
public $prod_show_price_vat = 'Y';
public $prod_prefer_price_vat = 'N';
public $prod_show_not_in_store = 'Y';
public $prod_show_not_in_category = 'Y';
public $prod_show_admin_hidden = 'N';
public string $order_availability = self::ORDER_AVAILABILITY_IN_STORE;
/**
* @var varchar(10)
*/
public $date_format = '%e.%c.%Y';
/**
* @var varchar(10)
*/
public $time_format = '%H:%i:%s';
/**
* @var tinytext
*/
public $order_shopkeeper_mail;
public $order_from_mail;
/**
* Automatic mail sending.
*
* @var enum('Y','N')
*/
public $order_send_to_shopkeeper = 'Y';
public $order_send_received_mail = 'Y';
public $order_send_status_mail = 'Y';
/**
* Array with custom settings from yml shop config.
*
* @var array
*/
public $custom;
/**
* Mail after order received.
*
* @deprecated
*
* @var tinytext
*/
private $order_received_subject;
/**
* @deprecated
*
* @var null
*/
private $order_received_text;
/**
* Mail for order confirmation.
*
* @deprecated
*
* @var tinytext
*/
private $order_template_text;
/**
* Mail for order status change.
*
* @deprecated
*
* @var tinytext
*/
private $order_status_subject;
/**
* @deprecated
*
* @var null
*/
private $order_status_text;
/**
* Custom messages to user.
*
* @deprecated
*
* @var array
*/
private $order_messages = [];
/**
* Custom templates of product descriptions.
*
* @var array
*/
public $product_templates = [];
/**
* @var int
*/
public $price_round = 0;
/**
* @var int
*/
public $price_round_order;
/**
* @var string ('up','down','math')
*/
public $price_round_direction = 'up';
/**
* @var string (0, 2, 'dynamic')
*/
public $price_precision;
/**
* @var string
*/
public $price_decimal_mark = ',';
/**
* @var enum('Y','N')
*/
public $prod_subtract_from_store = 'Y';
/**
* @var enum('Y','N')
*/
public $shop_out_of_order = 'N';
/**
* @var enum('Y','N')
*/
public $shop_closed = 'N';
/**
* @var enum('Y','N')
*/
public $orders_closed = 'N';
public $cookie_bar = [];
/**
* @var enum('Y','N')
*/
public $prod_in_feed_all = 'N';
public $user_rights_version = 99;
public $page_divide = 30;
public $terms_and_conditions_file;
public $invoice_name;
public $currency_code = 'CZK';
public $currencies = [];
public $email;
public $telfa;
public $analytics;
public $balikonos;
public $info_panel;
public $sort_in_cat_by_in_store = 'Y';
public $order_multiple_paid_status = 'N';
public $eshop_live = 'Y';
public $highlight_order_rows = 'N';
public $orders_only_active_custom = 'N';
public $orders_only_active_custom_filter = [];
/**
* List of fields that should not be saved.
*
* @var unknown_type
*/
public static $doNotSerializeFields = ['id', 'is_default', 'name', 'doNotSerializeFields', '_language'];
public function __construct()
{
}
public static function getDefault()
{
return self::getFromCache(
static::getLanguage()
);
}
/**
* @return mixed|Settings|null
*/
public static function getFromCache($languageID)
{
$cacheName = 'settings-'.$languageID;
if (empty(self::$instance[$languageID])) {
if ((self::$instance[$languageID] = getCache($cacheName)) == false) {
self::$instance[$languageID] = self::createFromDB($languageID);
setCache($cacheName, self::$instance[$languageID], 3600);
}
if (!self::$instance[$languageID] instanceof self) {
clearCache($cacheName);
}
}
return self::$instance[$languageID];
}
/**
* Creates Settings object from database.
*
* @param string $languageID
*
* @return Settings
*
* @throws Exception
*/
public static function createFromDB($languageID = null, bool $withDisabledAutoload = false)
{
$SQL = sqlQueryBuilder()
->select('key_name, value')
->from('settings')
->sendToMaster();
if (!$withDisabledAutoload) {
$SQL = $SQL->where(Operator::equals(['autoload' => 1]));
}
$SQL = $SQL->execute();
$decoded = false;
if ($languageID && findModule(Modules::TRANSLATIONS)
&& ($languageID != ServiceContainer::getService(LanguageContext::class)->getDefaultId())) {
try {
$settingsTranslations = ServiceContainer::getService(\KupShop\I18nBundle\Translations\SettingsTranslation::class);
if ($SQLTranslations = $settingsTranslations->setLanguageId($languageID)->fetch($withDisabledAutoload)) {
$SQL = $SQLTranslations;
$decoded = true;
}
$SQL[] = ['key_name' => '_language', 'value' => $languageID];
} catch (Exception $e) {
// Ignore translations error
}
}
$settings = new Settings();
foreach ($SQL as $value) {
if ($decoded) {
$settings->{$value['key_name']} = $value['value'];
} else {
$settings->{$value['key_name']} = json_decode($value['value'], true);
}
}
if (!empty($settings->custom)) {
$settings->custom = (new \KupShop\KupShopBundle\Util\System\CustomSettingsWrapper())->setObject($settings->custom);
}
if ($settings instanceof self) {
return $settings;
}
throw new Exception('Error loading settings');
}
/**
* Creates Settings object from serialized string.
*
* @param string $str
*
* @return Settings
*
* @throws Exception
*/
public static function createFromString($str)
{
$settings = unserialize($str);
if ($settings instanceof self) {
return $settings;
}
throw new Exception('Error loading settings');
}
/**
* Updates settings fields from supplied array.
*
* @param array $data
* @param bool $force
*
* @return bool
*/
public function loadFromArray($data, $force = false)
{
foreach ($data as $key => $value) {
// If $force is not set, allow update only "safe" fields
if (!$force && array_search($key, Settings::$doNotSerializeFields)) {
continue;
}
$this->{$key} = $value;
}
return true;
}
/**
* Overrides stored singleton instance.
*/
public static function setDefault($instance)
{
self::$instance = $instance;
}
/**
* Stores Settings to database.
*
* @deprecated Místo tohodle používej saveValue(key, value). Tahle metoda je šílená, nebezpečná, příjde se snadno o data.
*/
public function saveToDB($settings = null, ?array $disable_autoload = null)
{
// Sanity check. Ensure this settings are not from language
if (!empty($this->_language)) {
// Když dostaneš tuhle exception znamená to, že eshop naloadoval settingy z ne-default jazyka a zkouší je uložit přes saveToDB()
// To je samozřejmě špatně, protože by tím propsal ty jazykový settingy do hlavních.
// TODO: Handlovat languageSettingy a ukládat do translation table
throw new \Exception('Language settings can not be saved to main settings');
}
self::clearCache(true);
if (empty($settings)) {
$settings = get_object_vars($this);
}
$ret = null;
foreach ($settings as $key => $value) {
$ret = $this->saveValue($key, $value, !isset($disable_autoload[$key]));
}
return $ret;
}
public function saveValue($key, $value, bool $autoload = true)
{
$ret = false;
if (!in_array($key, Settings::$doNotSerializeFields) && !is_numeric($key)) {
$ret = sqlQuery('INSERT INTO settings (key_name, value, autoload) VALUES (:key_name, :value, :autoload)
ON DUPLICATE KEY UPDATE value=:value, autoload=:autoload', ['key_name' => $key, 'value' => json_encode($value), 'autoload' => (int) $autoload]);
}
return $ret;
}
public function loadValue($key)
{
$qb = sqlQueryBuilder()
->select('s.value')
->from('settings', 's')
->where(Operator::equals(['s.key_name' => $key]))
->sendToMaster();
if (findModule(Modules::TRANSLATIONS)) {
$activeLangId = static::getLanguage();
if (Contexts::get(LanguageContext::class)->getDefaultId() != $activeLangId) {
$qb = $qb->leftJoin('s', 'settings_translations', 'st', 'st.key_name = s.key_name AND st.id_language = :idlanguage')
->select('COALESCE(st.value, s.value) as value')
->setParameter('idlanguage', $activeLangId);
}
}
return json_decode($qb->execute()->fetchOne(), true);
}
public function deleteValue($key)
{
if (!empty($this->{$key})) {
unset($this->{$key});
}
$this->deleteSQL('settings', ['key_name' => $key]);
}
public function updateValue($key, array $newValue)
{
$value = json_decode(
sqlQueryBuilder()->select('value')->from('settings')
->where(Operator::equals(['key_name' => $key]))
->sendToMaster()->execute()->fetchOne(),
true
);
$value = array_replace_recursive($value, $newValue);
$this->saveValue($key, $value);
$this->{$key} = $value;
self::clearCache();
}
/**
* Get array describing custom settings for this eshop.
*/
public function getCustomSettings()
{
return [];
}
/**
* Get array describing custom settings for this eshop.
*/
public function getYmlCustomSettings()
{
$params = ServiceContainer::getContainer()->getParameterBag()->all();
$params = array_filter($params, function ($key) {
return \KupShop\KupShopBundle\Util\StringUtil::startsWith($key, 'kupshop.custom_settings');
}, ARRAY_FILTER_USE_KEY);
$ymlCustomSettings = [];
foreach ($params as $customSettings) {
$ymlCustomSettings = array_merge($ymlCustomSettings, $customSettings);
}
return $ymlCustomSettings;
}
public static function clearCache($clearInstance = false)
{
foreach (Contexts::get(LanguageContext::class)->getAll() as $language) {
clearCache('settings-'.$language->getId());
}
if ($clearInstance) {
self::$instance = [];
}
}
/**
* @deprecated
*
* @param string|null $languageID
*
* @return array
*/
public function getOrderStatusMessages($status, $languageID = null)
{
$messages = $this->getMailClass()->getOrderStatusMessagesByStatus($status, $languageID);
$messages = array_combine(array_column($messages, 'name'), $messages);
return $messages;
}
/**
* @deprecated
*
* @return object
*/
private function getMailClass()
{
if (!$this->email) {
/* @var \KupShop\KupShopBundle\Util\Mail\Email $email */
$this->email = ServiceContainer::getService("KupShop\KupShopBundle\Util\Mail\Email");
}
return $this->email;
}
/**
* @deprecated
*/
public function getTemplate()
{
return $this->getMailClass()->getBasicTemplate();
}
/**
* @deprecated
*/
public function stripEmail($email)
{
return $this->getMailClass()::stripEmail($email);
}
public static function getTimeFormat()
{
$dbcfg = Settings::getDefault();
switch ($dbcfg['time_format']) {
case '%k:%i:%s':
return 'G:i:s';
break;
case '%H:%i':
return 'H:i';
break;
case '%k:%i':
return 'G:i';
break;
case '%H:%i:%s':
default:
return 'H:i:s';
break;
}
}
public static function getDateFormat()
{
$dbcfg = Settings::getDefault();
switch ($dbcfg['date_format']) {
case '%e.%c.%y':
return 'j.n.y';
break;
case '%d.%m.%Y':
return 'd.m.Y';
break;
case '%d/%m/%Y':
return 'd/m/Y';
break;
case '%d/%m/%y':
return 'd/m/y';
break;
case '%e.%c.%Y':
default:
return 'j.n.Y';
break;
}
}
private static function getLanguage(): string
{
if (isAdministration()) {
return Config::get()['Lang']['admin'] ?? Contexts::get(LanguageContext::class)->getDefaultId();
}
return Contexts::get(LanguageContext::class)->getActiveId();
}
/**
* @deprecated
*/
public function getOrderMessages(): array
{
return $this->order_messages;
}
/**
* @deprecated
*/
public function getOrderReceivedSubject()
{
return $this->order_received_subject;
}
/**
* @deprecated
*/
public function getOrderReceivedText()
{
return $this->order_received_text;
}
/**
* @deprecated
*/
public function getOrderTemplateText()
{
return $this->order_template_text;
}
/**
* @deprecated
*/
public function getOrderStatusSubject()
{
return $this->order_status_subject;
}
/**
* @deprecated
*/
public function getOrderStatusText()
{
return $this->order_status_text;
}
public function &offsetGet(mixed $offset): mixed
{
return $this->__get($offset);
}
public function offsetExists($offset): bool
{
if ($offset === 'order_not_in_store') {
return true;
}
return parent::offsetExists($offset);
}
public function &__get(string $name): mixed
{
// emulate getting of deprecated `order_not_in_store`
if ($name === 'order_not_in_store') {
$result = 'N';
if ($this->order_availability === self::ORDER_AVAILABILITY_ALL) {
$result = 'Y';
}
return $result;
}
if (!property_exists($this, $name)) {
$this->{$name} = null;
}
return $this->{$name};
}
public function __set(string $name, $value)
{
// emulate setting of deprecated `order_not_in_store`
if ($name === 'order_not_in_store') {
$this->order_availability = $value === 'Y' ? self::ORDER_AVAILABILITY_ALL : (findModule(Modules::PRODUCTS_SUPPLIERS) ? self::ORDER_AVAILABILITY_IN_STORE_OR_SUPPLIER_STORE : self::ORDER_AVAILABILITY_IN_STORE);
}
$this->{$name} = $value;
}
}
if (empty($subclass)) {
class Settings extends SettingsBase
{
}
}