pnd8_rasp/app/engine/core/object.class.php

664 lines
24 KiB
PHP
Raw 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
class cobject {
var $obj_name;
var $attrs = array();
var $attrs_vals = array();
var $id = 0;
var $errors = array();
var $global_type = 0; // 0 - локальный, 1 - глобальный
var $recursion_depth = 0;
var $force_hidden = array();
var $sql_where; // Глобальное ограничение на объект
var $save_sql = '';
var $diffed = array();
var $exceptPrimaryKeys = ['_sys_cat' => 'cat_id', // объекты где основной ключ не ID при сохранении
'_sys_cat_admin' => 'cat_id'];
/**
* Конструктор
* @param string $obj_name имя таблицы в DB
* @param integer $depth текущия глубина рекурсии (для предотвращения бесконечной рекурсии)
*/
function __construct( $obj_name, $depth = 0 ) {
global $statistica;
$statistica['objects_add']++;
$this->recursion_depth = ($depth+1);
$this->obj_name = $obj_name;
// Определяем тип объекта по имени
//if ( strpos($obj_name, '_sys_') !== false ) {
// All objects is local in basic mode
$this->global_type = 1;
//}
if ($depth <= 2 ) { // Не более 3х вложений!!
$this->getAttrs();
}
$this->attrs_vals = array();
}
/**
* Получить экземпляр базы данных, связанный с объектом
* @return [type] [description]
*/
function getDB() {
global $db, $core_db;
if ( $this->global_type == 1 ) {
return $core_db;
} else {
return $db;
}
}
/**
* Pагружаем атрибуты в объект
* @return [type] [description]
*/
private function getAttrs() {
global $objects_cache;
$curdb = $this->getDB();
if ( $objects_cache[$this->obj_name] ) {
foreach( $objects_cache[$this->obj_name] as $name => $arr ) {
$this->attrs[$name]['name'] = $name;
$this->attrs[$name]['type'] = $arr['attr_type'];
$this->attrs[$name]['templ'] = str_replace('[', '{', str_replace(']', '}', $arr['attr_templ']));
$this->attrs[$name]['desc'] = $arr['attr_desc'];
$this->attrs[$name]['hide'] = $arr['attr_hide'];
$this->attrs[$name]['mand'] = $arr['attr_mand'];
$this->attrs[$name]['attr_obj'] = $this->getAttrObj( $name, $arr['attr_type'] );
}
} else {
$db2 = $curdb->q("SELECT * FROM `_sys_datatypes` WHERE `obj_name` = '".$this->obj_name."' AND !`_sys_deleted` ORDER BY `attr_order` ASC");
while( $db2->r() ) {
$name=$db2->f('attr_name');
$objects_cache[$this->obj_name][$name] = $db2->lastRow;
$this->attrs[$name]['name'] = $name;
$this->attrs[$name]['type'] = $db2->f('attr_type');
$this->attrs[$name]['templ'] = str_replace('[', '{', str_replace(']', '}', $db2->f('attr_templ')));
$this->attrs[$name]['desc'] = $db2->f('attr_desc');
$this->attrs[$name]['hide'] = $db2->f('attr_hide');
$this->attrs[$name]['mand'] = $db2->f('attr_mand');
$this->attrs[$name]['attr_obj'] = $this->getAttrObj( $name, $db2->f('attr_type') );
}
}
}
/**
* Получить объект атрибута
* @param string $attr_name имя атрибута
* @param string $attr_type тип атрибута
* @return object
*/
function getAttrObj( $attr_name, $attr_type ) {
@list($type, $obj_link) = explode( '|', $attr_type );
$classname = 'attr_' . $type;
if ( class_exists( $classname ) ) {
$attr_obj = new $classname( $attr_name, $this);
return $attr_obj;
} else {
die( 'Заявленный класс "' . $classname . '" - не определен' );
}
}
/**
* Расширенный конструктор SQL запросов
* @param string $sql_from что берём
* @param string $sql_where с каким where ограничением
* @param integer $show_deleted забираем ли удалённые объекты (по умолчанию нет)
* @return string SQL запрос
*/
function getSelectEx( $sql_from ="*", $sql_where = "", $show_deleted = 0) {
$sql = "SELECT " . $sql_from;
$sql .= " FROM `" . $this->obj_name . "` WHERE 1 ";
if (!$show_deleted && isset($this->attrs['_sys_deleted']) ) {
$sql .= " AND !`".$this->obj_name."`.`_sys_deleted` ";
}
$sql .= $sql_where;
return $sql;
}
/**
* Конструктор SQL запросов
* @param string $sql_where_in where ограничение
* @param integer $show_deleted забираем ли удалённые объекты (по умолчанию нет)
* @return string SQL запрос
*/
function getSelect($sql_where_in = "", $show_deleted = 0) {
global $auth, $cat;
$sql_joins = '';
/* Access deleted */
$sql_where = '';
if (!$show_deleted && isset($this->attrs['_sys_deleted']) ) {
$sql_where .= " AND !`".$this->obj_name."`.`_sys_deleted` ";
}
/* Access Group */
if ( isset($this->attrs['access_group']) && ( $auth->user_id != _ROOT_USER_ID ) ) {
if ( !$auth->is_login() ) {
$sql_where .= " AND !`".$this->obj_name."`.`access_group` ";
} else {
$tmp_sql[] = ' !`'.$this->obj_name.'`.`access_group` ';
foreach( $auth->groups as $v ) {
$tmp_sql[] = ' FIND_IN_SET('.$v.',`'.$this->obj_name.'`.`access_group`) ';
}
if ($tmp_sql ) {
$sql_where .= " AND (" . implode(" OR ", $tmp_sql ) . " ) ";
} else {
$sql_where .= " AND !`".$this->obj_name."`.`access_group` ";
}
}
}
/* access geo */
if ( isset($this->attrs['access_city']) && !defined('_ADMINKA_') ) {
global $geoip;
$sql_where .= " AND ( FIND_IN_SET(".$geoip->city_id.", `".$this->obj_name."`.`access_city` ) OR `".$this->obj_name."`.`access_city` = '' ) ";
}
/* Global where */
if ( $this->sql_where ) {
$sql_where = $this->sql_where .' '. $sql_where;
}
/* incoming arg */
$sql_where .= $sql_where_in;
/* SELECT */
$sql = "SELECT ";
$sqls[] = " `".$this->obj_name."`.`id` ";
foreach( $this->attrs as $k => $arr ) {
$sqls[] = " `".$this->obj_name."`.`".$k."` ";
}
$sql .= implode(",", $sqls);
$sql .= " FROM `" . $this->obj_name . "` " . $sql_joins . " WHERE 1 ";
$sql .= $sql_where;
return $sql;
}
/**
* Загружаем данные в объект по ID
* @param integer $id ID из таблицы
* @param boolean $usecache Использовать ли кэш
*/
function byId( $id, $usecache = true ) {
global $cached_objects;
$this->diffed = array();
$this->save_sql = '';
if ($cached_objects[$this->obj_name][$id] && $usecache) {
$this->attrs_vals = $cached_objects[$this->obj_name][$id];
$this->id = $id;
} else {
$curdb = $this->getDB();
$db2 = $curdb->q( $this->getSelect( ' AND `'. $this->obj_name.'`.`id` = "'.$id.'" ', 1 ) );
$this->attrs_vals = array();
$this->id = 0;
if ( $db2->r() ) {
foreach( $this->attrs as $k => $arr ) {
$this->attrs_vals[$k] = $db2->f( $k );
}
$this->id = $id;
$cached_objects[$this->obj_name][$id] = $this->attrs_vals;
} else {
return false;
}
}
}
/**
* Сохраняет объект
* @param boolean $do_log логировать ли сохранение
* @param boolean $delayed отложенный UPDATE/INSERT
*/
function save($do_log = true, $delayed = false ) {
$curdb = $this->getDB();
/* только измененные атрибуты */
if ( empty( $this->diffed ) ) return false;
$this->diffed = array_unique($this->diffed);
foreach( $this->diffed as $key ) {
if ( $this->attrs[$key] ) {
$this->attrs[$key]['attr_obj']->presave();
}
}
foreach( $this->diffed as $key ) {
$val = $this->attrs_vals[$key];
if (is_array($val)) {
$val = trim_array($val);
$val = implode(',', $val);
}
$val = db_escape_string( $val );
$update[] = ' `'.$this->obj_name.'`.`'.$key.'` = "' . $val . '" ' ;
$insert[$key] = $val;
}
// Расширенный лог для товаров
$this->itemObjLog();
if ( $this->id ) {
if ($do_log) {
if ($this->global_type == 1 ) {
$db2 = $curdb->q('SELECT * FROM `'.$this->obj_name.'` WHERE `id` = ' . intval( $this->id ) );
if ( $db2->nr() ) {
$old_d = $db2->lastRow;
$new_d = $this->attrs_vals;
foreach( $old_d as $k=>$v ) {
if ( $k == 'id' ) continue;
if ( $k == 'full' ) continue;
if ( $new_d[$k] != $v ) {
$s_old[$k] = $v;
$s_new[$k] = $new_d[$k];
}
}
if ( $s_old || $s_new ) {
global $auth;
$db2->q("INSERT INTO `_sys_obj_log` (`datetime`,`user_id`,`obj_name`,`obj_id`,`old_data`,`user_ip`,`new_data`)
VALUES ('".time()."','".$auth->user_id."','".$this->obj_name."','".$this->id."','".db_escape_string(serialize($s_old))."','".$_SERVER['REMOTE_ADDR']."','".mysql_real_escape_string(serialize($s_new))."') ");
}
}
}
}
if ( $delayed ) {
$sql = 'UPDATE LOW_PRIORITY `'.$this->obj_name.'` SET ';
} else {
$sql = 'UPDATE `'.$this->obj_name.'` SET ';
}
$sql .= implode( ',', $update );
if (isset($this->exceptPrimaryKeys[$this->obj_name]) ) {
$saveKey = $this->exceptPrimaryKeys[$this->obj_name];
$sql .= ' WHERE `'.$this->obj_name.'`.`'.$saveKey.'` = "' . $this->get($saveKey) . '"';
} else {
$sql .= ' WHERE `'.$this->obj_name.'`.`id` = "' . $this->id . '"';
}
$curdb->q( $sql );
$this->save_sql = $sql;
global $cached_objects;
unset($cached_objects[$this->obj_name][$this->id]);
} else {
$sql = 'INSERT INTO `' . $this->obj_name . '` (`' . implode( '`, `', array_keys( $insert ) ) . '`) VALUES ( "' . implode( '", "', array_values( $insert ) ) . '")' ;
$db2 = $curdb->q( $sql );
$this->id = $db2->insert_id();
$this->save_sql = $sql;
if ($do_log) {
if ($this->global_type == 1 ) {
global $auth;
$db2->q("INSERT INTO `_sys_obj_log` (`datetime`,`user_id`,`obj_name`,`obj_id`,`old_data`,`user_ip`,`new_data`)
VALUES ('".time()."','".$auth->user_id."','".$this->obj_name."','".$this->id."','','".$_SERVER['REMOTE_ADDR']."','') ");
}
}
}
foreach( $this->diffed as $key ) {
if ( $this->attrs[$key] ) {
$this->attrs[$key]['attr_obj']->postsave();
}
}
}
/**
* Сбрасывает (обнуляет) объект
*/
public function reset() {
$this->byId(0);
$this->save_sql = '';
$this->diffed = [];
}
/**
* Создает новые объект с данными текущего, но без ID
*/
function copy() {
$this->id = 0;
$this->save_sql = '';
foreach($this->attrs_vals as $k => $v) {
$this->diffed[] = $k;
}
}
/**
* Сохраняет объект как копию
* @param boolean $do_log логировать ли запрос
*/
function saveAsCopy($do_log = true) {
$this->id = 0;
$this->save_sql = '';
foreach( $this->attrs as $key => $val ) {
$this->diffed[] = $key;
}
return $this->save($do_log);
}
/**
* Удаляет объект
*/
function del() {
$curdb = $this->getDB();
if ( $this->id ) {
if ( isset($this->attrs['_sys_deleted']) ) {
$curdb->q('UPDATE `'.$this->obj_name.'` SET `'.$this->obj_name.'`.`_sys_deleted` = "1" WHERE `'.$this->obj_name.'`.`id` = "'.$this->id.'"');
} else {
$curdb->q('DELETE FROM `'.$this->obj_name.'` WHERE `'.$this->obj_name.'`.`id` = "'.$this->id.'"');
}
}
global $cached_objects;
unset($cached_objects[$this->obj_name][$this->id]);
}
/**
* Заплоняет объект строчкой из базы данных
* @param db $db ссылка на подключение к базе данных
*/
function lRow( $db ) {
$this->diffed = array();
foreach( $this->attrs as $key => $val ) {
$this->attrs_vals[$key] = $db->f( $key );
}
$this->id = $db->f('id');
global $cached_objects;
$cached_objects[$this->obj_name][$db->f('id')] = $this->attrs_vals;
return $this;
}
/**
* Заполняет объект из POST данных формы
*/
function lPost() {
if ( intval( $_POST['id']) ) {
$this->byId( intval( $_POST['id']) );
}
foreach( $this->attrs as $k => $val ) {
if (in_array($k, $this->force_hidden ) ) continue;
if ( !isset($_FILES[$k]) && !isset($_POST[$k]) && (!$this->attrs[$k]['mand']) ) {
if ( substr( $val['name'], -8 ) != '_preview' ) {
$this->set($k,'');
}
} else {
$val['attr_obj']->lPost();
}
// $this->diffed[] = $k;
}
$this->id = intval($_POST['id']);
}
/**
* Меняет данных атрибута (сеттер)
* @param string $attr_name имя атрибута
* @param string $value данные
*/
function set( $attr_name, $value ) {
// Проверка на совпадение, с учётом приведения типов
// в this->attrs_vals всегда лежат string
if ( (string)$this->attrs_vals[$attr_name] === (string)$value ) return false;
if ( $this->attrs_vals[$attr_name] === '0' && $value === "") return false;
if ( $this->attrs_vals[$attr_name] === '0' && $value === false ) return false;
if ( $this->attrs_vals[$attr_name] === '1' && $value === true ) return false;
if ( is_numeric($this->attrs_vals[$attr_name]) && is_numeric($value) && $this->attrs_vals[$attr_name] == $value ) return false;
$this->attrs_vals[$attr_name] = $value;
if (!in_array($attr_name, $this->diffed)) {
$this->diffed[] = $attr_name;
}
return true;
}
/**
* Получает данные атрибута из объекта
* @param string $attr_name имя атрибута
* @return string
*/
function get( $attr_name ) {
return $this->attrs_vals[$attr_name];
}
/**
* Отрисовка атрибутов через шаблонизатор Render
* @param string $tpl переменная-шаблон
* @param boolean $crop укороченный вывод
* @param array $params устарело - не используется
* @return [type] [description]
*/
function assign( $tpl, $crop = false, $params = array() ) {
global $R;
$vars = $R->getVars($tpl);
foreach( $this->attrs as $key => $val ) {
if ( in_array( $key, $vars ) ) {
if ($this->recursion_depth < 3 ) {
$tpl = $R->set( $key, $this->attrs[$key]['attr_obj']->render_text($crop), $tpl );
} else {
$tpl = $R->set( $key, $this->get($key), $tpl );
}
}
$tpl = $R->set( $key.'_real', $this->get($key), $tpl );
$tpl = $R->set( $key.'_money', number_format((float)$this->get($key), 2), $tpl );
}
$tpl = $R->set( "id", $this->id, $tpl );
$tpl = $R->set( $this->obj_name."_id", $this->id, $tpl );
return $tpl;
}
function validate() {
$valid = true;
foreach( $this->attrs as $attr_name=>$attr ) {
if (in_array($attr_name, $this->force_hidden ) ) continue;
if ($attr['mand'] && !$this->attrs_vals[$attr_name]) {
$this->errors[$attr_name] = 'Поле не заполнено';
$valid = false;
} elseif ( $this->attrs_vals[$attr_name] ) {
$err = $attr['attr_obj']->validate();
if ( $err && $err !== true ) {
$this->errors[$attr_name] = $err;
$valid = false;
}
}
}
return $valid;
}
function set_hidden( $attr_name ) {
$this->force_hidden[] = $attr_name;
}
function set_no_hidden( $attr_arr = array() ) {
foreach( $this->attrs as $k => $v ) {
if (!in_array($k, $attr_arr ) ) {
$this->force_hidden[] = $k;
}
}
}
function setSqlWhere( $attr_name, $sql_where ) {
if ( $this->attrs[$attr_name] ) {
$this->attrs[$attr_name]['attr_obj']->setSqlWhere($sql_where);
}
}
function addSqlWhere( $attr_name, $sql_where ) {
if ( $this->attrs[$attr_name] ) {
$this->attrs[$attr_name]['attr_obj']->setSqlWhere( $this->attrs[$attr_name]['attr_obj']->sql_where . $sql_where);
}
}
function setError($attr_name, $error) {
$this->errors[$attr_name] = $error;
}
function getSize( $sql_where = '' ) {
$db2 = $this->getDB()->q( $this->getSelectEx(' count(*) as `c` ', $sql_where ) );
$db2->nr();
return intval( $db2->f('c') );
}
function getList( $sql_where = '', $value = 'title' ) {
$db2 = $this->getDB()->q( $this->getSelect( $sql_where ) );
$lst = array();
while($db2->nr()) {
$lst[$db2->f('id')] = $db2->f($value);
}
return $lst;
}
function itemObjLog() {
global $auth;
// array('shop_item', 'shop_item_variants','shop_item_chars','shop_item_images')
if (!in_array($this->obj_name, array('shop_item', 'shop_item_variants',/*'shop_item_chars',*/'shop_item_images') ) ) return;
$skipFields = array('nostock_tmp', 'stock_data', 'stock_roz', 'in_stock', 'stock_im', 'in_stock_im');
$data = array();
$data['datetime'] = time();
$data['ip'] = $_SERVER['REMOTE_ADDR'];
$data['user_id'] = $auth->user_id;
$data['obj_name'] = $this->obj_name;
$data['script_name'] = $_SERVER['PWD'].'/'.$_SERVER['PHP_SELF'];
switch( $this->obj_name ) {
case 'shop_item':
$data['item_id'] = $this->id;
$data['variant_id'] = 0;
break;
case 'shop_item_variants':
$data['item_id'] = $this->get('item_id');
$data['variant_id'] = $this->id;
break;
default:
$data['item_id'] = $this->get('item_id');
$data['variant_id'] = $this->id;
break;
}
$old = array();
if ($this->id ) {
/* OldVals */
$curdb = $this->getDB();
$db2 = $curdb->q('SELECT * FROM `'.$this->obj_name.'` WHERE `id` = ' . intval( $this->id ) );
if ( $db2->nr() ) {
$old = $db2->lastRow;
}
}
foreach( $this->diffed as $field ) {
if (in_array( $field, $skipFields ) ) continue;
$newval = $this->attrs_vals[$field];
$oldval = $old[$field];
if ($newval == $oldval ) continue;
$data['field_name'] = $this->attrs[$field]['name'];
if (!$newval) {
$data['change_type'] = 3;
} elseif( !$oldval ) {
$data['change_type'] = 1;
} else {
$data['change_type'] = 2;
}
$data['old_value'] = db_escape_string($oldval);
$data['new_value'] = db_escape_string($newval);
$sql = 'INSERT DELAYED INTO `shop_item_change_log` (`'.implode("`, `",array_keys($data)).'`) VALUES ("'.implode('", "', $data).'") ';
$curdb = $this->getDB();
$db2 = $curdb->q( $sql );
}
}
function getCollection($sql_where = "", $show_deleted = 0) {
return new cobject_collection($this, $sql_where, $show_deleted);
}
}
/**
* Класс для коллекции объектов.
* Так удобнее работать с blade шаблонами
*/
class cobject_collection {
var $obj;
var $db;
// Готовим запрос в базу
function __construct($obj, $sql_where, $show_deleted = 0) {
$this->obj = $obj;
$this->db = $this->obj->getDB()->q($this->obj->getSelect($sql_where));
}
// Следующий экземпляр коллекции
public function next() {
if ($this->db->nr()) {
$this->obj->lRow($this->db);
return true;
} else {
return false;
}
}
// Получение свойства
public function __get($key) {
return $this->render($key);
}
// Получение реального значения свойства
public function get($key) {
return $this->obj->get($key);
}
// Отрисовка
public function render($key, $crop = false) {
if (isset($this->obj->attrs[$key])) {
if ($this->obj->recursion_depth < 3 ) {
return $this->obj->attrs[$key]['attr_obj']->render_text($crop);
} else {
return $this->obj->get($key);
}
} else {
if ($key == 'id') return $this->obj->id;
return '';
}
}
}
?>