1747 lines
48 KiB
PHP
1747 lines
48 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Webshop System - ObjectModel Class
|
|
*
|
|
* @package WebshopSystem
|
|
* @author Webshop System Team
|
|
* @copyright 2024 Webshop System
|
|
* @license MIT
|
|
*/
|
|
|
|
/**
|
|
* ObjectModel - Base class for all database objects
|
|
*/
|
|
abstract class ObjectModel
|
|
{
|
|
/**
|
|
* List of field types
|
|
*/
|
|
public const TYPE_INT = 1;
|
|
public const TYPE_BOOL = 2;
|
|
public const TYPE_STRING = 3;
|
|
public const TYPE_FLOAT = 4;
|
|
public const TYPE_DATE = 5;
|
|
public const TYPE_HTML = 6;
|
|
public const TYPE_NOTHING = 7;
|
|
public const TYPE_SQL = 8;
|
|
|
|
/**
|
|
* List of data to format
|
|
*/
|
|
public const FORMAT_COMMON = 1;
|
|
public const FORMAT_LANG = 2;
|
|
public const FORMAT_SHOP = 3;
|
|
|
|
/**
|
|
* List of association types
|
|
*/
|
|
public const HAS_ONE = 1;
|
|
public const HAS_MANY = 2;
|
|
|
|
/** @var int|null Object ID */
|
|
public $id;
|
|
|
|
/** @var int|null Language ID */
|
|
protected $id_lang = null;
|
|
|
|
/** @var Language|null Language ID */
|
|
protected $lang_associated = null;
|
|
|
|
/** @var int|null Shop ID */
|
|
protected $id_shop = null;
|
|
|
|
/** @var array List of shop IDs */
|
|
public $id_shop_list = [];
|
|
|
|
/** @var bool */
|
|
protected $get_shop_from_context = true;
|
|
|
|
/** @var array|null Holds required fields for each ObjectModel class */
|
|
protected static $fieldsRequiredDatabase = null;
|
|
|
|
/** @var string */
|
|
protected $table;
|
|
|
|
/** @var string */
|
|
protected $identifier;
|
|
|
|
/** @var array */
|
|
protected $tables = [];
|
|
|
|
/** @var array Tables */
|
|
protected $webserviceParameters = [];
|
|
|
|
/** @var string Path to image directory */
|
|
protected $image_dir = null;
|
|
|
|
/** @var string file type of image files */
|
|
protected $image_format = 'jpg';
|
|
|
|
/** @var TranslatorComponent */
|
|
protected $translator;
|
|
|
|
/** @var array Contains object definition */
|
|
public static $definition = [];
|
|
|
|
/** @var array Holds compiled definitions of each ObjectModel class */
|
|
protected static $loaded_classes = [];
|
|
|
|
/** @var array Contains current object definition */
|
|
protected $def;
|
|
|
|
/** @var array|null List of specific fields to update */
|
|
protected $update_fields = null;
|
|
|
|
/** @var Db|bool An instance of the db */
|
|
protected static $db = false;
|
|
|
|
/** @var array|null List of HTML field */
|
|
public static $htmlFields = null;
|
|
|
|
/** @var bool Enables to define an ID before adding object */
|
|
public $force_id = false;
|
|
|
|
/** @var bool if true, objects are cached in memory */
|
|
protected static $cache_objects = true;
|
|
|
|
/**
|
|
* Get repository class name
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function getRepositoryClassName()
|
|
{
|
|
return str_replace('Model', 'Repository', get_called_class());
|
|
}
|
|
|
|
/**
|
|
* Reset static cache
|
|
*/
|
|
public static function resetStaticCache()
|
|
{
|
|
self::$loaded_classes = [];
|
|
self::$fieldsRequiredDatabase = [];
|
|
self::$htmlFields = [];
|
|
}
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param int|null $id
|
|
* @param int|null $id_lang
|
|
* @param int|null $id_shop
|
|
* @param object|null $translator
|
|
*/
|
|
public function __construct($id = null, $id_lang = null, $id_shop = null, $translator = null)
|
|
{
|
|
$this->def = static::$definition;
|
|
$this->setDefinitionRetrocompatibility();
|
|
|
|
if ($id) {
|
|
$this->id = (int) $id;
|
|
$this->id_lang = $id_lang ? (int) $id_lang : (int) Configuration::get('PS_LANG_DEFAULT');
|
|
$this->id_shop = $id_shop ? (int) $id_shop : (int) Context::getContext()->shop->id;
|
|
$this->loadFields();
|
|
}
|
|
|
|
if ($translator) {
|
|
$this->translator = $translator;
|
|
}
|
|
|
|
if (!$this->id_lang) {
|
|
$this->id_lang = (int) Configuration::get('PS_LANG_DEFAULT');
|
|
}
|
|
|
|
if (!$this->id_shop) {
|
|
$this->id_shop = (int) Context::getContext()->shop->id;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set definition retrocompatibility
|
|
*/
|
|
protected function setDefinitionRetrocompatibility()
|
|
{
|
|
if (!isset($this->def['table'])) {
|
|
$this->def['table'] = $this->def['classname'];
|
|
}
|
|
|
|
if (!isset($this->def['primary'])) {
|
|
$this->def['primary'] = 'id_' . $this->def['table'];
|
|
}
|
|
|
|
if (!isset($this->def['fields'])) {
|
|
$this->def['fields'] = [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Save object
|
|
*
|
|
* @param bool $null_values
|
|
* @param bool $auto_date
|
|
* @return bool
|
|
*/
|
|
public function save($null_values = false, $auto_date = true)
|
|
{
|
|
return (int) $this->id > 0 ? $this->update($null_values) : $this->add($auto_date, $null_values);
|
|
}
|
|
|
|
/**
|
|
* Add object to database
|
|
*
|
|
* @param bool $auto_date
|
|
* @param bool $null_values
|
|
* @return bool
|
|
*/
|
|
public function add($auto_date = true, $null_values = false)
|
|
{
|
|
if (isset($this->id) && !$this->force_id) {
|
|
$this->id = null;
|
|
}
|
|
|
|
// Automatically fill dates
|
|
if ($auto_date && property_exists($this, 'date_add')) {
|
|
$this->date_add = date('Y-m-d H:i:s');
|
|
}
|
|
if ($auto_date && property_exists($this, 'date_upd')) {
|
|
$this->date_upd = date('Y-m-d H:i:s');
|
|
}
|
|
|
|
$id_shop_list = [];
|
|
if (Shop::isTableAssociated($this->def['table'])) {
|
|
$id_shop_list = Shop::getContextListShopID();
|
|
if (count($this->id_shop_list)) {
|
|
$id_shop_list = $this->id_shop_list;
|
|
}
|
|
}
|
|
|
|
// Database insertion
|
|
if (Shop::checkIdShopDefault($this->def['table']) && array_key_exists('id_shop_default', get_object_vars($this))) {
|
|
$this->id_shop_default = (in_array(Configuration::get('PS_SHOP_DEFAULT'), $id_shop_list) == true) ? Configuration::get('PS_SHOP_DEFAULT') : min($id_shop_list);
|
|
}
|
|
|
|
if (!$result = Db::getInstance()->insert($this->def['table'], $this->getFields(), $null_values)) {
|
|
return false;
|
|
}
|
|
|
|
// Get object id in database if force_id is not true
|
|
if (empty($this->id)) {
|
|
$this->id = Db::getInstance()->Insert_ID();
|
|
}
|
|
|
|
// Database insertion for multishop fields related to the object
|
|
if (Shop::isTableAssociated($this->def['table'])) {
|
|
$fields = $this->getFieldsShop();
|
|
$fields[$this->def['primary']] = (int) $this->id;
|
|
|
|
foreach ($id_shop_list as $id_shop) {
|
|
$fields['id_shop'] = (int) $id_shop;
|
|
$result &= Db::getInstance()->insert($this->def['table'] . '_shop', $fields, $null_values);
|
|
}
|
|
}
|
|
|
|
if (!$result) {
|
|
return false;
|
|
}
|
|
|
|
// Database insertion for multilingual fields related to the object
|
|
if (!empty($this->def['multilang'])) {
|
|
$fields = $this->getFieldsLang();
|
|
if ($fields && is_array($fields)) {
|
|
$shops = Shop::getCompleteListOfShopsID();
|
|
$asso = Shop::getAssoTable($this->def['table'] . '_lang');
|
|
foreach ($fields as $field) {
|
|
foreach (array_keys($field) as $key) {
|
|
if (!Validate::isTableOrIdentifier($key)) {
|
|
throw new Exception('key ' . $key . ' is not table or identifier');
|
|
}
|
|
}
|
|
$field[$this->def['primary']] = (int) $this->id;
|
|
|
|
if ($asso !== false && $asso['type'] == 'fk_shop') {
|
|
foreach ($shops as $id_shop) {
|
|
$field['id_shop'] = (int) $id_shop;
|
|
$result &= Db::getInstance()->insert($this->def['table'] . '_lang', $field);
|
|
}
|
|
} else {
|
|
$result &= Db::getInstance()->insert($this->def['table'] . '_lang', $field);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Duplicate object
|
|
*
|
|
* @return ObjectModel|false
|
|
*/
|
|
public function duplicateObject()
|
|
{
|
|
$definition = self::getDefinition($this);
|
|
|
|
$res = Db::getInstance()->getRow(
|
|
'SELECT * FROM `' . _DB_PREFIX_ . $definition['table'] . '` WHERE `' . $definition['primary'] . '` = ' . (int) $this->id
|
|
);
|
|
if (!$res) {
|
|
return false;
|
|
}
|
|
|
|
unset($res[$definition['primary']]);
|
|
foreach ($res as $field => &$value) {
|
|
if (isset($definition['fields'][$field])) {
|
|
$value = self::formatValue(
|
|
$value,
|
|
$definition['fields'][$field]['type'],
|
|
false,
|
|
true,
|
|
!empty($definition['fields'][$field]['allow_null'])
|
|
);
|
|
}
|
|
}
|
|
|
|
if (!Db::getInstance()->insert($definition['table'], $res)) {
|
|
return false;
|
|
}
|
|
|
|
$object_id = Db::getInstance()->Insert_ID();
|
|
|
|
if (isset($definition['multilang']) && $definition['multilang']) {
|
|
$result = Db::getInstance()->executeS('
|
|
SELECT * FROM `' . _DB_PREFIX_ . $definition['table'] . '_lang`
|
|
WHERE `' . $definition['primary'] . '` = ' . (int) $this->id
|
|
);
|
|
if (!$result) {
|
|
return false;
|
|
}
|
|
|
|
foreach ($result as $rowKey => $row) {
|
|
foreach ($row as $field => $value) {
|
|
if (isset($definition['fields'][$field])) {
|
|
$result[$rowKey][$field] = self::formatValue(
|
|
$value,
|
|
$definition['fields'][$field]['type'],
|
|
false,
|
|
true,
|
|
!empty($definition['fields'][$field]['allow_null'])
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach ($result as $row2) {
|
|
$row2[$definition['primary']] = (int) $object_id;
|
|
if (!Db::getInstance()->insert($definition['table'] . '_lang', $row2)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
$object_duplicated = new $definition['classname']((int) $object_id);
|
|
$object_duplicated->duplicateShops((int) $this->id);
|
|
|
|
return $object_duplicated;
|
|
}
|
|
|
|
/**
|
|
* Update object in database
|
|
*
|
|
* @param bool $null_values
|
|
* @return bool
|
|
*/
|
|
public function update($null_values = false)
|
|
{
|
|
$this->clearCache();
|
|
|
|
// Automatically fill dates
|
|
if (property_exists($this, 'date_upd')) {
|
|
$this->date_upd = date('Y-m-d H:i:s');
|
|
}
|
|
|
|
$id_shop_list = [];
|
|
if (Shop::isTableAssociated($this->def['table'])) {
|
|
$id_shop_list = Shop::getContextListShopID();
|
|
if (count($this->id_shop_list)) {
|
|
$id_shop_list = $this->id_shop_list;
|
|
}
|
|
}
|
|
|
|
// Database update
|
|
if (!$result = Db::getInstance()->update($this->def['table'], $this->getFields(), '`' . pSQL($this->def['primary']) . '` = ' . (int) $this->id, 0, $null_values)) {
|
|
return false;
|
|
}
|
|
|
|
// Database update for multishop fields related to the object
|
|
if (Shop::isTableAssociated($this->def['table'])) {
|
|
$fields = $this->getFieldsShop();
|
|
if (is_array($fields)) {
|
|
$fields[$this->def['primary']] = (int) $this->id;
|
|
foreach ($id_shop_list as $id_shop) {
|
|
$fields['id_shop'] = (int) $id_shop;
|
|
$where = $this->def['primary'] . ' = ' . (int) $this->id . ' AND id_shop = ' . (int) $id_shop;
|
|
$result &= Db::getInstance()->update($this->def['table'] . '_shop', $fields, $where, 0, $null_values);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Database update for multilingual fields related to the object
|
|
if (!empty($this->def['multilang'])) {
|
|
$fields = $this->getFieldsLang();
|
|
if (is_array($fields)) {
|
|
$shops = Shop::getCompleteListOfShopsID();
|
|
$asso = Shop::getAssoTable($this->def['table'] . '_lang');
|
|
foreach ($fields as $field) {
|
|
$field[$this->def['primary']] = (int) $this->id;
|
|
|
|
if ($asso !== false && $asso['type'] == 'fk_shop') {
|
|
foreach ($shops as $id_shop) {
|
|
$field['id_shop'] = (int) $id_shop;
|
|
$where = $this->def['primary'] . ' = ' . (int) $this->id . ' AND id_lang = ' . (int) $field['id_lang'] . ' AND id_shop = ' . (int) $id_shop;
|
|
$result &= Db::getInstance()->update($this->def['table'] . '_lang', $field, $where, 0, $null_values);
|
|
}
|
|
} else {
|
|
$where = $this->def['primary'] . ' = ' . (int) $this->id . ' AND id_lang = ' . (int) $field['id_lang'];
|
|
$result &= Db::getInstance()->update($this->def['table'] . '_lang', $field, $where, 0, $null_values);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Delete object from database
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function delete()
|
|
{
|
|
$result = true;
|
|
|
|
// Remove from database
|
|
if (!$result = Db::getInstance()->delete($this->def['table'], '`' . $this->def['primary'] . '` = ' . (int) $this->id)) {
|
|
return false;
|
|
}
|
|
|
|
// Database deletion for multilingual fields related to the object
|
|
if (!empty($this->def['multilang'])) {
|
|
$result &= Db::getInstance()->delete($this->def['table'] . '_lang', '`' . $this->def['primary'] . '` = ' . (int) $this->id);
|
|
}
|
|
|
|
// Database deletion for multishop fields related to the object
|
|
if (Shop::isTableAssociated($this->def['table'])) {
|
|
$result &= Db::getInstance()->delete($this->def['table'] . '_shop', '`' . $this->def['primary'] . '` = ' . (int) $this->id);
|
|
}
|
|
|
|
$this->clearCache();
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Delete selection
|
|
*
|
|
* @param array $ids
|
|
* @return bool
|
|
*/
|
|
public function deleteSelection(array $ids)
|
|
{
|
|
$result = true;
|
|
foreach ($ids as $id) {
|
|
$this->id = (int) $id;
|
|
$result = $result && $this->delete();
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Validate fields
|
|
*
|
|
* @param bool $die
|
|
* @param bool $error_return
|
|
* @return bool|string
|
|
*/
|
|
public function validateFields($die = true, $error_return = false)
|
|
{
|
|
$error = true;
|
|
$this->cacheFieldsRequiredDatabase();
|
|
$required_fields = (isset($this->id) && $this->id) ? $this->getCachedFieldsRequiredDatabase($all = false) : $this->getCachedFieldsRequiredDatabase($all = true);
|
|
|
|
if ($required_fields) {
|
|
$fields = $this->getFields();
|
|
foreach ($required_fields as $field) {
|
|
if (!isset($fields[$field]) || !$fields[$field]) {
|
|
$error = $this->displayFieldName($field, get_class($this), true);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (is_string($error)) {
|
|
if ($die) {
|
|
throw new Exception($error);
|
|
}
|
|
return $error_return ? $error : false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get fields
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getFields()
|
|
{
|
|
$this->validateFields();
|
|
$fields = $this->formatFields(self::FORMAT_COMMON);
|
|
foreach ($this->def['fields'] as $field => $data) {
|
|
if ($field == 'id_' . $this->def['table']) {
|
|
$fields[$field] = $this->id;
|
|
}
|
|
}
|
|
|
|
return $fields;
|
|
}
|
|
|
|
/**
|
|
* Get fields shop
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getFieldsShop()
|
|
{
|
|
$fields = $this->formatFields(self::FORMAT_SHOP);
|
|
return $fields;
|
|
}
|
|
|
|
/**
|
|
* Get fields lang
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getFieldsLang()
|
|
{
|
|
$fields = $this->formatFields(self::FORMAT_LANG);
|
|
return $fields;
|
|
}
|
|
|
|
/**
|
|
* Format fields
|
|
*
|
|
* @param int $type
|
|
* @param int|null $id_lang
|
|
* @return array
|
|
*/
|
|
protected function formatFields($type, $id_lang = null)
|
|
{
|
|
$fields = [];
|
|
|
|
if (in_array($type, [self::FORMAT_LANG, self::FORMAT_SHOP])) {
|
|
$fields['id_' . $this->def['table']] = (int) $this->id;
|
|
}
|
|
|
|
if ($type == self::FORMAT_LANG) {
|
|
$fields['id_lang'] = (int) $id_lang;
|
|
}
|
|
|
|
if ($type == self::FORMAT_SHOP && !Shop::isTableAssociated($this->def['table'])) {
|
|
return $fields;
|
|
}
|
|
|
|
foreach ($this->def['fields'] as $field => $data) {
|
|
if (is_array($this->update_fields) && !in_array($field, $this->update_fields)) {
|
|
continue;
|
|
}
|
|
|
|
if ($type == self::FORMAT_LANG && empty($data['lang'])) {
|
|
continue;
|
|
}
|
|
|
|
if ($type == self::FORMAT_SHOP && empty($data['shop'])) {
|
|
continue;
|
|
}
|
|
|
|
if (isset($this->{$field})) {
|
|
$fields[$field] = self::formatValue($this->{$field}, $data['type'], false, true, (isset($data['allow_null']) ? $data['allow_null'] : false));
|
|
}
|
|
}
|
|
|
|
return $fields;
|
|
}
|
|
|
|
/**
|
|
* Format value
|
|
*
|
|
* @param mixed $value
|
|
* @param int $type
|
|
* @param bool $with_quotes
|
|
* @param bool $purify
|
|
* @param bool $allow_null
|
|
* @return string
|
|
*/
|
|
public static function formatValue($value, $type, $with_quotes = false, $purify = true, $allow_null = false)
|
|
{
|
|
if ($allow_null && $value === null) {
|
|
return 'NULL';
|
|
}
|
|
|
|
switch ($type) {
|
|
case self::TYPE_INT:
|
|
return (int) $value;
|
|
|
|
case self::TYPE_BOOL:
|
|
return (int) $value;
|
|
|
|
case self::TYPE_FLOAT:
|
|
return (float) $value;
|
|
|
|
case self::TYPE_DATE:
|
|
if (!$value) {
|
|
return 'NULL';
|
|
}
|
|
if ($with_quotes) {
|
|
return '\'' . pSQL($value) . '\'';
|
|
}
|
|
return pSQL($value);
|
|
|
|
case self::TYPE_HTML:
|
|
if ($purify) {
|
|
$value = Tools::purifyHTML($value);
|
|
}
|
|
if ($with_quotes) {
|
|
return '\'' . pSQL($value, true) . '\'';
|
|
}
|
|
return pSQL($value, true);
|
|
|
|
case self::TYPE_SQL:
|
|
return $value;
|
|
|
|
case self::TYPE_NOTHING:
|
|
return $value;
|
|
|
|
case self::TYPE_STRING:
|
|
default:
|
|
if ($with_quotes) {
|
|
return '\'' . pSQL($value) . '\'';
|
|
}
|
|
return pSQL($value);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Hydrate object
|
|
*
|
|
* @param array $data
|
|
* @param int|null $id_lang
|
|
* @return ObjectModel
|
|
*/
|
|
public function hydrate(array $data, $id_lang = null)
|
|
{
|
|
foreach ($data as $key => $value) {
|
|
if (property_exists($this, $key)) {
|
|
$this->{$key} = $value;
|
|
}
|
|
}
|
|
|
|
if ($id_lang) {
|
|
$this->id_lang = (int) $id_lang;
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Hydrate collection
|
|
*
|
|
* @param string $class
|
|
* @param array $datas
|
|
* @param int|null $id_lang
|
|
* @return array
|
|
*/
|
|
public static function hydrateCollection($class, array $datas, $id_lang = null)
|
|
{
|
|
$collection = [];
|
|
$fields = [];
|
|
|
|
if ($datas) {
|
|
$fields = array_keys($datas[0]);
|
|
}
|
|
|
|
foreach ($datas as $row) {
|
|
$obj = new $class();
|
|
$obj->hydrate($row, $id_lang);
|
|
$collection[] = $obj;
|
|
}
|
|
|
|
return $collection;
|
|
}
|
|
|
|
/**
|
|
* Get definition
|
|
*
|
|
* @param string|ObjectModel $class
|
|
* @param string|null $field
|
|
* @return array
|
|
*/
|
|
public static function getDefinition($class, $field = null)
|
|
{
|
|
if (is_object($class)) {
|
|
$class = get_class($class);
|
|
}
|
|
|
|
if (!isset(self::$definition[$class])) {
|
|
throw new Exception('Definition not found for class ' . $class);
|
|
}
|
|
|
|
if ($field === null) {
|
|
return self::$definition[$class];
|
|
}
|
|
|
|
return isset(self::$definition[$class]['fields'][$field]) ? self::$definition[$class]['fields'][$field] : null;
|
|
}
|
|
|
|
/**
|
|
* Display field name
|
|
*
|
|
* @param string $field
|
|
* @param string $class
|
|
* @param bool $htmlentities
|
|
* @param Context|null $context
|
|
* @return string
|
|
*/
|
|
public static function displayFieldName($field, $class = __CLASS__, $htmlentities = true, ?Context $context = null)
|
|
{
|
|
if (!$context) {
|
|
$context = Context::getContext();
|
|
}
|
|
|
|
$definition = self::getDefinition($class);
|
|
if (isset($definition['fields'][$field]['title'])) {
|
|
$field_name = $definition['fields'][$field]['title'];
|
|
} else {
|
|
$field_name = $field;
|
|
}
|
|
|
|
return $htmlentities ? htmlentities($field_name, ENT_QUOTES, 'utf-8') : $field_name;
|
|
}
|
|
|
|
/**
|
|
* Clear cache
|
|
*
|
|
* @param bool $all
|
|
*/
|
|
public function clearCache($all = false)
|
|
{
|
|
if ($all) {
|
|
self::$loaded_classes = [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Enable cache
|
|
*/
|
|
public static function enableCache()
|
|
{
|
|
self::$cache_objects = true;
|
|
}
|
|
|
|
/**
|
|
* Disable cache
|
|
*/
|
|
public static function disableCache()
|
|
{
|
|
self::$cache_objects = false;
|
|
}
|
|
|
|
/**
|
|
* Load fields
|
|
*/
|
|
protected function loadFields()
|
|
{
|
|
// Load object from database if object id is present
|
|
$sql = 'SELECT * FROM `' . _DB_PREFIX_ . $this->def['table'] . '` WHERE `' . $this->def['primary'] . '` = ' . (int) $this->id;
|
|
$result = Db::getInstance()->getRow($sql);
|
|
if ($result) {
|
|
$this->hydrate($result);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get fully qualified name
|
|
*
|
|
* @return string
|
|
*/
|
|
private function getFullyQualifiedName()
|
|
{
|
|
return str_replace('\\', '', get_class($this));
|
|
}
|
|
|
|
/**
|
|
* Get object name
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getObjectName()
|
|
{
|
|
return get_class($this);
|
|
}
|
|
|
|
/**
|
|
* Validate fields required database
|
|
*
|
|
* @param bool $htmlentities
|
|
* @return bool|string
|
|
*/
|
|
public function validateFieldsRequiredDatabase($htmlentities = true)
|
|
{
|
|
$errors = [];
|
|
$required_fields = $this->getFieldsRequiredDatabase();
|
|
|
|
foreach ($required_fields as $field) {
|
|
if (!$this->validateField($field, $this->{$field}, null, [], $htmlentities)) {
|
|
$errors[] = $this->trans(
|
|
'The field %field_name% is required.',
|
|
['%field_name%' => self::displayFieldName($field, get_class($this), $htmlentities)],
|
|
'Admin.Notifications.Error'
|
|
);
|
|
}
|
|
}
|
|
|
|
if (count($errors)) {
|
|
return $htmlentities ? implode('<br />', $errors) : implode("\n", $errors);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get fields required database
|
|
*
|
|
* @param bool $all
|
|
* @return array
|
|
*/
|
|
public function getFieldsRequiredDatabase($all = false)
|
|
{
|
|
if (!$all && isset($this->id)) {
|
|
return [];
|
|
}
|
|
|
|
$this->cacheFieldsRequiredDatabase($all);
|
|
|
|
$objectName = $this->getObjectName();
|
|
|
|
return !empty(self::$fieldsRequiredDatabase[$objectName])
|
|
? self::$fieldsRequiredDatabase[$objectName]
|
|
: [];
|
|
}
|
|
|
|
/**
|
|
* Check if field is required
|
|
*
|
|
* @param string $field_name
|
|
* @param bool $all
|
|
* @return bool
|
|
*/
|
|
public function isFieldRequired($field_name, $all = false)
|
|
{
|
|
$required_fields = $this->getFieldsRequiredDatabase($all);
|
|
|
|
return in_array($field_name, $required_fields);
|
|
}
|
|
|
|
/**
|
|
* Cache fields required database
|
|
*
|
|
* @param bool $all
|
|
*/
|
|
public function cacheFieldsRequiredDatabase($all = true)
|
|
{
|
|
if (!is_array(self::$fieldsRequiredDatabase)) {
|
|
self::$fieldsRequiredDatabase = [];
|
|
}
|
|
|
|
if ($all && !self::$fieldsRequiredDatabase) {
|
|
$result = Db::getInstance()->executeS('SELECT * FROM ' . _DB_PREFIX_ . 'required_field');
|
|
foreach ($result as $row) {
|
|
self::$fieldsRequiredDatabase[$row['object_name']][] = $row['field_name'];
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get cached fields required database
|
|
*
|
|
* @param bool $all
|
|
* @return array
|
|
*/
|
|
public function getCachedFieldsRequiredDatabase($all = false)
|
|
{
|
|
$this->cacheFieldsRequiredDatabase($all);
|
|
|
|
if ($all) {
|
|
return self::$fieldsRequiredDatabase;
|
|
}
|
|
|
|
$objectName = $this->getObjectName();
|
|
|
|
return !empty(self::$fieldsRequiredDatabase[$objectName])
|
|
? self::$fieldsRequiredDatabase[$objectName]
|
|
: [];
|
|
}
|
|
|
|
/**
|
|
* Add fields required database
|
|
*
|
|
* @param array $fields
|
|
* @return bool
|
|
*/
|
|
public function addFieldsRequiredDatabase($fields)
|
|
{
|
|
if (!is_array($fields)) {
|
|
return false;
|
|
}
|
|
|
|
$objectName = $this->getObjectName();
|
|
if (!Db::getInstance()->execute(
|
|
'DELETE FROM ' . _DB_PREFIX_ . 'required_field'
|
|
. " WHERE object_name = '" . Db::getInstance()->escape($objectName) . "'"
|
|
)) {
|
|
return false;
|
|
}
|
|
|
|
foreach ($fields as $field) {
|
|
if (!Db::getInstance()->insert(
|
|
'required_field',
|
|
['object_name' => $objectName, 'field_name' => pSQL($field)]
|
|
)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Check if object is associated to shop
|
|
*
|
|
* @param int|null $id_shop
|
|
* @return bool
|
|
*/
|
|
public function isAssociatedToShop($id_shop = null)
|
|
{
|
|
if ($id_shop === null) {
|
|
$id_shop = Context::getContext()->shop->id;
|
|
}
|
|
|
|
$cache_id = 'objectmodel_shop_' . $this->def['classname'] . '_' . (int) $this->id . '-' . (int) $id_shop;
|
|
if (!ObjectModel::$cache_objects || !Cache::isStored($cache_id)) {
|
|
$associated = (bool) Db::getInstance()->getValue(
|
|
'
|
|
SELECT id_shop
|
|
FROM `' . pSQL(_DB_PREFIX_ . $this->def['table']) . '_shop`
|
|
WHERE `' . $this->def['primary'] . '` = ' . (int) $this->id . '
|
|
AND id_shop = ' . (int) $id_shop
|
|
);
|
|
|
|
if (!ObjectModel::$cache_objects) {
|
|
return $associated;
|
|
}
|
|
|
|
Cache::store($cache_id, $associated);
|
|
|
|
return $associated;
|
|
}
|
|
|
|
return Cache::retrieve($cache_id);
|
|
}
|
|
|
|
/**
|
|
* Associate object to shops
|
|
*
|
|
* @param int|array $id_shops
|
|
* @return bool|void
|
|
*/
|
|
public function associateTo($id_shops)
|
|
{
|
|
if (!$this->id) {
|
|
return;
|
|
}
|
|
|
|
if (!is_array($id_shops)) {
|
|
$id_shops = [$id_shops];
|
|
}
|
|
|
|
$data = [];
|
|
foreach ($id_shops as $id_shop) {
|
|
if (!$this->isAssociatedToShop($id_shop)) {
|
|
$data[] = [
|
|
$this->def['primary'] => (int) $this->id,
|
|
'id_shop' => (int) $id_shop,
|
|
];
|
|
}
|
|
}
|
|
|
|
if ($data) {
|
|
return Db::getInstance()->insert($this->def['table'] . '_shop', $data);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get associated shops
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getAssociatedShops()
|
|
{
|
|
if (!Shop::isTableAssociated($this->def['table'])) {
|
|
return [];
|
|
}
|
|
|
|
$list = [];
|
|
$sql = 'SELECT id_shop FROM `' . _DB_PREFIX_ . $this->def['table'] . '_shop` WHERE `' . $this->def['primary'] . '` = ' . (int) $this->id;
|
|
foreach (Db::getInstance()->executeS($sql) as $row) {
|
|
$list[] = (int) $row['id_shop'];
|
|
}
|
|
|
|
return $list;
|
|
}
|
|
|
|
/**
|
|
* Duplicate shops
|
|
*
|
|
* @param int $id
|
|
* @return bool|void
|
|
*/
|
|
public function duplicateShops($id)
|
|
{
|
|
if (!Shop::isTableAssociated($this->def['table'])) {
|
|
return false;
|
|
}
|
|
|
|
$sql = 'SELECT id_shop
|
|
FROM ' . _DB_PREFIX_ . $this->def['table'] . '_shop
|
|
WHERE ' . $this->def['primary'] . ' = ' . (int) $id;
|
|
if ($results = Db::getInstance()->executeS($sql)) {
|
|
$ids = [];
|
|
foreach ($results as $row) {
|
|
$ids[] = $row['id_shop'];
|
|
}
|
|
|
|
return $this->associateTo($ids);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if object is multishop
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function isMultishop()
|
|
{
|
|
return Shop::isTableAssociated($this->def['table']) || !empty($this->def['multishop']);
|
|
}
|
|
|
|
/**
|
|
* Check if field is multishop
|
|
*
|
|
* @param string $field
|
|
* @return bool
|
|
*/
|
|
public function isMultiShopField($field)
|
|
{
|
|
return (isset($this->def['fields'][$field]['shop']) && $this->def['fields'][$field]['shop']);
|
|
}
|
|
|
|
/**
|
|
* Check if object is lang multishop
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function isLangMultishop()
|
|
{
|
|
return !empty($this->def['multilang_shop']);
|
|
}
|
|
|
|
/**
|
|
* Update multishop table
|
|
*
|
|
* @param string $classname
|
|
* @param array $data
|
|
* @param string $where
|
|
* @return bool
|
|
*/
|
|
public static function updateMultishopTable($classname, $data, $where = '')
|
|
{
|
|
$def = ObjectModel::getDefinition($classname);
|
|
if (!isset($def['fields'])) {
|
|
return false;
|
|
}
|
|
|
|
$update_fields = [];
|
|
foreach ($def['fields'] as $field_name => $field) {
|
|
if (isset($field['shop']) && $field['shop'] && isset($data[$field_name])) {
|
|
$update_fields[] = '`' . bqSQL($field_name) . '` = \'' . pSQL($data[$field_name]) . '\'';
|
|
}
|
|
}
|
|
|
|
if (!count($update_fields)) {
|
|
return true;
|
|
}
|
|
|
|
return Db::getInstance()->execute('
|
|
UPDATE `' . bqSQL(_DB_PREFIX_ . $def['table']) . '_shop`
|
|
SET ' . implode(', ', $update_fields) . '
|
|
WHERE 1 ' . $where
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get shop ID
|
|
*
|
|
* @return int
|
|
*/
|
|
public function getShopId(): int
|
|
{
|
|
return (int) Context::getContext()->shop->id;
|
|
}
|
|
|
|
/**
|
|
* Delete image
|
|
*
|
|
* @param bool $force_delete
|
|
* @return bool
|
|
*/
|
|
public function deleteImage($force_delete = false)
|
|
{
|
|
if (!$this->id) {
|
|
return false;
|
|
}
|
|
|
|
if ($force_delete || !$this->hasMultishopEntries()) {
|
|
/* Deleting object images and thumbnails (cache) */
|
|
if ($this->image_dir) {
|
|
if (file_exists($this->image_dir . $this->id . '.' . $this->image_format)
|
|
&& !unlink($this->image_dir . $this->id . '.' . $this->image_format)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (isset($this->def['image']['fields'])) {
|
|
foreach ($this->def['image']['fields'] as $field) {
|
|
if (file_exists($this->image_dir . $this->id . '-' . stripslashes($field) . '.' . $this->image_format)
|
|
&& !unlink($this->image_dir . $this->id . '-' . stripslashes($field) . '.' . $this->image_format)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
$types = ImageType::getImagesTypes();
|
|
foreach ($types as $image_type) {
|
|
if (file_exists($this->image_dir . $this->id . '-' . stripslashes($image_type['name']) . '.' . $this->image_format)
|
|
&& !unlink($this->image_dir . $this->id . '-' . stripslashes($image_type['name']) . '.' . $this->image_format)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Check if entity exists in database
|
|
*
|
|
* @param int $id_entity
|
|
* @param string|null $table
|
|
* @return bool
|
|
*/
|
|
public static function existsInDatabase($id_entity, $table = null)
|
|
{
|
|
if ($table === null) {
|
|
$table = self::$definition[get_called_class()]['table'];
|
|
}
|
|
|
|
$sql = 'SELECT `id_' . bqSQL($table) . '`
|
|
FROM `' . bqSQL(_DB_PREFIX_ . $table) . '`
|
|
WHERE `id_' . bqSQL($table) . '` = ' . (int) $id_entity;
|
|
|
|
return (bool) Db::getInstance()->getValue($sql);
|
|
}
|
|
|
|
/**
|
|
* Check if object is currently used
|
|
*
|
|
* @param string|null $table
|
|
* @param bool $has_active_column
|
|
* @return bool
|
|
*/
|
|
public static function isCurrentlyUsed($table = null, $has_active_column = false)
|
|
{
|
|
if ($table === null) {
|
|
$table = self::$definition[get_called_class()]['table'];
|
|
}
|
|
|
|
$sql = 'SELECT `id_' . bqSQL($table) . '` FROM `' . bqSQL(_DB_PREFIX_ . $table) . '`';
|
|
|
|
if ($has_active_column) {
|
|
$sql .= ' WHERE `active` = 1';
|
|
}
|
|
|
|
return (bool) Db::getInstance()->getValue($sql);
|
|
}
|
|
|
|
/**
|
|
* Validate fields lang
|
|
*
|
|
* @param bool $die
|
|
* @param bool $errorReturn
|
|
* @return bool|string
|
|
*/
|
|
public function validateFieldsLang($die = true, $errorReturn = false)
|
|
{
|
|
$errors = [];
|
|
$object = $this;
|
|
|
|
/* Checking for multilingual fields validity */
|
|
foreach ($object->def['fields'] as $field => $data) {
|
|
if (empty($data['lang'])) {
|
|
continue;
|
|
}
|
|
|
|
$values = $object->getFieldsLang();
|
|
|
|
/* If the object has not been loaded in multilanguage, we load all fields from all languages */
|
|
if ($values === false) {
|
|
$values = $object->getFieldsLang((int) Configuration::get('PS_LANG_DEFAULT'));
|
|
}
|
|
|
|
/* The object is not in a language context */
|
|
if (!is_array($values)) {
|
|
continue;
|
|
}
|
|
|
|
foreach ($values as $id_lang => $value) {
|
|
if (empty($value)) {
|
|
continue;
|
|
}
|
|
|
|
$message = $this->validateField($field, $value, (int) $id_lang, [], true);
|
|
if ($message !== true) {
|
|
if ($die) {
|
|
throw new PrestaShopException('Validation error: ' . $message);
|
|
}
|
|
$errors[] = $message;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $errorReturn ? $errors : (count($errors) ? $errors : true);
|
|
}
|
|
|
|
/**
|
|
* Validate controller
|
|
*
|
|
* @param bool $htmlentities
|
|
* @return array
|
|
*/
|
|
public function validateController($htmlentities = true)
|
|
{
|
|
$errors = [];
|
|
|
|
/* Checking for multilingual fields validity */
|
|
$errors = $this->validateFieldsLang($htmlentities);
|
|
|
|
if (!is_array($errors)) {
|
|
$errors = [];
|
|
}
|
|
|
|
/* Checking for fields validity */
|
|
$errors = array_merge($errors, $this->validateFields($htmlentities));
|
|
|
|
return $errors;
|
|
}
|
|
|
|
/**
|
|
* Get webservice parameters
|
|
*
|
|
* @param string|null $ws_params_attribute_name
|
|
* @return array
|
|
*/
|
|
public function getWebserviceParameters($ws_params_attribute_name = null)
|
|
{
|
|
$this->cacheFieldsRequiredDatabase();
|
|
$default_resource_parameters = [
|
|
'objectMethods' => [
|
|
'add' => 'addWs',
|
|
'update' => 'updateWs',
|
|
],
|
|
'objectNodeName' => 'object',
|
|
'objectsNodeName' => 'objects',
|
|
'objectFields' => [
|
|
'id' => [],
|
|
'associations' => [],
|
|
],
|
|
];
|
|
|
|
if (!$ws_params_attribute_name) {
|
|
$ws_params_attribute_name = 'webserviceParameters';
|
|
}
|
|
|
|
if (!isset($this->{$ws_params_attribute_name})) {
|
|
$this->{$ws_params_attribute_name} = [];
|
|
}
|
|
|
|
$resource_parameters = array_merge($default_resource_parameters, $this->{$ws_params_attribute_name});
|
|
|
|
$object_vars = get_object_vars($this);
|
|
if ($resource_parameters['objectFields'] == [] && isset($object_vars['id'])) {
|
|
$resource_parameters['objectFields']['id'] = ['sqlId' => 'id_' . $this->def['table']];
|
|
}
|
|
|
|
// Retrocompatibility
|
|
if (isset($this->def['fields'])) {
|
|
foreach ($this->def['fields'] as $field_name => $field) {
|
|
if (isset($field['size'])) {
|
|
$resource_parameters['objectFields'][$field_name]['size'] = $field['size'];
|
|
}
|
|
if (isset($field['type'])) {
|
|
$resource_parameters['objectFields'][$field_name]['type'] = $field['type'];
|
|
}
|
|
}
|
|
}
|
|
|
|
return $resource_parameters;
|
|
}
|
|
|
|
/**
|
|
* Get webservice object list
|
|
*
|
|
* @param string $sql_join
|
|
* @param string $sql_filter
|
|
* @param string $sql_sort
|
|
* @param string $sql_limit
|
|
* @return array
|
|
*/
|
|
public function getWebserviceObjectList($sql_join, $sql_filter, $sql_sort, $sql_limit)
|
|
{
|
|
$def = $this->getDefinition($this);
|
|
if (isset($def['fields'])) {
|
|
$sql_select = [];
|
|
foreach ($def['fields'] as $field_name => $field) {
|
|
$sql_select[] = 'a.' . $field_name;
|
|
}
|
|
$sql_select = implode(', ', $sql_select);
|
|
} else {
|
|
$sql_select = 'a.*';
|
|
}
|
|
|
|
$sql = 'SELECT DISTINCT ' . $sql_select . '
|
|
FROM `' . _DB_PREFIX_ . bqSQL($def['table']) . '` a
|
|
' . $sql_join . '
|
|
WHERE 1 ' . $sql_filter . '
|
|
' . ($sql_sort ? 'ORDER BY ' . $sql_sort : '') . '
|
|
' . ($sql_limit ? 'LIMIT ' . $sql_limit : '');
|
|
|
|
return Db::getInstance()->executeS($sql, true, false);
|
|
}
|
|
|
|
/**
|
|
* Get field by lang
|
|
*
|
|
* @param string $field_name
|
|
* @param int|null $id_lang
|
|
* @return mixed
|
|
*/
|
|
public function getFieldByLang($field_name, $id_lang = null)
|
|
{
|
|
if (!$id_lang) {
|
|
$id_lang = (int) Configuration::get('PS_LANG_DEFAULT');
|
|
}
|
|
|
|
$sql = 'SELECT ' . bqSQL($field_name) . '
|
|
FROM ' . _DB_PREFIX_ . bqSQL($this->def['table']) . '_lang
|
|
WHERE ' . bqSQL($this->def['primary']) . ' = ' . (int) $this->id . '
|
|
AND id_lang = ' . (int) $id_lang;
|
|
|
|
return Db::getInstance()->getValue($sql);
|
|
}
|
|
|
|
/**
|
|
* Set fields to update
|
|
*
|
|
* @param array|null $fields
|
|
*/
|
|
public function setFieldsToUpdate(?array $fields)
|
|
{
|
|
$this->update_fields = $fields;
|
|
}
|
|
|
|
/**
|
|
* Get fields to update
|
|
*
|
|
* @return array|null
|
|
*/
|
|
public function getFieldsToUpdate(): ?array
|
|
{
|
|
return $this->update_fields;
|
|
}
|
|
|
|
/**
|
|
* Get HTML fields
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getHtmlFields()
|
|
{
|
|
$html_fields = [];
|
|
foreach ($this->def['fields'] as $field_name => $field) {
|
|
if (isset($field['type']) && $field['type'] == self::TYPE_HTML) {
|
|
$html_fields[] = $field_name;
|
|
}
|
|
}
|
|
|
|
return $html_fields;
|
|
}
|
|
|
|
/**
|
|
* Get shop IDs list
|
|
*
|
|
* @return array
|
|
*/
|
|
protected function getShopIdsList(): array
|
|
{
|
|
return Shop::getShops(true, null, true);
|
|
}
|
|
|
|
/**
|
|
* Check if object has multishop entries
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function hasMultishopEntries()
|
|
{
|
|
if (!Shop::isTableAssociated($this->def['table']) || !Shop::isFeatureActive()) {
|
|
return false;
|
|
}
|
|
|
|
return (bool) Db::getInstance()->getValue('SELECT COUNT(*) FROM `' . _DB_PREFIX_ . $this->def['table'] . '_shop` WHERE `' . $this->def['primary'] . '` = ' . (int) $this->id);
|
|
}
|
|
|
|
/**
|
|
* Soft delete object
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function softDelete()
|
|
{
|
|
if (!$this->id) {
|
|
return false;
|
|
}
|
|
|
|
if (isset($this->def['fields']['deleted'])) {
|
|
$this->deleted = true;
|
|
return $this->update();
|
|
}
|
|
|
|
return $this->delete();
|
|
}
|
|
|
|
/**
|
|
* Toggle status
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function toggleStatus()
|
|
{
|
|
if (!$this->id) {
|
|
return false;
|
|
}
|
|
|
|
if (isset($this->def['fields']['active'])) {
|
|
$this->active = !$this->active;
|
|
return $this->update();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Validate field
|
|
*
|
|
* @param string $field
|
|
* @param mixed $value
|
|
* @param int|null $id_lang
|
|
* @param array $skip
|
|
* @param bool $human_errors
|
|
* @return bool|string
|
|
*/
|
|
public function validateField($field, $value, $id_lang = null, $skip = [], $human_errors = false)
|
|
{
|
|
$definition = $this->def['fields'][$field] ?? null;
|
|
if (!$definition) {
|
|
return true;
|
|
}
|
|
|
|
$required = isset($definition['required']) ? $definition['required'] : false;
|
|
$size = isset($definition['size']) ? $definition['size'] : null;
|
|
$values = isset($definition['values']) ? $definition['values'] : null;
|
|
$validate = isset($definition['validate']) ? $definition['validate'] : null;
|
|
|
|
if ($required && empty($value) && $value !== '0') {
|
|
return $human_errors ? $this->trans('The field %field_name% is required.', ['%field_name%' => self::displayFieldName($field, get_class($this))], 'Admin.Notifications.Error') : false;
|
|
}
|
|
|
|
if ($size && strlen($value) > $size) {
|
|
return $human_errors ? $this->trans('The field %field_name% is too long (%length% chars max).', ['%field_name%' => self::displayFieldName($field, get_class($this)), '%length%' => $size], 'Admin.Notifications.Error') : false;
|
|
}
|
|
|
|
if ($values && !in_array($value, $values)) {
|
|
return $human_errors ? $this->trans('The field %field_name% is invalid.', ['%field_name%' => self::displayFieldName($field, get_class($this))], 'Admin.Notifications.Error') : false;
|
|
}
|
|
|
|
if ($validate) {
|
|
if (!method_exists('Validate', $validate)) {
|
|
return $human_errors ? $this->trans('The field %field_name% is invalid.', ['%field_name%' => self::displayFieldName($field, get_class($this))], 'Admin.Notifications.Error') : false;
|
|
}
|
|
|
|
if (!Validate::$validate($value)) {
|
|
return $human_errors ? $this->trans('The field %field_name% is invalid.', ['%field_name%' => self::displayFieldName($field, get_class($this))], 'Admin.Notifications.Error') : false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get associated language
|
|
*
|
|
* @return Language
|
|
*/
|
|
public function getAssociatedLanguage(): Language
|
|
{
|
|
if (!$this->id_lang) {
|
|
$this->id_lang = (int) Configuration::get('PS_LANG_DEFAULT');
|
|
}
|
|
|
|
return new Language($this->id_lang);
|
|
}
|
|
|
|
/**
|
|
* Trans method for translations
|
|
*
|
|
* @param string $id
|
|
* @param array $parameters
|
|
* @param string|null $domain
|
|
* @param string|null $locale
|
|
* @return string
|
|
*/
|
|
protected function trans($id, array $parameters = [], $domain = null, $locale = null)
|
|
{
|
|
if ($this->translator) {
|
|
return $this->translator->trans($id, $parameters, $domain, $locale);
|
|
}
|
|
|
|
return $id;
|
|
}
|
|
|
|
/**
|
|
* Add webservice fields
|
|
*
|
|
* @param array $fields
|
|
*/
|
|
public function addWebserviceFields($fields)
|
|
{
|
|
$this->webserviceParameters['objectFields'] = array_merge(
|
|
$this->webserviceParameters['objectFields'] ?? [],
|
|
$fields
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get webservice object list with associations
|
|
*
|
|
* @param string $sql_join
|
|
* @param string $sql_filter
|
|
* @param string $sql_sort
|
|
* @param string $sql_limit
|
|
* @return array
|
|
*/
|
|
public function getWebserviceObjectListWithAssociations($sql_join, $sql_filter, $sql_sort, $sql_limit)
|
|
{
|
|
$def = $this->getDefinition($this);
|
|
$sql_select = [];
|
|
|
|
if (isset($def['fields'])) {
|
|
foreach ($def['fields'] as $field_name => $field) {
|
|
$sql_select[] = 'a.' . $field_name;
|
|
}
|
|
$sql_select = implode(', ', $sql_select);
|
|
} else {
|
|
$sql_select = 'a.*';
|
|
}
|
|
|
|
// Add associations
|
|
if (isset($def['associations'])) {
|
|
foreach ($def['associations'] as $alias => $association) {
|
|
if (isset($association['fields'])) {
|
|
foreach ($association['fields'] as $field_name => $field) {
|
|
$sql_select .= ', ' . $alias . '.' . $field_name;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$sql = 'SELECT DISTINCT ' . $sql_select . '
|
|
FROM `' . _DB_PREFIX_ . bqSQL($def['table']) . '` a
|
|
' . $sql_join . '
|
|
WHERE 1 ' . $sql_filter . '
|
|
' . ($sql_sort ? 'ORDER BY ' . $sql_sort : '') . '
|
|
' . ($sql_limit ? 'LIMIT ' . $sql_limit : '');
|
|
|
|
return Db::getInstance()->executeS($sql, true, false);
|
|
}
|
|
|
|
/**
|
|
* Get fields for webservice
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getFieldsForWebservice()
|
|
{
|
|
$fields = $this->getFields();
|
|
$def = $this->getDefinition($this);
|
|
|
|
// Add multilang fields
|
|
if (isset($def['fields'])) {
|
|
foreach ($def['fields'] as $field_name => $field) {
|
|
if (isset($field['lang']) && $field['lang']) {
|
|
$fields[$field_name] = $this->getFieldByLang($field_name);
|
|
}
|
|
}
|
|
}
|
|
|
|
return $fields;
|
|
}
|
|
|
|
/**
|
|
* Validate webservice fields
|
|
*
|
|
* @param array $data
|
|
* @return bool|array
|
|
*/
|
|
public function validateWebserviceFields($data)
|
|
{
|
|
$errors = [];
|
|
$def = $this->getDefinition($this);
|
|
|
|
foreach ($data as $field => $value) {
|
|
if (isset($def['fields'][$field])) {
|
|
$validation = $this->validateField($field, $value, null, [], true);
|
|
if ($validation !== true) {
|
|
$errors[] = $validation;
|
|
}
|
|
}
|
|
}
|
|
|
|
return empty($errors) ? true : $errors;
|
|
}
|
|
|
|
/**
|
|
* Get object as array for webservice
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getObjectForWebservice()
|
|
{
|
|
$object = [
|
|
'id' => $this->id,
|
|
'associations' => []
|
|
];
|
|
|
|
$fields = $this->getFieldsForWebservice();
|
|
foreach ($fields as $field => $value) {
|
|
$object[$field] = $value;
|
|
}
|
|
|
|
return $object;
|
|
}
|
|
|
|
/**
|
|
* Update object from webservice data
|
|
*
|
|
* @param array $data
|
|
* @return bool
|
|
*/
|
|
public function updateFromWebservice($data)
|
|
{
|
|
$def = $this->getDefinition($this);
|
|
|
|
foreach ($data as $field => $value) {
|
|
if (isset($def['fields'][$field]) && property_exists($this, $field)) {
|
|
$this->{$field} = $value;
|
|
}
|
|
}
|
|
|
|
return $this->update();
|
|
}
|
|
|
|
/**
|
|
* Get cache key
|
|
*
|
|
* @param string $key
|
|
* @return string
|
|
*/
|
|
protected function getCacheKey($key)
|
|
{
|
|
return 'objectmodel_' . $this->def['classname'] . '_' . $key;
|
|
}
|
|
|
|
/**
|
|
* Store cache
|
|
*
|
|
* @param string $key
|
|
* @param mixed $value
|
|
*/
|
|
protected function storeCache($key, $value)
|
|
{
|
|
if (self::$cache_objects) {
|
|
Cache::store($this->getCacheKey($key), $value);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieve cache
|
|
*
|
|
* @param string $key
|
|
* @return mixed
|
|
*/
|
|
protected function retrieveCache($key)
|
|
{
|
|
if (self::$cache_objects && Cache::isStored($this->getCacheKey($key))) {
|
|
return Cache::retrieve($this->getCacheKey($key));
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Clear object cache
|
|
*/
|
|
protected function clearObjectCache()
|
|
{
|
|
if ($this->id) {
|
|
Cache::clean('objectmodel_' . $this->def['classname'] . '_' . (int) $this->id . '_*');
|
|
}
|
|
}
|
|
}
|