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 $where_q[] = "$field $operator :$filter"; 82 } 83 $execute[":$filter"] = $value; 84 } 85 } 86 87 $where = ''; 88 if (count($where_q) > 0) { 89 $where = ' WHERE '.implode(' AND ', $where_q); 90 } 91 return array($where, $execute); 92 } 93 94 public function __construct(Model $model) { 95 $this->model = $model; 96 } 97 98 public function acl_static($field) { 99 return $this->model->acl->check_static_field($this->get_table_name(), $field); 100 } 101 102 //chek acl 103 public function get_all($filters=array(), $orderby='', $desc=true) { 104// $dummy = $this->get_dummy_object(); 105// if ($dummy->acl_of('id') < BEZ_PERMISSION_VIEW) { 106// throw new PermissionDeniedException(); 107// } 108// 109// if ($this->select_query === NULL) { 110// throw new \Exception('no select query defined'); 111// } 112 113 list($where_q, $execute) = $this->build_where($filters); 114 115 $q = $this->select_query() . $where_q; 116 117 if ($orderby != '') { 118 $fields = call_user_func(array($this->get_object_class_name(), 'get_columns')); 119 if (!in_array($orderby, $fields)) { 120 throw new \Exception('unknown field '.$orderby); 121 } 122 $q .= " ORDER BY $orderby"; 123 if ($desc) { 124 $q .= " DESC"; 125 } 126 } 127 128 $sth = $this->model->db->prepare($q); 129 130 $sth->setFetchMode(\PDO::FETCH_CLASS, $this->get_object_class_name(), 131 array($this->model)); 132 133 $sth->execute($execute); 134 135 return $sth; 136 } 137 138 public function count($filters=array()) { 139// $dummy = $this->get_dummy_object(); 140// if ($dummy->acl_of('id') < BEZ_PERMISSION_VIEW) { 141// throw new PermissionDeniedException(); 142// } 143 144 if ($this->acl_static('id') < BEZ_PERMISSION_VIEW) { 145 throw new PermissionDeniedException(); 146 } 147 148 list($where_q, $execute) = $this->build_where($filters); 149 150 $q = 'SELECT COUNT(*) FROM ' . $this->get_table_name() . ' ' . $where_q; 151 $sth = $this->model->db->prepare($q); 152 $sth->execute($execute); 153 154 $count = $sth->fetchColumn(); 155 return $count; 156 } 157 158 public function get_one($id) { 159// if ($this->select_query === NULL) { 160// throw new \Exception('no select query defined'); 161// } 162 163 $q = $this->select_query().' WHERE '.$this->get_table_name().'.id = ?'; 164 165 $sth = $this->model->db->prepare($q); 166 $sth->execute(array($id)); 167 168 $obj = $sth->fetchObject($this->get_object_class_name(), 169 array($this->model)); 170 171 if ($obj === false) { 172 throw new \Exception('there is no '.$this->get_table_name().' with id: '.$id); 173 } 174 175 return $obj; 176 } 177 178 public function get_table_name() { 179 $class = (new \ReflectionClass($this))->getShortName(); 180 return lcfirst(str_replace('Factory', '', $class)); 181 } 182 183 public function get_object_class_name() { 184 $class = (new \ReflectionClass($this))->getName(); 185 return str_replace('Factory', '', $class); 186 } 187// 188// public function get_table_singular() { 189// $table = $this->get_table_name(); 190// $singular = substr($table, 0, -1); 191// return $singular; 192// } 193// 194// private function get_singular_object_name() { 195// return ucfirst($this->get_table_singular()); 196// } 197// 198// private function get_object_class_name() { 199// return 'BEZ_mdl_'.$this->get_singular_object_name(); 200// } 201 202// private function get_dummy_object_class_name() { 203// return 'BEZ_mdl_Dummy_'.$this->get_singular_object_name(); 204// } 205 206 public function create_object($defaults=array()) { 207 $object_name = $this->get_object_class_name(); 208 209 $obj = new $object_name($this->model, $defaults); 210 return $obj; 211 } 212 213 protected function beginTransaction() { 214 $this->model->sqlite->query('BEGIN TRANSACTION'); 215 } 216 217 protected function commitTransaction() { 218 $this->model->sqlite->query('COMMIT TRANSACTION'); 219 } 220 221 protected function rollbackTransaction() { 222 $this->model->sqlite->query('ROLLBACK'); 223 } 224 225// public function get_dummy_object() { 226// if ($this->dummy_object === NULL) { 227// $dummy_object_name = $this->get_dummy_object_class_name(); 228// $this->dummy_object = new $dummy_object_name($this->model); 229// } 230// return $this->dummy_object; 231// } 232 233 public function save(Entity $obj) { 234 //if user can change id, he can modify record 235 //$this->model->acl->can_change($obj, 'id'); 236 237 $set = array(); 238 $execute = array(); 239 $columns = array(); 240 foreach ($obj->get_columns() as $column) { 241 if ($obj->$column === null) continue; 242 //id is special -> when null we insert new row 243// if ($column == 'id' && $obj->id == NULL) continue; 244 245// if ($obj->$column === null) { 246// throw new \Exception('cannot save object becouse it has uninitialized parameter: '.$column); 247// } 248 $set[] = ":$column"; 249 $columns[] = $column; 250 $value = $obj->$column; 251 if ($value === '') { 252 $execute[':'.$column] = null; 253 } else { 254 $execute[':'.$column] = $value; 255 } 256 } 257 258 $query = 'REPLACE INTO '.$this->get_table_name().' 259 ('.implode(',', $columns).') 260 VALUES ('.implode(',', $set).')'; 261 262 $sth = $this->model->db->prepare($query); 263 $sth->execute($execute); 264 265 //new object is created 266 if ($obj->id === NULL) { 267 $reflectionClass = new \ReflectionClass($obj); 268 $reflectionProperty = $reflectionClass->getProperty('id'); 269 $reflectionProperty->setAccessible(true); 270 $reflectionProperty->setValue($obj, $this->model->db->lastInsertId()); 271 } 272// $id = $this->model->db->lastInsertId(); 273// $obj->set_id($id); 274 275// } 276 277// return $id; 278 } 279 280 protected function delete_from_db($id) { 281 $q = 'DELETE FROM '.$this->get_table_name().' WHERE id = ?'; 282 $sth = $this->model->db->prepare($q); 283 $sth->execute(array($id)); 284 } 285 286 public function delete(Entity $obj) { 287 //if user can change id, he can delete record 288 $this->model->acl->can_change($obj, 'id'); 289 $this->delete_from_db($obj->id); 290 } 291} 292