From d3f79db0041193160190694d731ba00929d6f871 Mon Sep 17 00:00:00 2001 From: Elmar Ludwig <elmar.ludwig@uni-osnabrueck.de> Date: Sat, 17 Sep 2022 13:49:47 +0000 Subject: [PATCH] remove SORM config from object instances, re #1473 Merge request studip/studip!920 --- lib/classes/restapi/consumer/OAuth.php | 12 +- lib/models/CourseDate.class.php | 8 +- lib/models/FileRef.php | 2 +- lib/models/ModuleManagementModel.php | 30 +- lib/models/Semester.class.php | 4 +- lib/models/SimpleORMap.class.php | 521 ++++++++++-------- lib/models/StudiengangStgteil.php | 6 - lib/models/User.class.php | 25 +- .../unit/lib/classes/SimpleOrMapNodbTest.php | 16 +- 9 files changed, 321 insertions(+), 303 deletions(-) diff --git a/lib/classes/restapi/consumer/OAuth.php b/lib/classes/restapi/consumer/OAuth.php index daed763ca2d..f5d87ec3028 100644 --- a/lib/classes/restapi/consumer/OAuth.php +++ b/lib/classes/restapi/consumer/OAuth.php @@ -24,6 +24,8 @@ class OAuth extends Base { $config['default_values']['consumer_type'] = 'oauth'; + $config['registered_callbacks']['before_store'][] = 'before_store'; + parent::configure($config); } @@ -106,16 +108,6 @@ class OAuth extends Base return $server; } - /** - * SimpleORMap constructor, registers neccessary callbacks. - */ - public function __construct($id = null) - { - parent::__construct($id); - - $this->registerCallback('before_store', 'before_store'); - } - /** * "Before store" trigger. Creates a clone of the consumer in the * tables for the vendor oauth library. diff --git a/lib/models/CourseDate.class.php b/lib/models/CourseDate.class.php index e98308de3c1..5d8c60dc41f 100644 --- a/lib/models/CourseDate.class.php +++ b/lib/models/CourseDate.class.php @@ -106,6 +106,8 @@ class CourseDate extends SimpleORMap implements PrivacyObject 'on_delete' => 'delete', ]; $config['default_values']['date_typ'] = 1; + $config['registered_callbacks']['before_store'][] = 'cbStudipLog'; + $config['registered_callbacks']['after_create'][] = 'cbStudipLog'; parent::configure($config); } @@ -185,12 +187,6 @@ class CourseDate extends SimpleORMap implements PrivacyObject ); } - public function __construct($id = null) - { - parent::__construct($id); - $this->registerCallback('before_store after_create', 'cbStudipLog'); - } - /** * Adds a topic to this date. * diff --git a/lib/models/FileRef.php b/lib/models/FileRef.php index afdc541bbf1..48c64dc6150 100644 --- a/lib/models/FileRef.php +++ b/lib/models/FileRef.php @@ -199,7 +199,7 @@ class FileRef extends SimpleORMap implements PrivacyObject, FeedbackRange $this->downloads += 1; if (!$this->isNew()) { $where_query = join(' AND ' , $this->getWhereQuery()); - $query = "UPDATE `{$this->db_table}` + $query = "UPDATE `{$this->db_table()}` SET `downloads` = `downloads` + 1 WHERE {$where_query}"; return DBManager::get()->exec($query); diff --git a/lib/models/ModuleManagementModel.php b/lib/models/ModuleManagementModel.php index 39b7d75e229..d6b3eabb979 100644 --- a/lib/models/ModuleManagementModel.php +++ b/lib/models/ModuleManagementModel.php @@ -170,10 +170,10 @@ abstract class ModuleManagementModel extends SimpleORMap implements ModuleManage // check the permissions for every single db field except primary keys if ($this->isNew()) { - $fields = array_diff(array_keys($this->db_fields), - array_values($this->pk)); + $fields = array_diff(array_keys($this->db_fields()), + array_values($this->pk())); } else { - $fields = array_keys($this->db_fields); + $fields = array_keys($this->db_fields()); } foreach ($fields as $field) { if ($this->isFieldDirty($field) @@ -307,7 +307,7 @@ abstract class ModuleManagementModel extends SimpleORMap implements ModuleManage */ protected function logChanges ($action = null) { - switch ($this->db_table) { + switch ($this->db_table()) { case 'abschluss' : $logging = 'MVV_ABSCHLUSS'; $num_index = 1; @@ -467,11 +467,11 @@ abstract class ModuleManagementModel extends SimpleORMap implements ModuleManage } if ($this->isFieldDirty($name)) { $info = ($num_index == 3) ? $debuginfo.';'.$value : $value; - StudipLog::log($logging, $aff, $coaff, $this->db_table.'.'.$name, $info); + StudipLog::log($logging, $aff, $coaff, $this->db_table().'.'.$name, $info); } } } else { - StudipLog::log($logging, $aff, $coaff, $this->db_table, $debuginfo); + StudipLog::log($logging, $aff, $coaff, $this->db_table(), $debuginfo); } return true; @@ -519,12 +519,12 @@ abstract class ModuleManagementModel extends SimpleORMap implements ModuleManage $model_object = new static(); foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $data) { $pkey = []; - foreach ($model_object->pk as $pk) { - $pkey[]= $data[$model_object->db_fields[$pk]['name']]; + foreach (static::pk() as $pk) { + $pkey[]= $data[static::db_fields()[$pk]['name']]; } $data_object = clone $model_object; foreach ($data as $key => $value) { - if (isset($data_object->db_fields[$key])) { + if (isset($data_object->db_fields()[$key])) { $data_object->setValue($key, $value); } else { $data_object->content[mb_strtolower($key)] = $value; @@ -661,9 +661,8 @@ abstract class ModuleManagementModel extends SimpleORMap implements ModuleManage if (!is_array($sort)) { $sort = explode(',', $sort); } - $sorm = new static(); if (sizeof(array_intersect( - array_merge(array_keys($sorm->db_fields), $additional_fields), + array_merge(array_keys(static::db_fields()), $additional_fields), $sort))) { return implode(',', $sort); } @@ -687,12 +686,10 @@ abstract class ModuleManagementModel extends SimpleORMap implements ModuleManage $sort = explode(',', $sort); } $sort = array_map('trim', $sort); - $sorm_name = static::class; - $sorm = new $sorm_name(); $allowed_fields = array_intersect( $sort, array_merge( - array_keys($sorm->db_fields), + array_keys(static::db_fields()), $additional_fields ) ); @@ -731,9 +728,8 @@ abstract class ModuleManagementModel extends SimpleORMap implements ModuleManage } else { $filter_sql = ''; } - $sorm = new static(); $db = DBManager::get()->query('SELECT COUNT(*) FROM ' - . $sorm->db_table . $filter_sql); + . static::db_table() . $filter_sql); return $db->fetchColumn(0); } @@ -795,7 +791,7 @@ abstract class ModuleManagementModel extends SimpleORMap implements ModuleManage $stmt = DBManager::get()->prepare('SELECT DISTINCT `lang` ' . 'FROM i18n ' . 'WHERE `object_id` = ? AND `table` = ?'); - $stmt->execute([$this->id, $this->db_table]); + $stmt->execute([$this->id, $this->db_table()]); foreach ($stmt->fetchAll() as $locale) { $language = mb_strtoupper(mb_strstr($locale['lang'], '_', true)); if (is_array($GLOBALS['MVV_LANGUAGES']['values'][$language])) { diff --git a/lib/models/Semester.class.php b/lib/models/Semester.class.php index 84d90abb668..94a66059da0 100644 --- a/lib/models/Semester.class.php +++ b/lib/models/Semester.class.php @@ -461,7 +461,7 @@ class Semester extends SimpleORMap public function toArray($only_these_fields = null) { if (!isset($only_these_fields)) { - $fields = array_flip(array_diff($this->known_slots, array_keys($this->relations))); + $fields = array_flip(array_diff($this->known_slots(), array_keys($this->relations))); unset($fields['absolute_seminars_count']); unset($fields['duration_seminars_count']); unset($fields['continuous_seminars_count']); @@ -505,7 +505,7 @@ class Semester extends SimpleORMap continue; } - if (in_array('sem_wechsel', $semester->known_slots) && $semester['sem_wechsel']) { + if ($semester['sem_wechsel']) { $timestamp = $semester['sem_wechsel']; } else { $timestamp = $semester['beginn'] - (int)Config::get()->SEMESTER_TIME_SWITCH * 7 * 24 * 60 * 60; diff --git a/lib/models/SimpleORMap.class.php b/lib/models/SimpleORMap.class.php index 476e6462a7a..4bce0cf0540 100644 --- a/lib/models/SimpleORMap.class.php +++ b/lib/models/SimpleORMap.class.php @@ -26,161 +26,217 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate * @var array $content */ protected $content = []; + /** * table row data * @var array $content_db */ protected $content_db = []; + /** * new state of entry * @var boolean $is_new */ protected $is_new = true; + /** * deleted state of entry * @var boolean $is_deleted */ protected $is_deleted = false; + + /** + * db table metadata + * @var ?array $schemes; + */ + public static $schemes = null; + /** - * name of db table - * @var string $db_table + * configuration data for subclasses + * @see self::configure() + * @var array $config; */ - protected $db_table = ''; + protected static $config = []; + /** - * table columns - * @var array $db_fields + * stores instantiated related objects + * @var array $relations */ - protected $db_fields = null; + protected $relations = []; + /** - * primary key columns - * @var array $pk + * assoc array for storing values for additional fields + * + * @var array $additional_data */ - protected $pk = null; + protected $additional_data = []; /** - * default values for columns - * @var array $default_values + * reserved indentifiers, fields with those names must not have an explicit getXXX() method + * @var array $reserved_slots */ - protected $default_values = []; + protected static $reserved_slots = ['value','newid','iterator','tablemetadata', 'relationvalue','wherequery','relationoptions','data','new','id']; /** - * list of columns to deserialize - * @var array key is name of column, value is name of ArrayObject class + * indicator for batch operations in findEachBySQL + * + * @var bool $performs_batch_operation */ - protected $serialized_fields = []; + protected static $performs_batch_operation = false; - /** - * db table metadata - * @var ?array $schemes; + /** + * name of db table + * @return string */ - public static $schemes = null; + protected static function db_table() + { + return static::config('db_table'); + } /** - * configuration data for subclasses - * @see self::configure() - * @var array $config; + * table columns + * @return array */ - protected static $config = []; + protected static function db_fields() + { + return static::config('db_fields'); + } + + /** + * primary key columns + * @return array + */ + protected static function pk() + { + return static::config('pk'); + } + + /** + * default values for columns + * @return array + */ + protected static function default_values() + { + return static::config('default_values'); + } + + /** + * list of columns to deserialize + * @return array key is name of column, value is name of ArrayObject class + */ + protected static function serialized_fields() + { + return static::config('serialized_fields'); + } /** * aliases for columns * alias => column - * @var array $alias_fields + * @return array */ - protected $alias_fields = []; + protected static function alias_fields() + { + return static::config('alias_fields'); + } /** * multi-language fields * name => boolean - * @var array $i18n_fields + * @return array */ - protected $i18n_fields = []; + protected static function i18n_fields() + { + return static::config('i18n_fields'); + } /** * additional computed fields * name => callable - * @var array $additional_fields - */ - protected $additional_fields = []; - - /** - * stores instantiated related objects - * @var array $relations + * @return array */ - protected $relations = []; + protected static function additional_fields() + { + return static::config('additional_fields'); + } /** * 1:n relation - * @var array $has_many + * @return array */ - protected $has_many = []; + protected static function has_many() + { + return static::config('has_many'); + } /** * 1:1 relation - * @var array $has_one + * @return array */ - protected $has_one = []; + protected static function has_one() + { + return static::config('has_one'); + } /** * n:1 relations - * @var array $belongs_to + * @return array */ - protected $belongs_to = []; + protected static function belongs_to() + { + return static::config('belongs_to'); + } /** * n:m relations - * @var array $has_and_belongs_to_many + * @return array */ - protected $has_and_belongs_to_many = []; + protected static function has_and_belongs_to_many() + { + return static::config('has_and_belongs_to_many'); + } /** * callbacks - * @var array<string, array<string|Closure>> registered_callbacks + * @return array<string, array<string|Closure>> */ - protected $registered_callbacks = []; + protected static function registered_callbacks() + { + return static::config('registered_callbacks'); + } /** * contains an array of all used identifiers for fields * (db columns + aliased columns + additional columns + relations) - * @var array $known_slots - */ - protected $known_slots = []; - - /** - * reserved indentifiers, fields with those names must not have an explicit getXXX() method - * @var array $reserved_slots + * @return array */ - protected static $reserved_slots = ['value','newid','iterator','tablemetadata', 'relationvalue','wherequery','relationoptions','data','new','id']; + protected static function known_slots() + { + return static::config('known_slots'); + } /** * assoc array used to map SORM callback to NotificationCenter * keys are SORM callbacks, values notifications * eg. 'after_create' => 'FooDidCreate' * - * @var array $notification_map - */ - protected $notification_map = []; - - /** - * assoc array for storing values for additional fields - * - * @var array $additional_data + * @return array */ - protected $additional_data = []; + protected static function notification_map() + { + return static::config('notification_map'); + } /** * assoc array for mapping get/set Methods * - * @var array $getter_setter_map + * @return array */ - protected $getter_setter_map = []; + protected static function getter_setter_map() + { + return static::config('getter_setter_map'); + } - /** - * indicator for batch operations in findEachBySQL - * - * @var bool $performs_batch_operation - */ - protected static $performs_batch_operation = false; + ////////////////////////////////////////////////// /** * set configuration data from subclass @@ -241,11 +297,19 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate } } + foreach (['default_values', 'serialized_fields', 'alias_fields', 'i18n_fields', 'additional_fields'] as $fields) { + if (!isset($config[$fields])) { + $config[$fields] = []; + } + } + foreach (['has_many', 'belongs_to', 'has_one', 'has_and_belongs_to_many'] as $type) { if (isset($config[$type]) && is_array($config[$type])) { foreach (array_keys($config[$type]) as $one) { $config['relations'][$one] = null; } + } else { + $config[$type] = []; } } @@ -298,12 +362,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate } } - if (I18N::isEnabled()) { - if (isset($config['i18n_fields']) && count($config['i18n_fields']) > 0) { - $config['registered_callbacks']['before_store'][] = 'cbI18N'; - $config['registered_callbacks']['after_delete'][] = 'cbI18N'; - } - } else { + if (!I18N::isEnabled()) { $config['i18n_fields'] = []; } @@ -416,7 +475,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate public static function exists($id) { $ret = false; - $db_table = static::config('db_table'); + $db_table = static::db_table(); $class = get_called_class(); $record = new $class(); call_user_func_array([$record, 'setId'], func_get_args()); @@ -438,7 +497,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate */ public static function countBySql($sql = '1', $params = []) { - $db_table = static::config('db_table'); + $db_table = static::db_table(); $db = DBManager::get(); $has_join = stripos($sql, 'JOIN '); if ($has_join === false || $has_join > 10) { @@ -562,7 +621,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate */ public static function findBySQL($sql, $params = []) { - $db_table = static::config('db_table'); + $db_table = static::db_table(); $class = get_called_class(); $record = new $class(); $db = DBManager::get(); @@ -617,7 +676,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate $thru_assoc_key = $options['thru_assoc_key']; $assoc_foreign_key = $options['assoc_foreign_key']; - $db_table = static::config('db_table'); + $db_table = static::db_table(); $class = get_called_class(); $record = new $class(); $sql = "SELECT `$db_table`.* FROM `$thru_table` @@ -658,7 +717,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate $record = new $class(); $record->setNew(false); - $db_table = static::config('db_table'); + $db_table = static::db_table(); $st = DBManager::get()->prepare("SELECT `{$db_table}`.* FROM `{$db_table}` {$sql}"); $st->execute($params); $st->setFetchMode(PDO::FETCH_INTO , $record); @@ -691,8 +750,8 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate */ public static function findMany($pks = [], $order = '', $order_params = []) { - $db_table = static::config('db_table'); - $pk = static::config('pk'); + $db_table = static::db_table(); + $pk = static::pk(); $db = DBManager::get(); if (count($pk) > 1) { throw new Exception('not implemented yet'); @@ -712,8 +771,8 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate */ public static function findEachMany($callable, $pks = [], $order = '', $order_params = []) { - $db_table = static::config('db_table'); - $pk = static::config('pk'); + $db_table = static::db_table(); + $pk = static::pk(); $db = DBManager::get(); if (count($pk) > 1) { throw new Exception('not implemented yet'); @@ -757,8 +816,8 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate $calleach = function($m) use (&$ret, $callable) { $ret[] = $callable($m); }; - $db_table = static::config('db_table'); - $pk = static::config('pk'); + $db_table = static::db_table(); + $pk = static::pk(); $db = DBManager::get(); if (count($pk) > 1) { throw new Exception('not implemented yet'); @@ -795,7 +854,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate return $id_or_object; } if (is_array($id_or_object)) { - $pk = static::config('pk'); + $pk = static::pk(); $key_values = []; foreach($pk as $key) { if (array_key_exists($key, $id_or_object)) { @@ -825,9 +884,9 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate */ public static function __callStatic($name, $arguments) { - $db_table = static::config('db_table'); - $alias_fields = static::config('alias_fields'); - $db_fields = static::config('db_fields'); + $db_table = static::db_table(); + $alias_fields = static::alias_fields(); + $db_fields = static::db_fields(); $name = strtolower($name); $class = get_called_class(); $order = ''; @@ -886,15 +945,9 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate */ function __construct($id = null) { - $class = get_class($this); - //initialize configuration for subclass, only one time - if (!array_key_exists($class, self::$config)) { - static::configure(); - } - //if configuration data for subclass is found, point internal properties to it - if (self::$config[$class] !== null) { - foreach (array_keys(self::$config[$class]) as $config_key) { - $this->{$config_key} = self::$config[$class][$config_key]; + foreach(['has_many', 'belongs_to', 'has_one', 'has_and_belongs_to_many'] as $type) { + foreach (array_keys($this->$type()) as $one) { + $this->relations[$one] = null; } } @@ -935,8 +988,8 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate */ protected function _getAdditionalValueFromRelation($field) { - list($relation, $relation_field) = [$this->additional_fields[$field]['relation'], - $this->additional_fields[$field]['relation_field']]; + list($relation, $relation_field) = [$this->additional_fields()[$field]['relation'], + $this->additional_fields()[$field]['relation_field']]; if (!array_key_exists($field, $this->additional_data)) { $this->_setAdditionalValue($field, $this->getRelationValue($relation, $relation_field)); } @@ -952,8 +1005,8 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate */ protected function _setAdditionalValueFromRelation($field, $value) { - list($relation, $relation_field) = [$this->additional_fields[$field]['relation'], - $this->additional_fields[$field]['relation_field']]; + list($relation, $relation_field) = [$this->additional_fields()[$field]['relation'], + $this->additional_fields()[$field]['relation_field']]; $this->$relation->$field = $value; unset($this->additional_data[$field]); return $this->_getAdditionalValueFromRelation($field); @@ -985,8 +1038,8 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate function __clone() { //all references link still to old object => reset all aliases - foreach ($this->alias_fields as $alias => $field) { - if (isset($this->db_fields[$field])) { + foreach ($this->alias_fields() as $alias => $field) { + if (isset($this->db_fields()[$field])) { $content_value = $this->content[$field]; $content_db_value = $this->content_db[$field]; unset($this->content[$alias]); @@ -1010,7 +1063,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate //unset all relations for now //TODO: maybe a deep copy of all belonging objects is more appropriate foreach(['has_many', 'belongs_to', 'has_one', 'has_and_belongs_to_many'] as $type) { - foreach (array_keys($this->{$type}) as $one) { + foreach (array_keys($this->$type()) as $one) { $this->relations[$one] = null; } } @@ -1034,7 +1087,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate } if (empty($options['assoc_foreign_key'])) { if ($type === 'has_many' || $type === 'has_one') { - $options['assoc_foreign_key'] = $this->pk[0]; + $options['assoc_foreign_key'] = $this->pk()[0]; } else if ($type === 'belongs_to') { $options['assoc_foreign_key'] = 'id'; } @@ -1042,7 +1095,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate if ($type === 'has_and_belongs_to_many') { $thru_table = $options['thru_table']; if (!$options['thru_key']) { - $options['thru_key'] = $this->pk[0]; + $options['thru_key'] = $this->pk()[0]; } if (empty($options['thru_assoc_key']) || empty($options['assoc_foreign_key'])) { $class = $options['class_name']; @@ -1125,13 +1178,12 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate { $options = []; foreach(['has_many', 'belongs_to', 'has_one', 'has_and_belongs_to_many'] as $type) { - if (isset($this->{$type}[$relation])) { - $options = self::$config[get_class($this)][$type][$relation] ?: $this->{$type}[$relation]; + if (isset($this->$type()[$relation])) { + $options = self::$config[get_class($this)][$type][$relation]; if (!isset($options['type'])) { - $options = $this->parseRelationOptions($type, $relation, $options, $this->db_table); + $options = $this->parseRelationOptions($type, $relation, $options, $this->db_table()); $options['type'] = $type; self::$config[get_class($this)][$type][$relation] = $options; - $this->{$type}[$relation] = $options; } break; } @@ -1146,11 +1198,11 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate */ function getTableMetadata() { - return ['fields' => $this->db_fields, - 'pk' => $this->pk, - 'table' => $this->db_table, - 'additional_fields' => $this->additional_fields, - 'alias_fields' => $this->alias_fields, + return ['fields' => $this->db_fields(), + 'pk' => $this->pk(), + 'table' => $this->db_table(), + 'additional_fields' => $this->additional_fields(), + 'alias_fields' => $this->alias_fields(), 'relations' => array_keys($this->relations)]; } @@ -1161,7 +1213,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate */ function hasAutoIncrementColumn() { - return $this->db_fields[$this->pk[0]]['extra'] == 'auto_increment'; + return $this->db_fields()[$this->pk()[0]]['extra'] == 'auto_increment'; } /** @@ -1175,10 +1227,10 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate if (!is_array($id)){ $id = [$id]; } - if (count($this->pk) != count($id)){ - throw new InvalidArgumentException("Invalid ID, Primary Key {$this->db_table} is " .join(",",$this->pk)); + if (count($this->pk()) != count($id)){ + throw new InvalidArgumentException("Invalid ID, Primary Key {$this->db_table()} is " .join(",",$this->pk())); } else { - foreach ($this->pk as $count => $key){ + foreach ($this->pk() as $count => $key){ $this->content[$key] = $id[$count]; } return true; @@ -1192,16 +1244,16 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate */ function getId() { - if (count($this->pk) == 1) { - return $this->content[$this->pk[0]] ?? null; + if (count($this->pk()) == 1) { + return $this->content[$this->pk()[0]] ?? null; } else { $id = []; - foreach ($this->pk as $key) { + foreach ($this->pk() as $key) { if (array_key_exists($key, $this->content)) { $id[] = $this->content[$key]; } } - return (count($this->pk) == count($id) ? $id : null); + return (count($this->pk()) == count($id) ? $id : null); } } @@ -1213,11 +1265,11 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate function getNewId() { $id = false; - if (count($this->pk) == 1) { + if (count($this->pk()) == 1) { do { - $id = md5(uniqid($this->db_table, 1)); - $db = DBManager::get()->query("SELECT `{$this->pk[0]}` FROM `{$this->db_table}` " - . "WHERE `{$this->pk[0]}` = '$id'"); + $id = md5(uniqid($this->db_table(), 1)); + $db = DBManager::get()->query("SELECT `{$this->pk()[0]}` FROM `{$this->db_table()}` " + . "WHERE `{$this->pk()[0]}` = '$id'"); } while($db->fetch()); } return $id; @@ -1237,7 +1289,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate if (is_string($only_these_fields)) { $only_these_fields = words($only_these_fields); } - $fields = array_diff($this->known_slots, array_keys($this->relations)); + $fields = array_diff($this->known_slots(), array_keys($this->relations)); if (is_array($only_these_fields)) { $only_these_fields = array_filter(array_map(function($s) { return is_string($s) ? strtolower($s) : null; @@ -1268,7 +1320,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate if (is_string($only_these_fields)) { $only_these_fields = words($only_these_fields); } - $fields = array_keys($this->db_fields); + $fields = array_keys($this->db_fields()); if (is_array($only_these_fields)) { $only_these_fields = array_filter(array_map(function ($s) { return is_string($s) ? strtolower($s) : null; @@ -1313,7 +1365,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate $only_these_fields = words($only_these_fields); } if (is_null($only_these_fields)) { - $only_these_fields = $this->known_slots; + $only_these_fields = $this->known_slots(); } $ret = $this->toArray($only_these_fields); $relations = []; @@ -1363,13 +1415,13 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate $field = strtolower($field); // No value defined, throw exception - if (!in_array($field, $this->known_slots)) { + if (!in_array($field, $this->known_slots())) { throw new InvalidArgumentException(static::class . '::'.$field . ' not found.'); } // Get value by getter - if (isset($this->getter_setter_map[$field]['get'])) { - return call_user_func([$this, $this->getter_setter_map[$field]['get']]); + if (isset($this->getter_setter_map()[$field]['get'])) { + return call_user_func([$this, $this->getter_setter_map()[$field]['get']]); } // Get value from content @@ -1384,14 +1436,14 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate } // Get value from additional_field - if (isset($this->additional_fields[$field]['get'])) { + if (isset($this->additional_fields()[$field]['get'])) { // Getter is defined as a closure - if ($this->additional_fields[$field]['get'] instanceof Closure) { - return call_user_func_array($this->additional_fields[$field]['get'], [$this, $field]); + if ($this->additional_fields()[$field]['get'] instanceof Closure) { + return call_user_func_array($this->additional_fields()[$field]['get'], [$this, $field]); } // Getter is defined as a method of this object - return call_user_func([$this, $this->additional_fields[$field]['get']], $field); + return call_user_func([$this, $this->additional_fields()[$field]['get']], $field); } // No value found, throw exception @@ -1428,9 +1480,9 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate function getDefaultValue($field) { $default_value = null; - if (!isset($this->default_values[$field])) { - if (!in_array($field, $this->pk)) { - $meta = $this->db_fields[$field]; + if (!isset($this->default_values()[$field])) { + if (!in_array($field, $this->pk())) { + $meta = $this->db_fields()[$field]; if (isset($meta['default'])) { $default_value = $meta['default']; } elseif ($meta['null'] == 'NO') { @@ -1443,7 +1495,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate } } } else { - $default_value = $this->default_values[$field]; + $default_value = $this->default_values()[$field]; } return $default_value; } @@ -1461,23 +1513,23 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate { $field = strtolower($field); $ret = false; - if (in_array($field, $this->known_slots)) { - if (isset($this->getter_setter_map[$field]['set'])) { - return call_user_func([$this, $this->getter_setter_map[$field]['set']], $value); + if (in_array($field, $this->known_slots())) { + if (isset($this->getter_setter_map()[$field]['set'])) { + return call_user_func([$this, $this->getter_setter_map()[$field]['set']], $value); } if (array_key_exists($field, $this->content)) { - if (array_key_exists($field, $this->serialized_fields)) { + if (array_key_exists($field, $this->serialized_fields())) { $ret = $this->setSerializedValue($field, $value); } elseif ($this->isI18nField($field)) { $ret = $this->setI18nValue($field, $value); } else { $ret = ($this->content[$field] = $value); } - } elseif (isset($this->additional_fields[$field]['set'])) { - if ($this->additional_fields[$field]['set'] instanceof Closure) { - return call_user_func_array($this->additional_fields[$field]['set'], [$this, $field, $value]); + } elseif (isset($this->additional_fields()[$field]['set'])) { + if ($this->additional_fields()[$field]['set'] instanceof Closure) { + return call_user_func_array($this->additional_fields()[$field]['set'], [$this, $field, $value]); } else { - return call_user_func([$this, $this->additional_fields[$field]['set']], $field, $value); + return call_user_func([$this, $this->additional_fields()[$field]['set']], $field, $value); } } elseif (array_key_exists($field, $this->relations)) { $options = $this->getRelationOptions($field); @@ -1570,7 +1622,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate function __isset($field) { $field = strtolower($field); - if (in_array($field, $this->known_slots)) { + if (in_array($field, $this->known_slots())) { $value = $this->getValue($field); return $value instanceOf SimpleORMapCollection ? (bool)count($value) : !is_null($value); } else { @@ -1640,7 +1692,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate */ public function count() { - return count($this->known_slots) - count($this->relations); + return count($this->known_slots()) - count($this->relations); } /** @@ -1651,7 +1703,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate function isField($field) { $field = strtolower($field); - return isset($this->db_fields[$field]); + return isset($this->db_fields()[$field]); } /** @@ -1662,7 +1714,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate function isAdditionalField($field) { $field = strtolower($field); - return isset($this->additional_fields[$field]); + return isset($this->additional_fields()[$field]); } /** @@ -1673,7 +1725,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate function isAliasField($field) { $field = strtolower($field); - return isset($this->alias_fields[$field]); + return isset($this->alias_fields()[$field]); } /** @@ -1684,7 +1736,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate function isI18nField($field) { $field = strtolower($field); - return isset($this->i18n_fields[$field]); + return isset($this->i18n_fields()[$field]); } /** @@ -1709,9 +1761,9 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate if (is_iterable($data)) { foreach($data as $key => $value) { $key = strtolower($key); - if (isset($this->db_fields[$key]) - || isset($this->alias_fields[$key]) - || isset($this->additional_fields[$key]['set']) + if (isset($this->db_fields()[$key]) + || isset($this->alias_fields()[$key]) + || isset($this->additional_fields()[$key]['set']) ) { $this->setValue($key, $value); ++$count; @@ -1762,10 +1814,10 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate { $where_query = null; $pk_not_set = []; - foreach ($this->pk as $key) { + foreach ($this->pk() as $key) { $pk = $this->content_db[$key] ?? $this->content[$key] ?? null; if (isset($pk)) { - $where_query[] = "`{$this->db_table}`.`{$key}` = " . DBManager::get()->quote($pk); + $where_query[] = "`{$this->db_table()}`.`{$key}` = " . DBManager::get()->quote($pk); } else { $pk_not_set[] = $key; } @@ -1793,7 +1845,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate return false; } $this->initializeContent(); - $query = "SELECT * FROM `{$this->db_table}` WHERE " + $query = "SELECT * FROM `{$this->db_table()}` WHERE " . join(" AND ", $where_query); $st = DBManager::get()->prepare($query); $st->execute(); @@ -1834,7 +1886,18 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate return false; } } - foreach ($this->db_fields as $field => $meta) { + + // Collect i18n contents + $i18ncontent = []; + foreach (array_keys($this->i18n_fields()) as $field) { + if ($this->content[$field] instanceof I18NString) { + $i18ncontent[$field] = $this->content[$field]; + $this->content[$field] = $this->content[$field]->original(); + $this->content_db[$field] = $this->content_db[$field]->original(); + } + } + + foreach ($this->db_fields() as $field => $meta) { $value = $this->content[$field]; if ($field == 'chdate' && !$this->isFieldDirty($field) && $this->isDirty()) { $value = time(); @@ -1849,7 +1912,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate } } if ($value === null && $meta['null'] == 'NO') { - throw new UnexpectedValueException($this->db_table . '.' . $field . ' must not be null.'); + throw new UnexpectedValueException($this->db_table() . '.' . $field . ' must not be null.'); } if (is_float($value)) { $value = str_replace(',', '.', $value); @@ -1859,14 +1922,31 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate } if (!$this->isNew()) { $where_query = $this->getWhereQuery(); - $query = "UPDATE `{$this->db_table}` SET " + $query = "UPDATE `{$this->db_table()}` SET " . implode(',', $query_part); $query .= " WHERE " . join(" AND ", $where_query); } else { - $query = "INSERT INTO `{$this->db_table}` SET " + $query = "INSERT INTO `{$this->db_table()}` SET " . implode(',', $query_part); } $ret = DBManager::get()->exec($query); + + // Store i18n contents + if (count($i18ncontent) > 0) { + foreach ($i18ncontent as $field => $one) { + $meta = [ + 'object_id' => $this->getId(), + 'table' => $this->db_table(), + 'field' => $field + ]; + $one->setMetadata($meta); + $one->storeTranslations(); + if (!$this->content[$field] instanceof I18NString) { + $this->content[$field] = $one; + $this->content_db[$field] = clone $one; + } + } + } if ($this->isNew()) { $this->applyCallbacks('after_create'); } else { @@ -1950,10 +2030,10 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate */ function triggerChdate() { - if ($this->db_fields['chdate']) { + if ($this->db_fields()['chdate']) { $this->content['chdate'] = time(); if ($where_query = $this->getWhereQuery()) { - DBManager::get()->exec("UPDATE `{$this->db_table}` SET chdate={$this->content['chdate']} + DBManager::get()->exec("UPDATE `{$this->db_table()}` SET chdate={$this->content['chdate']} WHERE ". join(" AND ", $where_query)); return true; } @@ -1977,12 +2057,21 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate $ret = $this->deleteRelations(); $where_query = $this->getWhereQuery(); if ($where_query) { - $query = "DELETE FROM `{$this->db_table}` WHERE " + $query = "DELETE FROM `{$this->db_table()}` WHERE " . join(" AND ", $where_query); $ret += DBManager::get()->exec($query); } $this->is_deleted = true; $this->applyCallbacks('after_delete'); + + // Remove i18n translations + if (I18N::isEnabled()) { + foreach (array_keys($this->i18n_fields()) as $field) { + if ($this->content[$field] instanceof I18NString) { + $this->content[$field]->removeTranslations(); + } + } + } } $this->setData([], true); return $ret; @@ -2039,13 +2128,13 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate protected function initializeContent() { $this->content = []; - foreach (array_keys($this->db_fields) as $field) { + foreach (array_keys($this->db_fields()) as $field) { $this->content[$field] = null; $this->content_db[$field] = null; $this->setValue($field, $this->getDefaultValue($field)); } - foreach ($this->alias_fields as $alias => $field) { - if (isset($this->db_fields[$field])) { + foreach ($this->alias_fields() as $alias => $field) { + if (isset($this->db_fields()[$field])) { $this->content[$alias] =& $this->content[$field]; $this->content_db[$alias] =& $this->content_db[$field]; } else { @@ -2065,7 +2154,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate */ public function isDirty() { - foreach (array_keys($this->db_fields) as $field) { + foreach (array_keys($this->db_fields()) as $field) { if ($this->isFieldDirty($field)) { return true; } @@ -2183,7 +2272,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate protected function applyCallbacks($type) { $ok = true; - foreach ($this->registered_callbacks[$type] as $cb) { + foreach ($this->registered_callbacks()[$type] as $cb) { if ($cb instanceof Closure) { $function = $cb; $params = [$this, $type, $cb]; @@ -2208,14 +2297,19 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate * @throws InvalidArgumentException if the callback type is not known * @return number of registered callbacks */ - protected function registerCallback($types, $cb) + protected static function registerCallback($types, $cb) { + trigger_error(__METHOD__ . ' is deprecated. Please use the configuration in configure().', E_USER_DEPRECATED); + $types = is_array($types) ? $types : words($types); $reg = 0; foreach ($types as $type) { - if (isset($this->registered_callbacks[$type])) { - $this->registered_callbacks[$type][] = $cb; - $reg++; + if (isset(static::registered_callbacks()[$type])) { + $found = array_search($cb, self::$config[static::class]['registered_callbacks'][$type], true); + if ($found === false) { + self::$config[static::class]['registered_callbacks'][$type][] = $cb; + $reg++; + } } else { throw new InvalidArgumentException('Unknown callback type: ' . $type); } @@ -2231,15 +2325,17 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate * @throws InvalidArgumentException if the callback type is not known * @return number of unregistered callbacks */ - protected function unregisterCallback($types, $cb) + protected static function unregisterCallback($types, $cb) { + trigger_error(__METHOD__ . ' is deprecated. Please use the configuration in configure().', E_USER_DEPRECATED); + $types = is_array($types) ? $types : words($types); foreach ($types as $type) { - if (isset($this->registered_callbacks[$type])) { - $found = array_search($cb, $this->registered_callbacks[$type], true); + if (isset(static::registered_callbacks()[$type])) { + $found = array_search($cb, self::$config[static::class]['registered_callbacks'][$type], true); if ($found !== false) { $unreg++; - unset($this->registered_callbacks[$type][$found]); + unset(self::$config[static::class]['registered_callbacks'][$type][$found]); } } else { throw new InvalidArgumentException('Unknown callback type: ' . $type); @@ -2284,9 +2380,9 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate */ protected function cbNotificationMapper($cb_type) { - if (isset($this->notification_map[$cb_type])) { + if (isset($this->notification_map()[$cb_type])) { try { - foreach(words($this->notification_map[$cb_type]) as $notification) { + foreach(words($this->notification_map()[$cb_type]) as $notification) { NotificationCenter::postNotification($notification, $this); } } catch (NotificationVetoException $e) { @@ -2303,7 +2399,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate */ protected function cbAfterInitialize($cb_type) { - foreach (array_keys($this->db_fields) as $field) { + foreach (array_keys($this->db_fields()) as $field) { if (is_object($this->content[$field])) { $this->content_db[$field] = clone $this->content[$field]; } else { @@ -2322,7 +2418,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate */ protected function setSerializedValue($field, $value) { - $object_type = $this->serialized_fields[$field]; + $object_type = $this->serialized_fields()[$field]; if (is_null($value) || $value instanceof $object_type) { $this->content[$field] = $value; } else { @@ -2342,7 +2438,7 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate protected function setI18nValue($field, $value) { $meta = ['object_id' => $this->getId(), - 'table' => $this->db_table, + 'table' => $this->db_table(), 'field' => $field]; if ($value instanceof I18NString) { $value->setMetadata($meta); @@ -2353,53 +2449,6 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate return $this->content[$field]; } - /** - * default callback for tables with I18N fields - * @param string $type - * @return bool - */ - protected function cbI18N($type) - { - - if ($type == 'before_store') { - $i18ncontent = []; - foreach (array_keys($this->i18n_fields) as $field) { - if ($this->content[$field] instanceof I18NString) { - $i18ncontent[$field] = $this->content[$field]; - $this->content[$field] = $this->content[$field]->original(); - $this->content_db[$field] = $this->content_db[$field]->original(); - } - } - if (count($i18ncontent)) { - $after_store = function($that, $type, $myself) use ($i18ncontent) { - foreach ($i18ncontent as $field => $one) { - $meta = ['object_id' => $this->getId(), - 'table' => $this->db_table, - 'field' => $field]; - $one->setMetadata($meta); - $one->storeTranslations(); - if (!$this->content[$field] instanceof I18NString) { - $this->content[$field] = $one; - $this->content_db[$field] = clone $one; - } - } - $this->unregisterCallback('after_store', $myself); - }; - $this->registerCallback('after_store', $after_store); - } - - } - - if ($type == 'after_delete') { - foreach (array_keys($this->i18n_fields) as $field) { - if ($this->content[$field] instanceof I18NString) { - $this->content[$field]->removeTranslations(); - } - } - } - return true; - } - /** * Cleans up this object. This essentially reset all relations of * this object and marks them as unused so that the garbage collector may diff --git a/lib/models/StudiengangStgteil.php b/lib/models/StudiengangStgteil.php index 76d01ff4e83..99140220fff 100644 --- a/lib/models/StudiengangStgteil.php +++ b/lib/models/StudiengangStgteil.php @@ -51,12 +51,6 @@ class StudiengangStgteil extends ModuleManagementModel private $stgbez_name; private $stgbez_id; - function __construct($id = null) - { - $this->default_values['position'] = 10000; - parent::__construct($id); - } - /** * Retrieves the StudiengangStgteil and all related data and some * additional fields. diff --git a/lib/models/User.class.php b/lib/models/User.class.php index cbd5e908769..7ce868bf222 100644 --- a/lib/models/User.class.php +++ b/lib/models/User.class.php @@ -232,7 +232,7 @@ class User extends AuthUserMd5 implements Range, PrivacyObject $user->info = new UserInfo(); $user->setData($data); $user->setNew($is_new); - foreach (array_keys($user->db_fields) as $field) { + foreach (array_keys($user->db_fields()) as $field) { $user->content_db[$field] = $user->content[$field]; } $user->info = UserInfo::build($data, $is_new); @@ -305,29 +305,6 @@ class User extends AuthUserMd5 implements Range, PrivacyObject ); } - public static function findDozentenByTermin_id($termin_id) - { - $record = new User(); - $db = DBManager::get(); - $sql = "SELECT `{$record->db_table}`.* - FROM `{$record->db_table}` - INNER JOIN `termin_related_persons` USING (user_id) - WHERE `termin_related_persons`.`range_id` = ? - ORDER BY Nachname, Vorname ASC"; - $statement = $db->prepare($sql); - $statement->execute([$termin_id]); - - $ret = []; - while($row = $statement->fetch(PDO::FETCH_ASSOC)) { - $item = new User(); - $item->setData($row, true); - $item->setNew(false); - - $ret[] = $item; - } - return $ret; - } - /** * Wraps a search parameter in %..% if the parameter itself does not * contain % or _. diff --git a/tests/unit/lib/classes/SimpleOrMapNodbTest.php b/tests/unit/lib/classes/SimpleOrMapNodbTest.php index f6b4e0b0574..e5c333b3be3 100644 --- a/tests/unit/lib/classes/SimpleOrMapNodbTest.php +++ b/tests/unit/lib/classes/SimpleOrMapNodbTest.php @@ -38,7 +38,7 @@ class auth_user_md5 extends SimpleORMap return $this->content['perms'] = mb_strtolower($perm); } - public function registerCallback($types, $cb) + public static function registerCallback($types, $cb) { return parent::registerCallback($types, $cb); } @@ -274,4 +274,18 @@ class SimpleOrMapNodbTest extends \Codeception\Test\Unit $this->assertEquals(3, $a->id); $this->assertEquals('auth_user_md5WillStore', $callback_was_here); } + + + /** + * @depends testConstruct + */ + public function testSerialization($a) + { + $serialized = serialize($a); + $this->assertIsString($serialized); + + $unserialized = unserialize($serialized); + + $this->assertEquals($a->toArray(), $unserialized->toArray()); + } } -- GitLab