xref: /plugin/bez/mdl/Entity.php (revision de02284c1e90f3c0d8df29c1c019b3ef912eafd9)
1*de02284cSSzymon Olewniczak<?php
2*de02284cSSzymon Olewniczak
3*de02284cSSzymon Olewniczak//if(!defined('DOKU_INC')) die();
4*de02284cSSzymon Olewniczak
5*de02284cSSzymon Olewniczak
6*de02284cSSzymon Olewniczak//~ abstract class BEZ_mdl_Dummy_Entity {
7*de02284cSSzymon Olewniczak
8*de02284cSSzymon Olewniczak    //~ protected $model;
9*de02284cSSzymon Olewniczak
10*de02284cSSzymon Olewniczak    //~ protected $id = NULL;
11*de02284cSSzymon Olewniczak
12*de02284cSSzymon Olewniczak    //~ public function __get($property) {
13*de02284cSSzymon Olewniczak		//~ if ($property === 'id') {
14*de02284cSSzymon Olewniczak            //~ return $this->id;
15*de02284cSSzymon Olewniczak        //~ }
16*de02284cSSzymon Olewniczak	//~ }
17*de02284cSSzymon Olewniczak
18*de02284cSSzymon Olewniczak    //~ public function get_table_singular() {
19*de02284cSSzymon Olewniczak        //~ $class = get_class($this);
20*de02284cSSzymon Olewniczak		//~ $exp = explode('_', $class);
21*de02284cSSzymon Olewniczak		//~ $singular = array_pop($exp);
22*de02284cSSzymon Olewniczak		//~ return lcfirst($singular);
23*de02284cSSzymon Olewniczak    //~ }
24*de02284cSSzymon Olewniczak
25*de02284cSSzymon Olewniczak    //~ public function get_table_name() {
26*de02284cSSzymon Olewniczak		//~ $singlar = $this->get_table_singular();
27*de02284cSSzymon Olewniczak		//~ return $singular.'s';
28*de02284cSSzymon Olewniczak	//~ }
29*de02284cSSzymon Olewniczak
30*de02284cSSzymon Olewniczak    //~ public function acl_of($field) {
31*de02284cSSzymon Olewniczak        //~ return $this->model->acl->check_field($this, $field);
32*de02284cSSzymon Olewniczak    //~ }
33*de02284cSSzymon Olewniczak
34*de02284cSSzymon Olewniczak    //~ public function __construct($model) {
35*de02284cSSzymon Olewniczak		//~ $this->model = $model;
36*de02284cSSzymon Olewniczak	//~ }
37*de02284cSSzymon Olewniczak//~ }
38*de02284cSSzymon Olewniczak
39*de02284cSSzymon Olewniczaknamespace dokuwiki\plugin\bez\mdl;
40*de02284cSSzymon Olewniczak/*
41*de02284cSSzymon Olewniczak * All fields are stored in object as strings.
42*de02284cSSzymon Olewniczak * NULLs are converted to empty string.
43*de02284cSSzymon Olewniczak * If any attribute in object === NULL -> it means that it was not initialized
44*de02284cSSzymon Olewniczak * But we always inserts NULLs instead of empty strings.
45*de02284cSSzymon Olewniczak * https://stackoverflow.com/questions/1267999/mysql-better-to-insert-null-or-empty-string
46*de02284cSSzymon Olewniczak **/
47*de02284cSSzymon Olewniczak
48*de02284cSSzymon Olewniczakuse dokuwiki\plugin\bez\meta\PermissionDeniedException;
49*de02284cSSzymon Olewniczak
50*de02284cSSzymon Olewniczakabstract class Entity {// extends BEZ_mdl_Dummy_Entity {
51*de02284cSSzymon Olewniczak
52*de02284cSSzymon Olewniczak    /** @var  Model */
53*de02284cSSzymon Olewniczak    protected $model;
54*de02284cSSzymon Olewniczak
55*de02284cSSzymon Olewniczak    /** @var Validator */
56*de02284cSSzymon Olewniczak    protected $validator;
57*de02284cSSzymon Olewniczak
58*de02284cSSzymon Olewniczak    //protected $columns_demendencies = array();
59*de02284cSSzymon Olewniczak
60*de02284cSSzymon Olewniczak	//protected $parse_int = array();
61*de02284cSSzymon Olewniczak
62*de02284cSSzymon Olewniczak	abstract public static function get_columns();
63*de02284cSSzymon Olewniczak
64*de02284cSSzymon Olewniczak//    abstract public static function get_virtual_columns();
65*de02284cSSzymon Olewniczak
66*de02284cSSzymon Olewniczak//    private function is_dummy() {
67*de02284cSSzymon Olewniczak//        if (strstr(get_class(), 'Dummy') === false) {
68*de02284cSSzymon Olewniczak//            return false;
69*de02284cSSzymon Olewniczak//        }
70*de02284cSSzymon Olewniczak//        return true;
71*de02284cSSzymon Olewniczak//    }
72*de02284cSSzymon Olewniczak//
73*de02284cSSzymon Olewniczak//    private function not_for_dummies() {
74*de02284cSSzymon Olewniczak//        if ($this->is_dummy()) {
75*de02284cSSzymon Olewniczak//            throw new Exception('dummy object doesn\'t contains data.');
76*de02284cSSzymon Olewniczak//        }
77*de02284cSSzymon Olewniczak//    }
78*de02284cSSzymon Olewniczak
79*de02284cSSzymon Olewniczak	public function get_assoc($filter=NULL) {
80*de02284cSSzymon Olewniczak        //$this->not_for_dummies();
81*de02284cSSzymon Olewniczak
82*de02284cSSzymon Olewniczak		$assoc = array();
83*de02284cSSzymon Olewniczak		//$columns = array_merge($this->get_columns(), $this->get_virtual_columns());
84*de02284cSSzymon Olewniczak
85*de02284cSSzymon Olewniczak        $columns = $this->get_columns();
86*de02284cSSzymon Olewniczak        if ($filter !== NULL) {
87*de02284cSSzymon Olewniczak            $columns = array_intersect($columns, $filter);
88*de02284cSSzymon Olewniczak        }
89*de02284cSSzymon Olewniczak
90*de02284cSSzymon Olewniczak		foreach ($columns as $col) {
91*de02284cSSzymon Olewniczak			$assoc[$col] = $this->$col;
92*de02284cSSzymon Olewniczak		}
93*de02284cSSzymon Olewniczak		return $assoc;
94*de02284cSSzymon Olewniczak	}
95*de02284cSSzymon Olewniczak
96*de02284cSSzymon Olewniczak//    public function get_table_singular() {
97*de02284cSSzymon Olewniczak//        $class = get_class($this);
98*de02284cSSzymon Olewniczak//		$exp = explode('_', $class);
99*de02284cSSzymon Olewniczak//		$singular = array_pop($exp);
100*de02284cSSzymon Olewniczak//		return lcfirst($singular);
101*de02284cSSzymon Olewniczak//    }
102*de02284cSSzymon Olewniczak//
103*de02284cSSzymon Olewniczak    public function get_table_name() {
104*de02284cSSzymon Olewniczak        $class = (new \ReflectionClass($this))->getShortName();
105*de02284cSSzymon Olewniczak		return lcfirst($class);
106*de02284cSSzymon Olewniczak	}
107*de02284cSSzymon Olewniczak
108*de02284cSSzymon Olewniczak//    private function create_DateTime_from_column($column) {
109*de02284cSSzymon Olewniczak//        $cols = array_merge($this->get_columns(), $this->get_virtual_columns());
110*de02284cSSzymon Olewniczak//        if (!in_array($column, $cols)) {
111*de02284cSSzymon Olewniczak//            throw new Exception("$column is not a column");
112*de02284cSSzymon Olewniczak//        }
113*de02284cSSzymon Olewniczak//        $dt = $this->$column;
114*de02284cSSzymon Olewniczak//        if (is_numeric($dt)) {
115*de02284cSSzymon Olewniczak//            return new DateTime('@'.$dt);
116*de02284cSSzymon Olewniczak//        }
117*de02284cSSzymon Olewniczak//        return new DateTime($dt);
118*de02284cSSzymon Olewniczak//    }
119*de02284cSSzymon Olewniczak//
120*de02284cSSzymon Olewniczak//    public function date_format($column) {
121*de02284cSSzymon Olewniczak//        $date = $this->create_DateTime_from_column($column);
122*de02284cSSzymon Olewniczak//
123*de02284cSSzymon Olewniczak//        return $date->format('Y-m-d');
124*de02284cSSzymon Olewniczak//    }
125*de02284cSSzymon Olewniczak//
126*de02284cSSzymon Olewniczak//    public function datetime_format($column, $format='comment') {
127*de02284cSSzymon Olewniczak//        $date = $this->create_DateTime_from_column($column);;
128*de02284cSSzymon Olewniczak//
129*de02284cSSzymon Olewniczak//        if ($format === 'comment') {
130*de02284cSSzymon Olewniczak//            return $dt->format('j') . ' ' .
131*de02284cSSzymon Olewniczak//                    $this->model->action->getLang('mon'.$dt->format('n').'_a') . ' ' .
132*de02284cSSzymon Olewniczak//                    ($dt->format('Y') === date('Y') ? '' : $dt->format('Y') . ' ') .
133*de02284cSSzymon Olewniczak//                    $this->model->action->getLang('at_hour') . ' ' .
134*de02284cSSzymon Olewniczak//                    $dt->format('G:i');
135*de02284cSSzymon Olewniczak//        }
136*de02284cSSzymon Olewniczak//    }
137*de02284cSSzymon Olewniczak//
138*de02284cSSzymon Olewniczak//    public function days_ago($column, $first_date = null) {
139*de02284cSSzymon Olewniczak//        if ($first_date === null) {
140*de02284cSSzymon Olewniczak//            $first_date = new DateTime();
141*de02284cSSzymon Olewniczak//        } elseif (is_string($first_date)) {
142*de02284cSSzymon Olewniczak//            $first_date = $this->create_DateTime_from_column($first_date);
143*de02284cSSzymon Olewniczak//        }
144*de02284cSSzymon Olewniczak//        $interval = $first_date->diff($this->create_DateTime_from_column($column));
145*de02284cSSzymon Olewniczak//        $sign = $interval->format('%R');
146*de02284cSSzymon Olewniczak//        $days = $interval->format('%a');
147*de02284cSSzymon Olewniczak//        if ($sign === '-') {
148*de02284cSSzymon Olewniczak//            return $days . ' ' . $this->model->action->getLang('days') . ' ' .
149*de02284cSSzymon Olewniczak//                    $this->model->action->getLang('ago');
150*de02284cSSzymon Olewniczak//        }
151*de02284cSSzymon Olewniczak//        return $days . ' ' . $this->model->action->getLang('days');
152*de02284cSSzymon Olewniczak//
153*de02284cSSzymon Olewniczak//    }
154*de02284cSSzymon Olewniczak//
155*de02284cSSzymon Olewniczak//    public function float_localized($column) {
156*de02284cSSzymon Olewniczak//        $cols = array_merge($this->get_columns(), $this->get_virtual_columns());
157*de02284cSSzymon Olewniczak//        if (!in_array($column, $cols)) {
158*de02284cSSzymon Olewniczak//            throw new Exception("$column is not a column");
159*de02284cSSzymon Olewniczak//        }
160*de02284cSSzymon Olewniczak//        if ($this->$column === '') {
161*de02284cSSzymon Olewniczak//            return '';
162*de02284cSSzymon Olewniczak//        }
163*de02284cSSzymon Olewniczak//
164*de02284cSSzymon Olewniczak//        if (!is_numeric($this->$column)) {
165*de02284cSSzymon Olewniczak//            throw new Exception('Column ' . $column . ' isn\'t numeric');
166*de02284cSSzymon Olewniczak//        }
167*de02284cSSzymon Olewniczak//
168*de02284cSSzymon Olewniczak//        return sprintf('%.2f', $this->$column);
169*de02284cSSzymon Olewniczak//    }
170*de02284cSSzymon Olewniczak
171*de02284cSSzymon Olewniczak    //set id when object is saved in database
172*de02284cSSzymon Olewniczak//    public function set_id($id) {
173*de02284cSSzymon Olewniczak////        $this->not_for_dummies();
174*de02284cSSzymon Olewniczak//
175*de02284cSSzymon Olewniczak//        if ($this->id === NULL) {
176*de02284cSSzymon Olewniczak//            $this->id = $id;
177*de02284cSSzymon Olewniczak//        } else {
178*de02284cSSzymon Olewniczak//            throw new \Exception('id already set for issue #'.$this->id);
179*de02284cSSzymon Olewniczak//        }
180*de02284cSSzymon Olewniczak//    }
181*de02284cSSzymon Olewniczak
182*de02284cSSzymon Olewniczak//	public function sqlite_date($time=NULL) {
183*de02284cSSzymon Olewniczak//		//SQLITE format: https://www.sqlite.org/lang_datefunc.html
184*de02284cSSzymon Olewniczak//		if ($time === NULL) {
185*de02284cSSzymon Olewniczak//			return date('Y-m-d H:i:s');
186*de02284cSSzymon Olewniczak//		} else {
187*de02284cSSzymon Olewniczak//			return date('Y-m-d H:i:s', $time);
188*de02284cSSzymon Olewniczak//		}
189*de02284cSSzymon Olewniczak//	}
190*de02284cSSzymon Olewniczak
191*de02284cSSzymon Olewniczak	public function __get($property) {
192*de02284cSSzymon Olewniczak//        $this->not_for_dummies();
193*de02284cSSzymon Olewniczak
194*de02284cSSzymon Olewniczak//		$columns = array_merge($this->get_columns(), $this->get_virtual_columns());
195*de02284cSSzymon Olewniczak        if (!property_exists($this, $property) || !in_array($property, $this->get_columns())) {
196*de02284cSSzymon Olewniczak            throw new \Exception('there is no column: "'.$property. '"" in table: "' . $this->get_table_name() . '"');
197*de02284cSSzymon Olewniczak        }
198*de02284cSSzymon Olewniczak
199*de02284cSSzymon Olewniczak        //now only normal db columns has ACL, it should be fixed
200*de02284cSSzymon Olewniczak        if ($this->acl_of($property) < BEZ_PERMISSION_VIEW) {
201*de02284cSSzymon Olewniczak            throw new PermissionDeniedException();
202*de02284cSSzymon Olewniczak        }
203*de02284cSSzymon Olewniczak
204*de02284cSSzymon Olewniczak        return $this->$property;
205*de02284cSSzymon Olewniczak
206*de02284cSSzymon Olewniczak//		if (property_exists($this, $property) && in_array($property, $this->get_columns())) {
207*de02284cSSzymon Olewniczak////			if (in_array($property, $this->parse_int)) {
208*de02284cSSzymon Olewniczak////				return (int)$this->$property;
209*de02284cSSzymon Olewniczak////			} else {
210*de02284cSSzymon Olewniczak//				return $this->$property;
211*de02284cSSzymon Olewniczak////			}
212*de02284cSSzymon Olewniczak//		}
213*de02284cSSzymon Olewniczak	}
214*de02284cSSzymon Olewniczak
215*de02284cSSzymon Olewniczak    protected function set_property($property, $value) {
216*de02284cSSzymon Olewniczak//        $this->not_for_dummies();
217*de02284cSSzymon Olewniczak
218*de02284cSSzymon Olewniczak        if (!in_array($property, $this->get_columns())) {
219*de02284cSSzymon Olewniczak            throw new \Exception('trying to set not existing column');
220*de02284cSSzymon Olewniczak        }
221*de02284cSSzymon Olewniczak
222*de02284cSSzymon Olewniczak        //throws ValidationException
223*de02284cSSzymon Olewniczak        $this->validator->validate_field($property, $value);
224*de02284cSSzymon Olewniczak
225*de02284cSSzymon Olewniczak        //throws PermissionDeniedException
226*de02284cSSzymon Olewniczak        $this->model->acl->can_change($this, $property);
227*de02284cSSzymon Olewniczak
228*de02284cSSzymon Olewniczak        $this->$property = $value;
229*de02284cSSzymon Olewniczak
230*de02284cSSzymon Olewniczak//        if (isset($this->columns_demendencies[$property])) {
231*de02284cSSzymon Olewniczak//            $method = $this->columns_demendencies[$property];
232*de02284cSSzymon Olewniczak//            //convention -> run the method with the same name as $property
233*de02284cSSzymon Olewniczak//            if (!method_exists($this, $method)) {
234*de02284cSSzymon Olewniczak//                throw new Exception("denepndency method: $property not implemented");
235*de02284cSSzymon Olewniczak//            }
236*de02284cSSzymon Olewniczak//            $this->$method();
237*de02284cSSzymon Olewniczak//        }
238*de02284cSSzymon Olewniczak    }
239*de02284cSSzymon Olewniczak
240*de02284cSSzymon Olewniczak    protected function set_property_array($array) {
241*de02284cSSzymon Olewniczak        foreach ($array as $k => $v) {
242*de02284cSSzymon Olewniczak            $this->set_property($k, $v);
243*de02284cSSzymon Olewniczak        }
244*de02284cSSzymon Olewniczak    }
245*de02284cSSzymon Olewniczak
246*de02284cSSzymon Olewniczak    //by default do nothing
247*de02284cSSzymon Olewniczak//    private function update_virtual_columns() {
248*de02284cSSzymon Olewniczak//    }
249*de02284cSSzymon Olewniczak//
250*de02284cSSzymon Olewniczak
251*de02284cSSzymon Olewniczak    public function set_data($post) {
252*de02284cSSzymon Olewniczak//        $input = array_intersect($this->changable_fields($filter), array_keys($post), array_keys($this->validator->get_rules()));
253*de02284cSSzymon Olewniczak
254*de02284cSSzymon Olewniczak        $val_data = $this->validator->validate($post);
255*de02284cSSzymon Olewniczak		if ($val_data === false) {
256*de02284cSSzymon Olewniczak			throw new ValidationException($this->get_table_name(), $this->validator->get_errors());
257*de02284cSSzymon Olewniczak		}
258*de02284cSSzymon Olewniczak
259*de02284cSSzymon Olewniczak		$this->set_property_array($val_data);
260*de02284cSSzymon Olewniczak
261*de02284cSSzymon Olewniczak//        $this->update_virtual_columns();
262*de02284cSSzymon Olewniczak    }
263*de02284cSSzymon Olewniczak
264*de02284cSSzymon Olewniczak//    public function changable_fields($filter=NULL) {
265*de02284cSSzymon Olewniczak//       $fields = $this->model->acl->check($this);
266*de02284cSSzymon Olewniczak//
267*de02284cSSzymon Olewniczak//       if ($filter !== NULL) {
268*de02284cSSzymon Olewniczak//           $fields = array_filter($fields, function ($k) use ($filter) {
269*de02284cSSzymon Olewniczak//                return in_array($k, $filter);
270*de02284cSSzymon Olewniczak//           }, ARRAY_FILTER_USE_KEY);
271*de02284cSSzymon Olewniczak//       }
272*de02284cSSzymon Olewniczak//
273*de02284cSSzymon Olewniczak//       return array_keys(array_filter($fields, function ($var) {
274*de02284cSSzymon Olewniczak//           return $var >= BEZ_PERMISSION_CHANGE;
275*de02284cSSzymon Olewniczak//       }));
276*de02284cSSzymon Olewniczak//    }
277*de02284cSSzymon Olewniczak
278*de02284cSSzymon Olewniczak    public function acl_of($field) {
279*de02284cSSzymon Olewniczak        return $this->model->acl->check_field($this, $field);
280*de02284cSSzymon Olewniczak    }
281*de02284cSSzymon Olewniczak
282*de02284cSSzymon Olewniczak    public function __construct($model) {
283*de02284cSSzymon Olewniczak        //by convention all defaults must be strings
284*de02284cSSzymon Olewniczak//        foreach ($defaults as $val) {
285*de02284cSSzymon Olewniczak//            if (!is_string($val)) {
286*de02284cSSzymon Olewniczak//                throw new Exception('all defaults must be strings');
287*de02284cSSzymon Olewniczak//            }
288*de02284cSSzymon Olewniczak//        }
289*de02284cSSzymon Olewniczak//		$this->model = $model;
290*de02284cSSzymon Olewniczak//
291*de02284cSSzymon Olewniczak//        if (!$this->is_dummy()) {
292*de02284cSSzymon Olewniczak//            $this->validator = new BEZ_mdl_Validator($this->model);
293*de02284cSSzymon Olewniczak//        }
294*de02284cSSzymon Olewniczak		//$this->helper = plugin_load('helper', 'bez');
295*de02284cSSzymon Olewniczak
296*de02284cSSzymon Olewniczak        $this->model = $model;
297*de02284cSSzymon Olewniczak        $this->validator = new Validator($this->model);
298*de02284cSSzymon Olewniczak	}
299*de02284cSSzymon Olewniczak}
300