xref: /plugin/bez/mdl/Factory.php (revision fe5d6d1ebd253c129098b67fff8cf438a54d8650)
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	public function beginTransaction() {
214        $this->model->sqlite->query('BEGIN TRANSACTION');
215    }
216
217    public function commitTransaction() {
218        $this->model->sqlite->query('COMMIT TRANSACTION');
219    }
220
221    public 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