xref: /plugin/bez/mdl/Factory.php (revision 16c7b168a60daa2c9b9ddcfa51e05d123a2a17dc)
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                } else {
99                    $where_q[] = "$field $operator :$filter";
100                }
101                $execute[":$filter"] = $value;
102            }
103		}
104
105		$where = '';
106		if (count($where_q) > 0) {
107			$where = ' WHERE '.implode(' AND ', $where_q);
108		}
109		return array($where, $execute);
110	}
111
112	public function __construct(Model $model) {
113		$this->model = $model;
114	}
115
116	public function acl_static($field) {
117        return $this->model->acl->check_static_field($this->get_table_name(), $field);
118    }
119
120    //chek acl
121    public function get_all($filters=array(), $orderby='', $desc=true, $defaults=array(), $limit=false) {
122
123        list($where_q, $execute) = $this->build_where($filters);
124
125		$q = $this->select_query() . $where_q;
126
127		if ($orderby != '') {
128		    $fields = call_user_func(array($this->get_object_class_name(), 'get_columns'));
129		    if (!in_array($orderby, $fields)) {
130		        throw new \Exception('unknown field '.$orderby);
131            }
132		    $q .= " ORDER BY $orderby";
133		    if ($desc) {
134		        $q .= " DESC";
135            }
136        }
137
138        if (is_int($limit)) {
139		    $q .= " LIMIT $limit";
140        }
141
142		$sth = $this->model->db->prepare($q);
143
144        $sth->setFetchMode(\PDO::FETCH_CLASS, $this->get_object_class_name(),
145                           array($this->model, $defaults));
146
147		$sth->execute($execute);
148
149		return $sth;
150    }
151
152    public function count($filters=array()) {
153        $table = $this->get_table_view();
154        if (!$table) {
155            $table = $this->get_table_name();
156        }
157        if ($this->acl_static('id') < BEZ_PERMISSION_VIEW) {
158            throw new PermissionDeniedException();
159        }
160
161        list($where_q, $execute) = $this->build_where($filters);
162
163        $q = "SELECT COUNT(*) FROM $table " . $where_q;
164        $sth = $this->model->db->prepare($q);
165        $sth->execute($execute);
166
167        $count = $sth->fetchColumn();
168        return $count;
169    }
170
171    public function get_one($id, $defaults=array()) {
172        $table = $this->get_table_view();
173        if (!$table) {
174            $table = $this->get_table_name();
175        }
176
177		$q = $this->select_query()." WHERE $table.id = ?";
178
179		$sth = $this->model->db->prepare($q);
180		$sth->execute(array($id));
181
182		$obj = $sth->fetchObject($this->get_object_class_name(),
183					array($this->model, $defaults));
184
185        if ($obj === false) {
186            throw new \Exception('there is no '.$this->get_table_name().' with id: '.$id);
187        }
188
189		return $obj;
190	}
191
192	public function get_table_name() {
193        $class = (new \ReflectionClass($this))->getShortName();
194        return lcfirst(str_replace('Factory', '', $class));
195	}
196
197    public function get_object_class_name() {
198        $class = (new \ReflectionClass($this))->getName();
199        return str_replace('Factory', '', $class);
200    }
201
202    public function create_object($defaults=array()) {
203        $object_name = $this->get_object_class_name();
204
205		$obj = new $object_name($this->model, $defaults);
206		return $obj;
207	}
208
209	protected function beginTransaction() {
210        $this->model->sqlite->query('BEGIN TRANSACTION');
211    }
212
213    protected function commitTransaction() {
214        $this->model->sqlite->query('COMMIT TRANSACTION');
215    }
216
217    protected function rollbackTransaction() {
218        $this->model->sqlite->query('ROLLBACK');
219    }
220
221	public function save(Entity $obj) {
222        //if user can change id, he can modify record
223		$set = array();
224		$execute = array();
225		$columns = array();
226		foreach ($obj->get_columns() as $column) {
227            if ($obj->$column === null) continue;
228			$set[] = ":$column";
229			$columns[] = $column;
230            $value = $obj->$column;
231            if ($value === '') {
232                $execute[':'.$column] = null;
233            } else {
234                $execute[':'.$column] = $value;
235            }
236		}
237
238		$query = 'REPLACE INTO '.$this->get_table_name().'
239							('.implode(',', $columns).')
240							VALUES ('.implode(',', $set).')';
241
242		$sth = $this->model->db->prepare($query);
243		$res = $sth->execute($execute);
244
245        //new object is created
246        if ($obj->id === NULL) {
247            $reflectionClass = new \ReflectionClass($obj);
248            $reflectionProperty = $reflectionClass->getProperty('id');
249            $reflectionProperty->setAccessible(true);
250            $reflectionProperty->setValue($obj, $this->model->db->lastInsertId());
251        }
252	}
253
254	public function initial_save(Entity $obj, $data) {
255        if ($obj->id != NULL) {
256            throw new \Exception('row already saved. use update_save');
257        }
258    }
259
260    public function update_save(Entity $obj, $data) {
261        if ($obj->id == NULL) {
262            throw new \Exception('row not saved. use initial_save()');
263        }
264    }
265
266	protected function delete_from_db($id) {
267		$q = 'DELETE FROM '.$this->get_table_name().' WHERE id = ?';
268		$sth = $this->model->db->prepare($q);
269		$sth->execute(array($id));
270	}
271
272	public function delete(Entity $obj) {
273        $this->model->acl->can($obj, 'id', BEZ_PERMISSION_DELETE);
274		$this->delete_from_db($obj->id);
275	}
276}
277