xref: /plugin/bez/mdl/Factory.php (revision 53df74e7ac5ae4234aac1fa716a33878a039026f)
1<?php
2
3namespace dokuwiki\plugin\bez\mdl;
4
5abstract class Factory {
6    /** @var Model */
7	protected $model;
8
9	/** @var array of Entity */
10	protected $objects = array();
11
12	protected function filter_field_map($field) {
13        $table = $this->get_table_view();
14        if (!$table) {
15            $table = $this->get_table_name();
16        }
17
18	    return "$table.$field";
19    }
20
21    protected function select_query() {
22	    $table = $this->get_table_view();
23	    if (!$table) {
24	        $table = $this->get_table_name();
25        }
26        return "SELECT * FROM $table";
27    }
28
29    public function get_table_view() {
30	    return false;
31    }
32
33    protected function build_where($filters=array()) {
34		$execute = array();
35		$where_q = array();
36		foreach ($filters as $filter => $value) {
37            $field = $this->filter_field_map($filter);
38
39            //parser
40			$operator = '=';
41            $function = '';
42            $function_args = array();
43			if (is_array($value)) {
44                $operators = array('!=', '<', '>', '<=', '>=', 'LIKE', 'BETWEEN', 'OR');
45                $functions = array('', 'date');
46
47                $operator = $value[0];
48                $function = isset($value[2]) ? $value[2] : '';
49
50                if (is_array($function)) {
51                    $function = $function[0];
52                    $function_args = array_slice($value[2], 1);
53                }
54
55                $value = $value[1];
56
57				if (!in_array($operator, $operators)) {
58                    throw new \Exception('unknown operator: '.$operator);
59                }
60
61                if (!in_array($function, $functions)) {
62                    throw new \Exception('unknown function: '.$function);
63                }
64			}
65
66            //builder
67            if ($operator === 'BETWEEN') {
68                if (count($value) < 2) {
69                    throw new \Exception('wrong BETWEEN argument. provide two values');
70                }
71                if ($function !== '') {
72                    array_unshift($function_args, $field);
73                    $where_q[] = "$function(".implode(',', $function_args).") BETWEEN :${filter}_start AND :${filter}_end";
74                } else {
75                    $where_q[] = "$field BETWEEN :${filter}_start AND :${filter}_end";
76                }
77                $execute[":${filter}_start"] = $value[0];
78                $execute[":${filter}_end"] = $value[1];
79            } elseif ($operator === 'OR') {
80                if (!is_array($value)) {
81                    throw new \Exception('$data should be an array');
82                }
83
84                $where_array = array();
85
86                foreach ($value as $k => $v) {
87                    $exec = ":${filter}_$k";
88                    $where_array[] = "$field = $exec";
89                    $execute[$exec] = $v;
90                }
91                $where_q[] = '('.implode('OR', $where_array).')';
92
93
94            } else {
95                if ($function !== '') {
96                    array_unshift($function_args, $field);
97                    $where_q[] = "$function(".implode(',', $function_args).") $operator :$filter";
98                    $execute[":$filter"] = $value;
99                } elseif (empty($value)) {
100                    $where_q[] = "($field IS NULL OR $field = '')";
101                } else {
102                    $where_q[] = "$field $operator :$filter";
103                    $execute[":$filter"] = $value;
104                }
105
106            }
107		}
108
109		$where = '';
110		if (count($where_q) > 0) {
111			$where = ' WHERE '.implode(' AND ', $where_q);
112		}
113		return array($where, $execute);
114	}
115
116	public function __construct(Model $model) {
117		$this->model = $model;
118	}
119
120	public function acl_static($field) {
121        return $this->model->acl->check_static_field($this->get_table_name(), $field);
122    }
123
124    //chek acl
125    public function get_all($filters=array(), $orderby='', $desc=true, $defaults=array(), $limit=false) {
126
127        list($where_q, $execute) = $this->build_where($filters);
128
129		$q = $this->select_query() . $where_q;
130
131		if ($orderby != '') {
132		    $fields = call_user_func(array($this->get_object_class_name(), 'get_columns'));
133		    if (!in_array($orderby, $fields)) {
134		        throw new \Exception('unknown field '.$orderby);
135            }
136		    $q .= " ORDER BY $orderby";
137		    if ($desc) {
138		        $q .= " DESC";
139            }
140        }
141
142        if (is_int($limit)) {
143		    $q .= " LIMIT $limit";
144        }
145
146		$sth = $this->model->db->prepare($q);
147
148        $sth->setFetchMode(\PDO::FETCH_CLASS, $this->get_object_class_name(),
149                           array($this->model, $defaults));
150
151		$sth->execute($execute);
152
153		return $sth;
154    }
155
156    public function count($filters=array()) {
157        $table = $this->get_table_view();
158        if (!$table) {
159            $table = $this->get_table_name();
160        }
161        if ($this->acl_static('id') < BEZ_PERMISSION_VIEW) {
162            throw new PermissionDeniedException();
163        }
164
165        list($where_q, $execute) = $this->build_where($filters);
166
167        $q = "SELECT COUNT(*) FROM $table " . $where_q;
168        $sth = $this->model->db->prepare($q);
169        $sth->execute($execute);
170
171        $count = $sth->fetchColumn();
172        return $count;
173    }
174
175    public function get_one($id, $defaults=array()) {
176        $table = $this->get_table_view();
177        if (!$table) {
178            $table = $this->get_table_name();
179        }
180
181		$q = $this->select_query()." WHERE $table.id = ?";
182
183		$sth = $this->model->db->prepare($q);
184		$sth->execute(array($id));
185
186		$obj = $sth->fetchObject($this->get_object_class_name(),
187					array($this->model, $defaults));
188
189        if ($obj === false) {
190            throw new \Exception('there is no '.$this->get_table_name().' with id: '.$id);
191        }
192
193		return $obj;
194	}
195
196	public function get_table_name() {
197        $class = (new \ReflectionClass($this))->getShortName();
198        return lcfirst(str_replace('Factory', '', $class));
199	}
200
201    public function get_object_class_name() {
202        $class = (new \ReflectionClass($this))->getName();
203        return str_replace('Factory', '', $class);
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	protected function insert(Entity $obj) {
226        if ($obj->id != NULL) {
227            throw new \Exception('row already saved');
228        }
229
230        $set = array();
231        $execute = array();
232        $columns = array();
233        foreach ($obj->get_columns() as $column) {
234            if ($obj->$column === null) continue;
235            $set[] = ":$column";
236            $columns[] = $column;
237            $value = $obj->$column;
238            if ($value === '') {
239                $execute[':'.$column] = null;
240            } else {
241                $execute[':'.$column] = $value;
242            }
243        }
244
245        $query = 'INSERT INTO '.$this->get_table_name().'
246							('.implode(',', $columns).')
247							VALUES ('.implode(',', $set).')';
248
249        $sth = $this->model->db->prepare($query);
250        $sth->execute($execute);
251
252        $reflectionClass = new \ReflectionClass($obj);
253        $reflectionProperty = $reflectionClass->getProperty('id');
254        $reflectionProperty->setAccessible(true);
255        $reflectionProperty->setValue($obj, $this->model->db->lastInsertId());
256
257    }
258
259    protected function update(Entity $obj) {
260        if ($obj->id == NULL) {
261            throw new \Exception('row not inserted');
262        }
263
264        $set = array();
265        $execute = array(':id' => $obj->id);
266        foreach ($obj->get_columns() as $column) {
267            if ($column == 'id') continue;
268            $set[] = "$column=:$column";
269            $value = $obj->$column;
270            if ($value === '') {
271                $execute[':'.$column] = null;
272            } else {
273                $execute[':'.$column] = $value;
274            }
275        }
276
277        $query = 'UPDATE ' . $this->get_table_name() .
278                    ' SET ' . implode(',', $set) .
279                    ' WHERE id=:id';
280
281        $sth = $this->model->db->prepare($query);
282        $sth->execute($execute);
283    }
284
285    public function initial_save(Entity $obj, $data) {
286	    $obj->set_data($data);
287	    $this->insert($obj);
288    }
289
290    public function update_save(Entity $obj, $data) {
291	    $obj->set_data($data);
292	    $this->update($obj);
293    }
294
295    public function save(Entity $obj) {
296	    if ($obj->id == NULL) {
297	        $this->insert($obj);
298        } else {
299	        $this->update($obj);
300        }
301    }
302
303	protected function delete_from_db($id) {
304		$q = 'DELETE FROM '.$this->get_table_name().' WHERE id = ?';
305		$sth = $this->model->db->prepare($q);
306		$sth->execute(array($id));
307	}
308
309	public function delete(Entity $obj) {
310        $this->model->acl->can($obj, 'id', BEZ_PERMISSION_DELETE);
311		$this->delete_from_db($obj->id);
312	}
313}
314