1de02284cSSzymon Olewniczak<?php 2de02284cSSzymon Olewniczak 3de02284cSSzymon Olewniczaknamespace dokuwiki\plugin\bez\mdl; 4de02284cSSzymon Olewniczak 5a0cd8c78SSzymon Olewniczakuse dokuwiki\plugin\bez\meta\PermissionDeniedException; 6a0cd8c78SSzymon Olewniczak 7a0cd8c78SSzymon Olewniczakdefine('BEZ_TABLE_PERMISSION_UNKNOWN', -1); 8a0cd8c78SSzymon Olewniczakdefine('BEZ_TABLE_PERMISSION_SELECT', 0); 9a0cd8c78SSzymon Olewniczakdefine('BEZ_TABLE_PERMISSION_INSERT', 1); 10a0cd8c78SSzymon Olewniczak 11de02284cSSzymon Olewniczakabstract class Factory { 12de02284cSSzymon Olewniczak /** @var Model */ 13de02284cSSzymon Olewniczak protected $model; 14de02284cSSzymon Olewniczak 15a0cd8c78SSzymon Olewniczak public function permission() { 16a0cd8c78SSzymon Olewniczak return BEZ_TABLE_PERMISSION_INSERT; 17a0cd8c78SSzymon Olewniczak } 18e8827d73SSzymon Olewniczak 19de02284cSSzymon Olewniczak protected function filter_field_map($field) { 20ff14b107SSzymon Olewniczak $table = $this->get_table_view(); 21ff14b107SSzymon Olewniczak if (!$table) { 22ff14b107SSzymon Olewniczak $table = $this->get_table_name(); 23de02284cSSzymon Olewniczak } 24de02284cSSzymon Olewniczak 25ff14b107SSzymon Olewniczak return "$table.$field"; 26ff14b107SSzymon Olewniczak } 27ff14b107SSzymon Olewniczak 28ff14b107SSzymon Olewniczak protected function select_query() { 29ff14b107SSzymon Olewniczak $table = $this->get_table_view(); 30ff14b107SSzymon Olewniczak if (!$table) { 31ff14b107SSzymon Olewniczak $table = $this->get_table_name(); 32ff14b107SSzymon Olewniczak } 33ff14b107SSzymon Olewniczak return "SELECT * FROM $table"; 34ff14b107SSzymon Olewniczak } 35ff14b107SSzymon Olewniczak 36ff14b107SSzymon Olewniczak public function get_table_view() { 37ff14b107SSzymon Olewniczak return false; 38ff14b107SSzymon Olewniczak } 39de02284cSSzymon Olewniczak 40de02284cSSzymon Olewniczak protected function build_where($filters=array()) { 41de02284cSSzymon Olewniczak $execute = array(); 42de02284cSSzymon Olewniczak $where_q = array(); 43de02284cSSzymon Olewniczak foreach ($filters as $filter => $value) { 44de02284cSSzymon Olewniczak $field = $this->filter_field_map($filter); 45de02284cSSzymon Olewniczak 46de02284cSSzymon Olewniczak //parser 47de02284cSSzymon Olewniczak $operator = '='; 48de02284cSSzymon Olewniczak $function = ''; 49de02284cSSzymon Olewniczak $function_args = array(); 50de02284cSSzymon Olewniczak if (is_array($value)) { 51de02284cSSzymon Olewniczak $operators = array('!=', '<', '>', '<=', '>=', 'LIKE', 'BETWEEN', 'OR'); 52de02284cSSzymon Olewniczak $functions = array('', 'date'); 53de02284cSSzymon Olewniczak 54de02284cSSzymon Olewniczak $operator = $value[0]; 55de02284cSSzymon Olewniczak $function = isset($value[2]) ? $value[2] : ''; 56de02284cSSzymon Olewniczak 57de02284cSSzymon Olewniczak if (is_array($function)) { 58de02284cSSzymon Olewniczak $function = $function[0]; 59de02284cSSzymon Olewniczak $function_args = array_slice($value[2], 1); 60de02284cSSzymon Olewniczak } 61de02284cSSzymon Olewniczak 62de02284cSSzymon Olewniczak $value = $value[1]; 63de02284cSSzymon Olewniczak 64de02284cSSzymon Olewniczak if (!in_array($operator, $operators)) { 65de02284cSSzymon Olewniczak throw new \Exception('unknown operator: '.$operator); 66de02284cSSzymon Olewniczak } 67de02284cSSzymon Olewniczak 68de02284cSSzymon Olewniczak if (!in_array($function, $functions)) { 69de02284cSSzymon Olewniczak throw new \Exception('unknown function: '.$function); 70de02284cSSzymon Olewniczak } 71de02284cSSzymon Olewniczak } 72de02284cSSzymon Olewniczak 73de02284cSSzymon Olewniczak //builder 74de02284cSSzymon Olewniczak if ($operator === 'BETWEEN') { 75de02284cSSzymon Olewniczak if (count($value) < 2) { 76de02284cSSzymon Olewniczak throw new \Exception('wrong BETWEEN argument. provide two values'); 77de02284cSSzymon Olewniczak } 78de02284cSSzymon Olewniczak if ($function !== '') { 79de02284cSSzymon Olewniczak array_unshift($function_args, $field); 80de02284cSSzymon Olewniczak $where_q[] = "$function(".implode(',', $function_args).") BETWEEN :${filter}_start AND :${filter}_end"; 81de02284cSSzymon Olewniczak } else { 82de02284cSSzymon Olewniczak $where_q[] = "$field BETWEEN :${filter}_start AND :${filter}_end"; 83de02284cSSzymon Olewniczak } 84de02284cSSzymon Olewniczak $execute[":${filter}_start"] = $value[0]; 85de02284cSSzymon Olewniczak $execute[":${filter}_end"] = $value[1]; 86de02284cSSzymon Olewniczak } elseif ($operator === 'OR') { 87de02284cSSzymon Olewniczak if (!is_array($value)) { 88de02284cSSzymon Olewniczak throw new \Exception('$data should be an array'); 89de02284cSSzymon Olewniczak } 90de02284cSSzymon Olewniczak 91de02284cSSzymon Olewniczak $where_array = array(); 92de02284cSSzymon Olewniczak 93de02284cSSzymon Olewniczak foreach ($value as $k => $v) { 94de02284cSSzymon Olewniczak $exec = ":${filter}_$k"; 95de02284cSSzymon Olewniczak $where_array[] = "$field = $exec"; 96de02284cSSzymon Olewniczak $execute[$exec] = $v; 97de02284cSSzymon Olewniczak } 98de02284cSSzymon Olewniczak $where_q[] = '('.implode(' OR ', $where_array).')'; 99de02284cSSzymon Olewniczak 100de02284cSSzymon Olewniczak 101de02284cSSzymon Olewniczak } else { 102de02284cSSzymon Olewniczak if ($function !== '') { 103de02284cSSzymon Olewniczak array_unshift($function_args, $field); 104de02284cSSzymon Olewniczak $where_q[] = "$function(".implode(',', $function_args).") $operator :$filter"; 10553df74e7SSzymon Olewniczak $execute[":$filter"] = $value; 106*a7028d8fSSzymon Olewniczak } elseif ($value === NULL || $value === '') { 10753df74e7SSzymon Olewniczak $where_q[] = "($field IS NULL OR $field = '')"; 108*a7028d8fSSzymon Olewniczak } elseif(is_int($value)) { 109*a7028d8fSSzymon Olewniczak $where_q[] = "$field $operator $value"; 110de02284cSSzymon Olewniczak } else { 111de02284cSSzymon Olewniczak $where_q[] = "$field $operator :$filter"; 112de02284cSSzymon Olewniczak $execute[":$filter"] = $value; 113de02284cSSzymon Olewniczak } 11453df74e7SSzymon Olewniczak 11553df74e7SSzymon Olewniczak } 116de02284cSSzymon Olewniczak } 117de02284cSSzymon Olewniczak 118de02284cSSzymon Olewniczak $where = ''; 119de02284cSSzymon Olewniczak if (count($where_q) > 0) { 120de02284cSSzymon Olewniczak $where = ' WHERE '.implode(' AND ', $where_q); 121de02284cSSzymon Olewniczak } 122de02284cSSzymon Olewniczak return array($where, $execute); 123de02284cSSzymon Olewniczak } 124de02284cSSzymon Olewniczak 125de02284cSSzymon Olewniczak public function __construct(Model $model) { 126de02284cSSzymon Olewniczak $this->model = $model; 127de02284cSSzymon Olewniczak } 128de02284cSSzymon Olewniczak 129038c5d4aSSzymon Olewniczak public function get_all($filters=array(), $orderby='', $defaults=array(), $limit=false) { 130de02284cSSzymon Olewniczak 131de02284cSSzymon Olewniczak list($where_q, $execute) = $this->build_where($filters); 132de02284cSSzymon Olewniczak 133de02284cSSzymon Olewniczak $q = $this->select_query() . $where_q; 134de02284cSSzymon Olewniczak 135fe5d6d1eSSzymon Olewniczak if ($orderby != '') { 136038c5d4aSSzymon Olewniczak if (is_array($orderby)) $orderby = implode(', ', $orderby); 137fe5d6d1eSSzymon Olewniczak $q .= " ORDER BY $orderby"; 138fe5d6d1eSSzymon Olewniczak } 139fe5d6d1eSSzymon Olewniczak 140e8827d73SSzymon Olewniczak if (is_int($limit)) { 141e8827d73SSzymon Olewniczak $q .= " LIMIT $limit"; 142e8827d73SSzymon Olewniczak } 143e8827d73SSzymon Olewniczak 144de02284cSSzymon Olewniczak $sth = $this->model->db->prepare($q); 145de02284cSSzymon Olewniczak 146de02284cSSzymon Olewniczak $sth->setFetchMode(\PDO::FETCH_CLASS, $this->get_object_class_name(), 1478a638198SSzymon Olewniczak array($this->model, $defaults)); 148de02284cSSzymon Olewniczak 149de02284cSSzymon Olewniczak $sth->execute($execute); 150de02284cSSzymon Olewniczak 151de02284cSSzymon Olewniczak return $sth; 152de02284cSSzymon Olewniczak } 153de02284cSSzymon Olewniczak 154de02284cSSzymon Olewniczak public function count($filters=array()) { 155ff14b107SSzymon Olewniczak $table = $this->get_table_view(); 156ff14b107SSzymon Olewniczak if (!$table) { 157ff14b107SSzymon Olewniczak $table = $this->get_table_name(); 158ff14b107SSzymon Olewniczak } 159de02284cSSzymon Olewniczak 160de02284cSSzymon Olewniczak list($where_q, $execute) = $this->build_where($filters); 161de02284cSSzymon Olewniczak 162ff14b107SSzymon Olewniczak $q = "SELECT COUNT(*) FROM $table " . $where_q; 163de02284cSSzymon Olewniczak $sth = $this->model->db->prepare($q); 164de02284cSSzymon Olewniczak $sth->execute($execute); 165de02284cSSzymon Olewniczak 166de02284cSSzymon Olewniczak $count = $sth->fetchColumn(); 167de02284cSSzymon Olewniczak return $count; 168de02284cSSzymon Olewniczak } 169de02284cSSzymon Olewniczak 170b0590826SSzymon Olewniczak public function exists($id) { 171b0590826SSzymon Olewniczak $table = $this->get_table_name(); 172b0590826SSzymon Olewniczak $q = "SELECT id FROM $table WHERE id = ?"; 173b0590826SSzymon Olewniczak 174b0590826SSzymon Olewniczak $sth = $this->model->db->prepare($q); 175b0590826SSzymon Olewniczak $sth->execute(array($id)); 176b0590826SSzymon Olewniczak 177b0590826SSzymon Olewniczak if ($sth->fetch()) { 178b0590826SSzymon Olewniczak return true; 179b0590826SSzymon Olewniczak } 180b0590826SSzymon Olewniczak 181b0590826SSzymon Olewniczak return false; 182b0590826SSzymon Olewniczak } 183b0590826SSzymon Olewniczak 1848a638198SSzymon Olewniczak public function get_one($id, $defaults=array()) { 185ff14b107SSzymon Olewniczak $table = $this->get_table_view(); 186ff14b107SSzymon Olewniczak if (!$table) { 187ff14b107SSzymon Olewniczak $table = $this->get_table_name(); 188ff14b107SSzymon Olewniczak } 189de02284cSSzymon Olewniczak 190ff14b107SSzymon Olewniczak $q = $this->select_query()." WHERE $table.id = ?"; 191de02284cSSzymon Olewniczak 192de02284cSSzymon Olewniczak $sth = $this->model->db->prepare($q); 193de02284cSSzymon Olewniczak $sth->execute(array($id)); 194de02284cSSzymon Olewniczak 195de02284cSSzymon Olewniczak $obj = $sth->fetchObject($this->get_object_class_name(), 1968a638198SSzymon Olewniczak array($this->model, $defaults)); 197de02284cSSzymon Olewniczak 198de02284cSSzymon Olewniczak if ($obj === false) { 199de02284cSSzymon Olewniczak throw new \Exception('there is no '.$this->get_table_name().' with id: '.$id); 200de02284cSSzymon Olewniczak } 201de02284cSSzymon Olewniczak 202de02284cSSzymon Olewniczak return $obj; 203de02284cSSzymon Olewniczak } 204de02284cSSzymon Olewniczak 205de02284cSSzymon Olewniczak public function get_table_name() { 206de02284cSSzymon Olewniczak $class = (new \ReflectionClass($this))->getShortName(); 207de02284cSSzymon Olewniczak return lcfirst(str_replace('Factory', '', $class)); 208de02284cSSzymon Olewniczak } 209de02284cSSzymon Olewniczak 210de02284cSSzymon Olewniczak public function get_object_class_name() { 211de02284cSSzymon Olewniczak $class = (new \ReflectionClass($this))->getName(); 212de02284cSSzymon Olewniczak return str_replace('Factory', '', $class); 213de02284cSSzymon Olewniczak } 214de02284cSSzymon Olewniczak 215de02284cSSzymon Olewniczak public function create_object($defaults=array()) { 216de02284cSSzymon Olewniczak $object_name = $this->get_object_class_name(); 217de02284cSSzymon Olewniczak 218de02284cSSzymon Olewniczak $obj = new $object_name($this->model, $defaults); 219de02284cSSzymon Olewniczak return $obj; 220de02284cSSzymon Olewniczak } 221de02284cSSzymon Olewniczak 2227fbf4c39SSzymon Olewniczak protected function beginTransaction() { 223de02284cSSzymon Olewniczak $this->model->sqlite->query('BEGIN TRANSACTION'); 224de02284cSSzymon Olewniczak } 225de02284cSSzymon Olewniczak 2267fbf4c39SSzymon Olewniczak protected function commitTransaction() { 227de02284cSSzymon Olewniczak $this->model->sqlite->query('COMMIT TRANSACTION'); 228de02284cSSzymon Olewniczak } 229de02284cSSzymon Olewniczak 2307fbf4c39SSzymon Olewniczak protected function rollbackTransaction() { 231de02284cSSzymon Olewniczak $this->model->sqlite->query('ROLLBACK'); 232de02284cSSzymon Olewniczak } 233de02284cSSzymon Olewniczak 23453df74e7SSzymon Olewniczak protected function insert(Entity $obj) { 23553df74e7SSzymon Olewniczak if ($obj->id != NULL) { 23653df74e7SSzymon Olewniczak throw new \Exception('row already saved'); 23753df74e7SSzymon Olewniczak } 23853df74e7SSzymon Olewniczak 239de02284cSSzymon Olewniczak $set = array(); 240de02284cSSzymon Olewniczak $execute = array(); 241de02284cSSzymon Olewniczak $columns = array(); 242de02284cSSzymon Olewniczak foreach ($obj->get_columns() as $column) { 243de02284cSSzymon Olewniczak if ($obj->$column === null) continue; 244de02284cSSzymon Olewniczak $set[] = ":$column"; 245de02284cSSzymon Olewniczak $columns[] = $column; 246de02284cSSzymon Olewniczak $value = $obj->$column; 247de02284cSSzymon Olewniczak if ($value === '') { 248de02284cSSzymon Olewniczak $execute[':'.$column] = null; 249de02284cSSzymon Olewniczak } else { 250de02284cSSzymon Olewniczak $execute[':'.$column] = $value; 251de02284cSSzymon Olewniczak } 252de02284cSSzymon Olewniczak } 253de02284cSSzymon Olewniczak 25453df74e7SSzymon Olewniczak $query = 'INSERT INTO '.$this->get_table_name().' 255de02284cSSzymon Olewniczak ('.implode(',', $columns).') 256de02284cSSzymon Olewniczak VALUES ('.implode(',', $set).')'; 257de02284cSSzymon Olewniczak 258de02284cSSzymon Olewniczak $sth = $this->model->db->prepare($query); 25953df74e7SSzymon Olewniczak $sth->execute($execute); 260de02284cSSzymon Olewniczak 261de02284cSSzymon Olewniczak $reflectionClass = new \ReflectionClass($obj); 262de02284cSSzymon Olewniczak $reflectionProperty = $reflectionClass->getProperty('id'); 263de02284cSSzymon Olewniczak $reflectionProperty->setAccessible(true); 264de02284cSSzymon Olewniczak $reflectionProperty->setValue($obj, $this->model->db->lastInsertId()); 26553df74e7SSzymon Olewniczak 266de02284cSSzymon Olewniczak } 26753df74e7SSzymon Olewniczak 26853df74e7SSzymon Olewniczak protected function update(Entity $obj) { 26953df74e7SSzymon Olewniczak if ($obj->id == NULL) { 27053df74e7SSzymon Olewniczak throw new \Exception('row not inserted'); 27153df74e7SSzymon Olewniczak } 27253df74e7SSzymon Olewniczak 27353df74e7SSzymon Olewniczak $set = array(); 27453df74e7SSzymon Olewniczak $execute = array(':id' => $obj->id); 27553df74e7SSzymon Olewniczak foreach ($obj->get_columns() as $column) { 27653df74e7SSzymon Olewniczak if ($column == 'id') continue; 27753df74e7SSzymon Olewniczak $set[] = "$column=:$column"; 27853df74e7SSzymon Olewniczak $value = $obj->$column; 27953df74e7SSzymon Olewniczak if ($value === '') { 28053df74e7SSzymon Olewniczak $execute[':'.$column] = null; 28153df74e7SSzymon Olewniczak } else { 28253df74e7SSzymon Olewniczak $execute[':'.$column] = $value; 28353df74e7SSzymon Olewniczak } 28453df74e7SSzymon Olewniczak } 28553df74e7SSzymon Olewniczak 28653df74e7SSzymon Olewniczak $query = 'UPDATE ' . $this->get_table_name() . 28753df74e7SSzymon Olewniczak ' SET ' . implode(',', $set) . 28853df74e7SSzymon Olewniczak ' WHERE id=:id'; 28953df74e7SSzymon Olewniczak 29053df74e7SSzymon Olewniczak $sth = $this->model->db->prepare($query); 29153df74e7SSzymon Olewniczak $sth->execute($execute); 292de02284cSSzymon Olewniczak } 293de02284cSSzymon Olewniczak 2948a638198SSzymon Olewniczak public function initial_save(Entity $obj, $data) { 29553df74e7SSzymon Olewniczak $obj->set_data($data); 29653df74e7SSzymon Olewniczak $this->insert($obj); 2978a638198SSzymon Olewniczak } 2988a638198SSzymon Olewniczak 2998a638198SSzymon Olewniczak public function update_save(Entity $obj, $data) { 30053df74e7SSzymon Olewniczak $obj->set_data($data); 30153df74e7SSzymon Olewniczak $this->update($obj); 30253df74e7SSzymon Olewniczak } 30353df74e7SSzymon Olewniczak 30453df74e7SSzymon Olewniczak public function save(Entity $obj) { 3058a638198SSzymon Olewniczak if ($obj->id == NULL) { 30653df74e7SSzymon Olewniczak $this->insert($obj); 30753df74e7SSzymon Olewniczak } else { 30853df74e7SSzymon Olewniczak $this->update($obj); 3098a638198SSzymon Olewniczak } 3108a638198SSzymon Olewniczak } 3118a638198SSzymon Olewniczak 312de02284cSSzymon Olewniczak protected function delete_from_db($id) { 313de02284cSSzymon Olewniczak $q = 'DELETE FROM '.$this->get_table_name().' WHERE id = ?'; 314de02284cSSzymon Olewniczak $sth = $this->model->db->prepare($q); 315de02284cSSzymon Olewniczak $sth->execute(array($id)); 316de02284cSSzymon Olewniczak } 317de02284cSSzymon Olewniczak 318de02284cSSzymon Olewniczak public function delete(Entity $obj) { 319a0cd8c78SSzymon Olewniczak if ($obj->acl_of('id') < BEZ_PERMISSION_DELETE) { 320a0cd8c78SSzymon Olewniczak throw new PermissionDeniedException('cannot delete'); 321a0cd8c78SSzymon Olewniczak } 322de02284cSSzymon Olewniczak $this->delete_from_db($obj->id); 323de02284cSSzymon Olewniczak } 324de02284cSSzymon Olewniczak} 325