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