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