1de02284cSSzymon Olewniczak<?php 2de02284cSSzymon Olewniczak 3de02284cSSzymon Olewniczaknamespace dokuwiki\plugin\bez\mdl; 4de02284cSSzymon Olewniczak 5de02284cSSzymon Olewniczakabstract class Factory { 6de02284cSSzymon Olewniczak /** @var Model */ 7de02284cSSzymon Olewniczak protected $model; 8de02284cSSzymon Olewniczak 9e8827d73SSzymon Olewniczak /** @var array of Entity */ 10e8827d73SSzymon Olewniczak protected $objects = array(); 11e8827d73SSzymon Olewniczak 12de02284cSSzymon Olewniczak protected function filter_field_map($field) { 13*ff14b107SSzymon Olewniczak $table = $this->get_table_view(); 14*ff14b107SSzymon Olewniczak if (!$table) { 15*ff14b107SSzymon Olewniczak $table = $this->get_table_name(); 16de02284cSSzymon Olewniczak } 17de02284cSSzymon Olewniczak 18*ff14b107SSzymon Olewniczak return "$table.$field"; 19*ff14b107SSzymon Olewniczak } 20*ff14b107SSzymon Olewniczak 21*ff14b107SSzymon Olewniczak protected function select_query() { 22*ff14b107SSzymon Olewniczak $table = $this->get_table_view(); 23*ff14b107SSzymon Olewniczak if (!$table) { 24*ff14b107SSzymon Olewniczak $table = $this->get_table_name(); 25*ff14b107SSzymon Olewniczak } 26*ff14b107SSzymon Olewniczak return "SELECT * FROM $table"; 27*ff14b107SSzymon Olewniczak } 28*ff14b107SSzymon Olewniczak 29*ff14b107SSzymon Olewniczak public function get_table_view() { 30*ff14b107SSzymon Olewniczak return false; 31*ff14b107SSzymon Olewniczak } 32de02284cSSzymon Olewniczak 33de02284cSSzymon Olewniczak protected function build_where($filters=array()) { 34de02284cSSzymon Olewniczak $execute = array(); 35de02284cSSzymon Olewniczak $where_q = array(); 36de02284cSSzymon Olewniczak foreach ($filters as $filter => $value) { 37de02284cSSzymon Olewniczak $field = $this->filter_field_map($filter); 38de02284cSSzymon Olewniczak 39de02284cSSzymon Olewniczak //parser 40de02284cSSzymon Olewniczak $operator = '='; 41de02284cSSzymon Olewniczak $function = ''; 42de02284cSSzymon Olewniczak $function_args = array(); 43de02284cSSzymon Olewniczak if (is_array($value)) { 44de02284cSSzymon Olewniczak $operators = array('!=', '<', '>', '<=', '>=', 'LIKE', 'BETWEEN', 'OR'); 45de02284cSSzymon Olewniczak $functions = array('', 'date'); 46de02284cSSzymon Olewniczak 47de02284cSSzymon Olewniczak $operator = $value[0]; 48de02284cSSzymon Olewniczak $function = isset($value[2]) ? $value[2] : ''; 49de02284cSSzymon Olewniczak 50de02284cSSzymon Olewniczak if (is_array($function)) { 51de02284cSSzymon Olewniczak $function = $function[0]; 52de02284cSSzymon Olewniczak $function_args = array_slice($value[2], 1); 53de02284cSSzymon Olewniczak } 54de02284cSSzymon Olewniczak 55de02284cSSzymon Olewniczak $value = $value[1]; 56de02284cSSzymon Olewniczak 57de02284cSSzymon Olewniczak if (!in_array($operator, $operators)) { 58de02284cSSzymon Olewniczak throw new \Exception('unknown operator: '.$operator); 59de02284cSSzymon Olewniczak } 60de02284cSSzymon Olewniczak 61de02284cSSzymon Olewniczak if (!in_array($function, $functions)) { 62de02284cSSzymon Olewniczak throw new \Exception('unknown function: '.$function); 63de02284cSSzymon Olewniczak } 64de02284cSSzymon Olewniczak } 65de02284cSSzymon Olewniczak 66de02284cSSzymon Olewniczak //builder 67de02284cSSzymon Olewniczak if ($operator === 'BETWEEN') { 68de02284cSSzymon Olewniczak if (count($value) < 2) { 69de02284cSSzymon Olewniczak throw new \Exception('wrong BETWEEN argument. provide two values'); 70de02284cSSzymon Olewniczak } 71de02284cSSzymon Olewniczak if ($function !== '') { 72de02284cSSzymon Olewniczak array_unshift($function_args, $field); 73de02284cSSzymon Olewniczak $where_q[] = "$function(".implode(',', $function_args).") BETWEEN :${filter}_start AND :${filter}_end"; 74de02284cSSzymon Olewniczak } else { 75de02284cSSzymon Olewniczak $where_q[] = "$field BETWEEN :${filter}_start AND :${filter}_end"; 76de02284cSSzymon Olewniczak } 77de02284cSSzymon Olewniczak $execute[":${filter}_start"] = $value[0]; 78de02284cSSzymon Olewniczak $execute[":${filter}_end"] = $value[1]; 79de02284cSSzymon Olewniczak } elseif ($operator === 'OR') { 80de02284cSSzymon Olewniczak if (!is_array($value)) { 81de02284cSSzymon Olewniczak throw new \Exception('$data should be an array'); 82de02284cSSzymon Olewniczak } 83de02284cSSzymon Olewniczak 84de02284cSSzymon Olewniczak $where_array = array(); 85de02284cSSzymon Olewniczak 86de02284cSSzymon Olewniczak foreach ($value as $k => $v) { 87de02284cSSzymon Olewniczak $exec = ":${filter}_$k"; 88de02284cSSzymon Olewniczak $where_array[] = "$field = $exec"; 89de02284cSSzymon Olewniczak $execute[$exec] = $v; 90de02284cSSzymon Olewniczak } 91de02284cSSzymon Olewniczak $where_q[] = '('.implode('OR', $where_array).')'; 92de02284cSSzymon Olewniczak 93de02284cSSzymon Olewniczak 94de02284cSSzymon Olewniczak } else { 95de02284cSSzymon Olewniczak if ($function !== '') { 96de02284cSSzymon Olewniczak array_unshift($function_args, $field); 97de02284cSSzymon Olewniczak $where_q[] = "$function(".implode(',', $function_args).") $operator :$filter"; 98de02284cSSzymon Olewniczak } else { 99de02284cSSzymon Olewniczak $where_q[] = "$field $operator :$filter"; 100de02284cSSzymon Olewniczak } 101de02284cSSzymon Olewniczak $execute[":$filter"] = $value; 102de02284cSSzymon Olewniczak } 103de02284cSSzymon Olewniczak } 104de02284cSSzymon Olewniczak 105de02284cSSzymon Olewniczak $where = ''; 106de02284cSSzymon Olewniczak if (count($where_q) > 0) { 107de02284cSSzymon Olewniczak $where = ' WHERE '.implode(' AND ', $where_q); 108de02284cSSzymon Olewniczak } 109de02284cSSzymon Olewniczak return array($where, $execute); 110de02284cSSzymon Olewniczak } 111de02284cSSzymon Olewniczak 112de02284cSSzymon Olewniczak public function __construct(Model $model) { 113de02284cSSzymon Olewniczak $this->model = $model; 114de02284cSSzymon Olewniczak } 115de02284cSSzymon Olewniczak 116de02284cSSzymon Olewniczak public function acl_static($field) { 117de02284cSSzymon Olewniczak return $this->model->acl->check_static_field($this->get_table_name(), $field); 118de02284cSSzymon Olewniczak } 119de02284cSSzymon Olewniczak 120de02284cSSzymon Olewniczak //chek acl 121e8827d73SSzymon Olewniczak public function get_all($filters=array(), $orderby='', $desc=true, $defaults=array(), $limit=false) { 122de02284cSSzymon Olewniczak 123de02284cSSzymon Olewniczak list($where_q, $execute) = $this->build_where($filters); 124de02284cSSzymon Olewniczak 125de02284cSSzymon Olewniczak $q = $this->select_query() . $where_q; 126de02284cSSzymon Olewniczak 127fe5d6d1eSSzymon Olewniczak if ($orderby != '') { 128fe5d6d1eSSzymon Olewniczak $fields = call_user_func(array($this->get_object_class_name(), 'get_columns')); 129fe5d6d1eSSzymon Olewniczak if (!in_array($orderby, $fields)) { 130fe5d6d1eSSzymon Olewniczak throw new \Exception('unknown field '.$orderby); 131fe5d6d1eSSzymon Olewniczak } 132fe5d6d1eSSzymon Olewniczak $q .= " ORDER BY $orderby"; 133fe5d6d1eSSzymon Olewniczak if ($desc) { 134fe5d6d1eSSzymon Olewniczak $q .= " DESC"; 135fe5d6d1eSSzymon Olewniczak } 136fe5d6d1eSSzymon Olewniczak } 137fe5d6d1eSSzymon Olewniczak 138e8827d73SSzymon Olewniczak if (is_int($limit)) { 139e8827d73SSzymon Olewniczak $q .= " LIMIT $limit"; 140e8827d73SSzymon Olewniczak } 141e8827d73SSzymon Olewniczak 142de02284cSSzymon Olewniczak $sth = $this->model->db->prepare($q); 143de02284cSSzymon Olewniczak 144de02284cSSzymon Olewniczak $sth->setFetchMode(\PDO::FETCH_CLASS, $this->get_object_class_name(), 1458a638198SSzymon Olewniczak array($this->model, $defaults)); 146de02284cSSzymon Olewniczak 147de02284cSSzymon Olewniczak $sth->execute($execute); 148de02284cSSzymon Olewniczak 149de02284cSSzymon Olewniczak return $sth; 150de02284cSSzymon Olewniczak } 151de02284cSSzymon Olewniczak 152de02284cSSzymon Olewniczak public function count($filters=array()) { 153*ff14b107SSzymon Olewniczak $table = $this->get_table_view(); 154*ff14b107SSzymon Olewniczak if (!$table) { 155*ff14b107SSzymon Olewniczak $table = $this->get_table_name(); 156*ff14b107SSzymon Olewniczak } 157de02284cSSzymon Olewniczak if ($this->acl_static('id') < BEZ_PERMISSION_VIEW) { 158de02284cSSzymon Olewniczak throw new PermissionDeniedException(); 159de02284cSSzymon Olewniczak } 160de02284cSSzymon Olewniczak 161de02284cSSzymon Olewniczak list($where_q, $execute) = $this->build_where($filters); 162de02284cSSzymon Olewniczak 163*ff14b107SSzymon Olewniczak $q = "SELECT COUNT(*) FROM $table " . $where_q; 164de02284cSSzymon Olewniczak $sth = $this->model->db->prepare($q); 165de02284cSSzymon Olewniczak $sth->execute($execute); 166de02284cSSzymon Olewniczak 167de02284cSSzymon Olewniczak $count = $sth->fetchColumn(); 168de02284cSSzymon Olewniczak return $count; 169de02284cSSzymon Olewniczak } 170de02284cSSzymon Olewniczak 1718a638198SSzymon Olewniczak public function get_one($id, $defaults=array()) { 172*ff14b107SSzymon Olewniczak $table = $this->get_table_view(); 173*ff14b107SSzymon Olewniczak if (!$table) { 174*ff14b107SSzymon Olewniczak $table = $this->get_table_name(); 175*ff14b107SSzymon Olewniczak } 176de02284cSSzymon Olewniczak 177*ff14b107SSzymon Olewniczak $q = $this->select_query()." WHERE $table.id = ?"; 178de02284cSSzymon Olewniczak 179de02284cSSzymon Olewniczak $sth = $this->model->db->prepare($q); 180de02284cSSzymon Olewniczak $sth->execute(array($id)); 181de02284cSSzymon Olewniczak 182de02284cSSzymon Olewniczak $obj = $sth->fetchObject($this->get_object_class_name(), 1838a638198SSzymon Olewniczak array($this->model, $defaults)); 184de02284cSSzymon Olewniczak 185de02284cSSzymon Olewniczak if ($obj === false) { 186de02284cSSzymon Olewniczak throw new \Exception('there is no '.$this->get_table_name().' with id: '.$id); 187de02284cSSzymon Olewniczak } 188de02284cSSzymon Olewniczak 189de02284cSSzymon Olewniczak return $obj; 190de02284cSSzymon Olewniczak } 191de02284cSSzymon Olewniczak 192de02284cSSzymon Olewniczak public function get_table_name() { 193de02284cSSzymon Olewniczak $class = (new \ReflectionClass($this))->getShortName(); 194de02284cSSzymon Olewniczak return lcfirst(str_replace('Factory', '', $class)); 195de02284cSSzymon Olewniczak } 196de02284cSSzymon Olewniczak 197de02284cSSzymon Olewniczak public function get_object_class_name() { 198de02284cSSzymon Olewniczak $class = (new \ReflectionClass($this))->getName(); 199de02284cSSzymon Olewniczak return str_replace('Factory', '', $class); 200de02284cSSzymon Olewniczak } 201de02284cSSzymon Olewniczak// 202de02284cSSzymon Olewniczak// public function get_table_singular() { 203de02284cSSzymon Olewniczak// $table = $this->get_table_name(); 204de02284cSSzymon Olewniczak// $singular = substr($table, 0, -1); 205de02284cSSzymon Olewniczak// return $singular; 206de02284cSSzymon Olewniczak// } 207de02284cSSzymon Olewniczak// 208de02284cSSzymon Olewniczak// private function get_singular_object_name() { 209de02284cSSzymon Olewniczak// return ucfirst($this->get_table_singular()); 210de02284cSSzymon Olewniczak// } 211de02284cSSzymon Olewniczak// 212de02284cSSzymon Olewniczak// private function get_object_class_name() { 213de02284cSSzymon Olewniczak// return 'BEZ_mdl_'.$this->get_singular_object_name(); 214de02284cSSzymon Olewniczak// } 215de02284cSSzymon Olewniczak 216de02284cSSzymon Olewniczak// private function get_dummy_object_class_name() { 217de02284cSSzymon Olewniczak// return 'BEZ_mdl_Dummy_'.$this->get_singular_object_name(); 218de02284cSSzymon Olewniczak// } 219de02284cSSzymon Olewniczak 220de02284cSSzymon Olewniczak public function create_object($defaults=array()) { 221de02284cSSzymon Olewniczak $object_name = $this->get_object_class_name(); 222de02284cSSzymon Olewniczak 223de02284cSSzymon Olewniczak $obj = new $object_name($this->model, $defaults); 224de02284cSSzymon Olewniczak return $obj; 225de02284cSSzymon Olewniczak } 226de02284cSSzymon Olewniczak 2277fbf4c39SSzymon Olewniczak protected function beginTransaction() { 228de02284cSSzymon Olewniczak $this->model->sqlite->query('BEGIN TRANSACTION'); 229de02284cSSzymon Olewniczak } 230de02284cSSzymon Olewniczak 2317fbf4c39SSzymon Olewniczak protected function commitTransaction() { 232de02284cSSzymon Olewniczak $this->model->sqlite->query('COMMIT TRANSACTION'); 233de02284cSSzymon Olewniczak } 234de02284cSSzymon Olewniczak 2357fbf4c39SSzymon Olewniczak protected function rollbackTransaction() { 236de02284cSSzymon Olewniczak $this->model->sqlite->query('ROLLBACK'); 237de02284cSSzymon Olewniczak } 238de02284cSSzymon Olewniczak 239de02284cSSzymon Olewniczak// public function get_dummy_object() { 240de02284cSSzymon Olewniczak// if ($this->dummy_object === NULL) { 241de02284cSSzymon Olewniczak// $dummy_object_name = $this->get_dummy_object_class_name(); 242de02284cSSzymon Olewniczak// $this->dummy_object = new $dummy_object_name($this->model); 243de02284cSSzymon Olewniczak// } 244de02284cSSzymon Olewniczak// return $this->dummy_object; 245de02284cSSzymon Olewniczak// } 246de02284cSSzymon Olewniczak 247de02284cSSzymon Olewniczak public function save(Entity $obj) { 248de02284cSSzymon Olewniczak //if user can change id, he can modify record 249de02284cSSzymon Olewniczak //$this->model->acl->can_change($obj, 'id'); 250de02284cSSzymon Olewniczak 251de02284cSSzymon Olewniczak $set = array(); 252de02284cSSzymon Olewniczak $execute = array(); 253de02284cSSzymon Olewniczak $columns = array(); 254de02284cSSzymon Olewniczak foreach ($obj->get_columns() as $column) { 255de02284cSSzymon Olewniczak if ($obj->$column === null) continue; 256de02284cSSzymon Olewniczak //id is special -> when null we insert new row 257de02284cSSzymon Olewniczak// if ($column == 'id' && $obj->id == NULL) continue; 258de02284cSSzymon Olewniczak 259de02284cSSzymon Olewniczak// if ($obj->$column === null) { 260de02284cSSzymon Olewniczak// throw new \Exception('cannot save object becouse it has uninitialized parameter: '.$column); 261de02284cSSzymon Olewniczak// } 262de02284cSSzymon Olewniczak $set[] = ":$column"; 263de02284cSSzymon Olewniczak $columns[] = $column; 264de02284cSSzymon Olewniczak $value = $obj->$column; 265de02284cSSzymon Olewniczak if ($value === '') { 266de02284cSSzymon Olewniczak $execute[':'.$column] = null; 267de02284cSSzymon Olewniczak } else { 268de02284cSSzymon Olewniczak $execute[':'.$column] = $value; 269de02284cSSzymon Olewniczak } 270de02284cSSzymon Olewniczak } 271de02284cSSzymon Olewniczak 272de02284cSSzymon Olewniczak $query = 'REPLACE INTO '.$this->get_table_name().' 273de02284cSSzymon Olewniczak ('.implode(',', $columns).') 274de02284cSSzymon Olewniczak VALUES ('.implode(',', $set).')'; 275de02284cSSzymon Olewniczak 276de02284cSSzymon Olewniczak $sth = $this->model->db->prepare($query); 2778a638198SSzymon Olewniczak $res = $sth->execute($execute); 278de02284cSSzymon Olewniczak 279de02284cSSzymon Olewniczak //new object is created 280de02284cSSzymon Olewniczak if ($obj->id === NULL) { 281de02284cSSzymon Olewniczak $reflectionClass = new \ReflectionClass($obj); 282de02284cSSzymon Olewniczak $reflectionProperty = $reflectionClass->getProperty('id'); 283de02284cSSzymon Olewniczak $reflectionProperty->setAccessible(true); 284de02284cSSzymon Olewniczak $reflectionProperty->setValue($obj, $this->model->db->lastInsertId()); 285de02284cSSzymon Olewniczak } 286de02284cSSzymon Olewniczak// $id = $this->model->db->lastInsertId(); 287de02284cSSzymon Olewniczak// $obj->set_id($id); 288de02284cSSzymon Olewniczak 289de02284cSSzymon Olewniczak// } 290de02284cSSzymon Olewniczak 291de02284cSSzymon Olewniczak// return $id; 292de02284cSSzymon Olewniczak } 293de02284cSSzymon Olewniczak 2948a638198SSzymon Olewniczak public function initial_save(Entity $obj, $data) { 2958a638198SSzymon Olewniczak if ($obj->id != NULL) { 2968a638198SSzymon Olewniczak throw new \Exception('row already saved. use update_save'); 2978a638198SSzymon Olewniczak } 2988a638198SSzymon Olewniczak } 2998a638198SSzymon Olewniczak 3008a638198SSzymon Olewniczak public function update_save(Entity $obj, $data) { 3018a638198SSzymon Olewniczak if ($obj->id == NULL) { 3028a638198SSzymon Olewniczak throw new \Exception('row not saved. use initial_save()'); 3038a638198SSzymon Olewniczak } 3048a638198SSzymon Olewniczak } 3058a638198SSzymon Olewniczak 306de02284cSSzymon Olewniczak protected function delete_from_db($id) { 307de02284cSSzymon Olewniczak $q = 'DELETE FROM '.$this->get_table_name().' WHERE id = ?'; 308de02284cSSzymon Olewniczak $sth = $this->model->db->prepare($q); 309de02284cSSzymon Olewniczak $sth->execute(array($id)); 310de02284cSSzymon Olewniczak } 311de02284cSSzymon Olewniczak 312de02284cSSzymon Olewniczak public function delete(Entity $obj) { 3138a638198SSzymon Olewniczak $this->model->acl->can($obj, 'id', BEZ_PERMISSION_DELETE); 314de02284cSSzymon Olewniczak $this->delete_from_db($obj->id); 315de02284cSSzymon Olewniczak } 316de02284cSSzymon Olewniczak} 317