* @version 0.2 * @copyright GNU Lesser General Public License (LGPL) version 3 */ /** * Model * * The mother class of all models * @since 0.1 */ abstract class Model extends Pluginable { protected $_error; // errors protected $_properties; // properties definition protected $_fields; // properties selection protected $data; // properties values protected $_table; public function __construct($table='') { parent::__construct(); $this->_error = array(); $this->_fields = array(); if (empty($table)) { $this->_table = StringHelper::camelToFlat(__CLASS__); } else { $this->_table = $table; } } // ---- INITIALIZE OBJECT : PROPERTIES ------------------------------------ /** * addProperties : generic function * add property(ies) to class/object * @param mixed $prm1 array or name of property * @param mixed $prm2 if first parameter is, second is type (else: not needed) */ protected function addProperties($prm1, $prm2=null) { if (is_array($prm1)) { if (is_array($this->_properties)) { $this->_properties = array_merge($this->_properties,$prm1); } else { $this->_properties = $prm1; } } else if ($prm2) { if (!is_array($this->_properties)) { $this->_properties = array(); } $this->_properties[$prm1] = $prm2; } $this->all(); // select all fields by default } /** * getPropertyType : returns property type * @param string $key name of property */ public function getPropertyType($key) { if (isset($this->_properties[$key])) { return substr($this->_properties[$key],0,3); } else { return false; } } /** * getPropertyOption : returns property options * @param string $key name of property * @return array of options */ public function getPropertyOptions($key) { $str = substr($this->_properties[$key],4); if (empty($str)) { return array(); // return empty array } else { $arr = json_decode($str, true); // force array $arr['type'] = $this->getPropertyType($key); $arr['value'] = $this->value($key); if (is_null($arr['value'])) { // no value set ? look for default if (isset($arr['default'])) { $arr['value'] = $arr['default']; } } return $arr; } } /** * removeProperties : generic function * remove property(ies) to class/object * @param prm1 array or name of property * @param prm2 if first parameter is, second is type (else: not needed) */ protected function removeProperties($prm1) { if (is_array($this->_properties)) { if (is_array($prm1)) { foreach($prm1 as $key) { unset($this->_properties[$key]); } } else { unset($this->_properties[$prm1]); } } $this->all(); // update fields selection } /** * initObjectProperties : initialize nested objects */ public function initObjectProperties($nested = false) { foreach($this->_properties as $key => $type) { if (preg_match('/^OBJ/i',$type)) { $class = (strlen($type) > 3)?substr($type,4):$key; if ($nested) { $this->$key = new $class(); } else { if (!is_object($this->$key) || strtolower(get_class($this->$key)) != strtolower($class)) { $this->$key = new $class(); } $this->$key->initObjectProperties(true); } } } $this->callPlugins('initObjectProperties', $nested); $this->all(); // update fields selection } /** * resetProperties : clear all data */ public function resetProperties($nested=false) { foreach($this->_properties as $key => $type) { if (preg_match('/^OBJ/i',$type)) { $class = (strlen($type) > 3)?substr($type,4):$key; $this->$key = new $class(); if (!$nested) { $this->$key->resetProperties(true); } } else { unset($this->data[$key]); } } $this->callPlugins('resetProperties', $nested); $this->all(); // update fields selection } /** * reset : full reset */ public function reset() { $this->resetProperties(); $this->callHelpers('reset'); } // ---- PREPARE DATA MANIPULATION -------------------------------------------- public function fields() { if (!func_num_args()) { $this->all(); return true; } $args = func_get_args(); $arrFields = forward_static_call_array(array('StringHelper','mixedToArray'),$args); $this->_fields = array_keys($this->_properties); $this->_fields = array_intersect($this->_fields, $arrFields); } public function ignore() { if (!func_num_args()) { $this->all(); return true; } $args = func_get_args(); $arrFields = forward_static_call_array(array('StringHelper','mixedToArray'),$args); $this->_fields = array_keys($this->_properties); $this->_fields = array_diff($this->_fields, $arrFields); } public function all() { $this->_fields = array_keys($this->_properties); return $this->_fields; } public function getFields() { $arr = array(); foreach($this->_fields as $key) { $arr[$key] = true; } return array_intersect_key($this->_properties,$arr); } // ---- SET PROPERTIES DATA -------------------------------------------------- /** * set : generic set function (for a single property) */ protected function _set($key, $value) { // set regular property $arr = explode(',',$this->_properties[$key]); $class = array_shift($arr); $class = 'Var'.ucfirst(strtolower($class)); // and call the corresponding class/method $value = forward_static_call_array(array($class,'sanitize'),array($value, &$arr)); if (!empty($arr['error'])) { // value is invalid $this->_error[$key] = $arr['error']; $this->data[$key] = $value; // -TODO- value might be empty, but you might want it anyway return false; } else { // value is valid $this->data[$key] = $value; return true; } } protected function _setObject($key, $data, $class='', $nkey='') { if (empty($class)) { if (!$this->isObjectProperty($key, $class, $nkey)) { return false; } } // setting an object FC::log_core_debug(get_class($this)."->_setObject($key, [data], $class, $nkey)"); $obj = new $class; // set data set with interresting data only $part = array(); foreach($data as $k => $v) { if (preg_match('/^('.$nkey.'__|'.$nkey.'::)([a-z0-9_]+)$/',$k,$m)) { $kk = $m[2]; $part[$kk] = $v; } } FC::log_core_debug(' -> found '.count($part).' properties to be set ('.implode(', ',array_keys($part)).')'); if (count($part)) { if ($obj->set($part)) { FC::log_core_debug(" => setting ".get_class($obj)." in $key"); $this->data[$key] = $obj; return true; } else { FC::log_core_debug($obj->getAllErrors()); } } return false; } /** * set : generic set function * @todo deal with files, images, multiple choices, switches */ public function set() { $args = func_get_args(); if (!count($args)) { FrontController::log_error('Error: Tzn::get (empty 1st parameter)'); } $data = $args[0]; if (is_array($data)) { // first parameter is an array ? Setting all (selected) properties then ! $ok = true; foreach($this->_fields as $key) { if ($this->isObjectProperty($key, $class, $nkey)) { $r = call_user_func_array(array($this,'_setObject'),array($key, $data, $class, $nkey)); } else { // data not set ? $val = (array_key_exists($key, $data))?$data[$key]:NULL; // set data $r = call_user_func_array(array($this,'_set'),array($key,$val)); if ($r == false) { // just one error and this is it, you're screwed $ok = false; } } } $this->all(); // select all fields again return $ok; } else { // set a single property // -TODO- set object property then return call_user_func_array(array($this,'_set'),array($data,$args[1])); } } // ---- GET PROPERTIES DATA -------------------------------------------------- /** * _get : private generic get function * check property type and call corresponding method * variable parameters * first parameter : the method to call * second parameter : the key */ private function _get() { if (!func_num_args()) { FrontController::log_error('Error: Model::get (empty 1st parameter)'); } $args = func_get_args(); // remove first parameter (method) $method = array_shift($args); // remove second parameter (key) $key = array_shift($args); if (!array_key_exists($key, $this->_properties)) { // property not defined, check if trying to access nested object prop ? if (preg_match('/^([a-z0-9]+)(__|::)([a-z0-9\_]+)$/', $key, $arr)) { // error_log (get_class($this).': check if '.$key.' exists as '.$arr[0].'/'.$arr[1]); // try again within nested object if (array_key_exists($arr[1], $this->_properties)) { if (!empty($this->data[$arr[1]])) { $obj = $this->data[$arr[1]]; if (is_a($obj, 'Model')) { array_unshift($args, $arr[3]); return call_user_func_array(array($obj,$method),$args); } } else { return false; } } } // FrontController::log_error("Error: Model::get (property '$key' does not exist)"); throw new AppException(get_class($this)."::get (property '$key' does not exist"); return false; } // regular property (not an object), proceed $dfn = $this->_properties[$key]; /* -TODO- if (is_array($dfn)) { return call_user_func_array(array(&$this,'getLst'),$dfn); } */ // parse property definition $arrType = explode(',',$dfn); // guess class name corresponding to property type $class = 'Var'.ucfirst(strtolower($arrType[0])); // if property value is empty, don't bother and return an empty string if (!isset($this->data[$key])) { // property not set yet return null; } // add value as first parameter array_unshift($args,$this->data[$key]); // and call the corresponding class/method return forward_static_call_array(array($class,$method),$args); } /** * get : returns property value, as it fucking is * variable parameters */ public function get() { $args = func_get_args(); array_unshift($args, 'get'); return call_user_func_array(array($this,'_get'),$args); } /** * html : returns property value, formatted in HTML * variable parameters */ public function html() { $args = func_get_args(); array_unshift($args, 'html'); return call_user_func_array(array($this,'_get'),$args); } /** * value : returns property value, formatted for HTML forms * variable parameters */ public function value() { $args = func_get_args(); array_unshift($args, 'value'); return call_user_func_array(array($this,'_get'),$args); } /** * checks if value (or date) is empty */ public function isEmpty($key) { if (empty($this->data[$key]) || preg_match('/^(0000|9999)\-00\-00/',$this->data[$key])) { return true; } else { return false; } } /** * checks if property is a class * @param string $key property name * @param string $class model's class name (returned) * @param string $nkey key name for SQL statements (returned) */ public function isObjectProperty($key, &$class, &$nkey) { $class = $nkey = ''; if (empty($this->_properties[$key])) { return false; } $type = $this->_properties[$key]; if (preg_match('/^OBJ(,([a-z0-9_]*))?$/', $type, $match)) { $nkey = (count($match)>2)?$match[2]:$key; $class = StringHelper::flatToCamel((count($match)>2)?$nkey:($nkey.'_model'), true); return true; } else { return false; } } // ---- DATABASE Capabilities ------------------------------------------------ /** * Add database capabilities */ public function connectDb() { $this->addHelper('db', $this, $this->_table); } /** * get model UID * @param ext : adds table name for SQL query purpose */ public function proUid() { foreach ($this->_properties as $key => $type) { if (preg_match('/^UID/i',$type)) { return $key; } } return false; } /** * set the data object UID */ public function setUid($val) { if ($key = $this->proUid()) { return $this->set($key, $val); } return false; } /** * get the data object UID */ public function getUid() { if ($key = $this->proUid()) { return $this->get($key); } else { return false; } } /** * check data before submitting */ public function check($fields='') { if (empty($this->data)) { return false; } $arr = StringHelper::mixedToArray($fields); $ok = true; if (count($arr)) { foreach($arr as $key) { if (empty($this->data[$key])) { $this->_error[$key] = 'compulsory_field'; $ok = false; } } } return $ok; } // ---- ERROR Reporting ------------------------------------------------------ /** * return error * @param the field */ public function getError($key) { if (empty($this->_error[$key])) { return false; } else { $err = $this->_error[$key]; if (is_array($err)) { $err = implode(', ', $err); } // -TODO- translate return $err; } } /** * print out list of errors (debugging) */ public function getAllErrors() { $str = ''; if (count($this->_error)) { foreach($this->_error as $key => $code) { $str .= '['.$key.'] '.$code."\n"; } } return $str; } /** * returns error in HTML format */ public function htmlError($key) { if ($str = $this->getError($key)) { return ''.VarStr::html($str).''; } else { return false; } } /** * print out list of errors (debugging) */ public function htmlAllErrors() { if (count($this->_error)) { echo ''; } } /** * temporary debug method */ public function __toString() { $str = '
';
		ob_start();
		print_r($this->data);
		$str .= ob_get_clean();
		$str .= '
'; return $str; } } /** * Any Variable (abstract class) * @since 0.1 */ abstract class VarAbstract { abstract public static function sanitize($val, &$info); public static function get($val) { return $val; } public static function html($val) { return $val; } public static function value($val) { return $val; } public static function sql($val, $db) { if (is_integer($val)) { return $val; } else if (empty($val)) { return "''"; } else { return "'".$db->escapeString($val)."'"; } } /** * get current user's timezone offset in seconds * @todo cache it */ public static function getUserTimeZoneOffset() { return intval($GLOBALS['config']['datetime']['timezone_user']->getOffset($GLOBALS['config']['datetime']['now'])); } } /** * Data Object ID Variable * @since 0.1 */ class VarUid extends VarAbstract { public static function sanitize($val, &$info) { if (is_array($val)) { throw new AppException('VarUid Sanitize Hell : '.implode(', ',$val)); } if (preg_match('/^[0-9A-Z]+$/i', $val)) { return $val; } else { return false; } } } /** * Integer Variable * @since 0.1 */ class VarInt extends VarAbstract { public static function sanitize($val, &$info) { $value = preg_replace(array('/[a-zA-Z]/','/ /','/,/'),'',$val); return intval($val); } } /** * Positive integer Variable * @since 0.1 */ class VarNum extends VarAbstract { public static function sanitize($val, &$info) { $value = preg_replace(array('/[a-zA-Z]/','/ /','/,/'),'',$val); return abs(intval($val)); } } /** * Float / Decimal Variable * @since 0.1 */ class VarDec extends VarAbstract { public static function sanitize($val, &$info) { $val = preg_replace(array('/[a-zA-Z]/','/ /','/,/'),array('','','.'),$val); if (preg_match('/[0-9]*(\.[0-9]+)?/',$val)) { return $val; } else { return 0; } } } /** * Date variable * @since 0.1 */ class VarDte extends VarAbstract { public static function sanitize($val, &$info) { if (empty($val)) { return '0000-00-00'; } if (preg_match('/^[0|2|9][0|1|9][0-9]{2}\-[0-1][0-9]\-[0-3][0-9]$/', $val)) { return $val; } if (!$GLOBALS['config']['datetime']['us_format']) { // try to parse non US format (dd/mm/yy) if (preg_match('/^([0-3]?[0-9])\/([0-1][0-9])(\/(20)?[0-9]{2})?$/',$val, $arr)) { if (empty($arr[3])) { $arr[3] = APP_YEAR; } else if (strlen($arr[3]) == 2) { $arr[3] = substr(APP_YEAR,0,2).substr($arr[3],1); } else { $arr[3] = substr($arr[3],1); } return $arr[3].'-'.$arr[2].'-'.$arr[1]; } } // try human readable formats (english only) if ($t = self::strToUnix($val)) { return strftime(APP_DATE_SQL, $t); } $info['error'] = 'model_date_invalid'; return false; } public static function html($val, $format='', $default='') { if (!$format) { $format = $format = $GLOBALS['config']['datetime']['us_format']?APP_DATE_USA:APP_DATE_EUR;; } $t = VarDte::strToUnix($val); if ($t === false) { return '/!\\'; } if ($t) { return strftime($format, $t); } else { return $default; } // -TODO- back as human readable format // -TODO- and in different formats, possibly return $val; } public static function value($val) { if (empty($val) || preg_match('/^(0000|9999)\-00\-00/',$val)) { return ''; } $arr = explode('-',$val); // -TODO- US format inverts day and month // -TODO- might want to use another separator instead of / $str = $arr[2].'/'.$arr[1].'/'.$arr[0]; return $str; } public static function strToUnix($val) { if (!$val || preg_match('/^(0000|9999)/',$val)) { return 0; } $t = strtotime($val); if ($t === false) { return false; } return $t; } } /** * Duration Variable (stored as number of seconds) * @since 0.1 */ class VarDur extends VarAbstract { public static function sanitize($val, &$info) { if (empty($val)) { return 0; } if (preg_match('/^[0-9]+$/', $val)) { // just a number of seconds return intval($val); } else if (preg_match('/^([0-2]?[0-9])\:([0-5][0-9])(\:([0-5][0-9]))?$/', $val, $arr)) { $t = 0; switch(count($arr)) { case 5: // seconds $t += intval($arr[4]); case 3: // minutes $t += intval($arr[2])*60; $t += intval($arr[1])*3600; } return $t; } else { $info['error'] = 'model_time_invalid'; return false; } } public static function html($val) { return self::workout($val); } public static function value($val) { return self::workout($val); } /** * format a number of seconds into HH:MM:SS * @todo enable callbacks to round up seconds if not showing */ public static function workout($val, $seconds=true) { $h = floor($val / 3600); $m = floor($val / 60) - ($h*60); $s = $val - ($h*3600 + $m*60); if ($seconds) { return str_pad($h, 2, '0',STR_PAD_LEFT) .':'.str_pad($m, 2, '0',STR_PAD_LEFT) .':'.str_pad($s, 2, '0',STR_PAD_LEFT); } else { if ($s) { // -TODO- add callback to round up seconds $m++; } return str_pad($h, 2, '0',STR_PAD_LEFT) .':'.str_pad($m, 2, '0',STR_PAD_LEFT); } } } /** * Time Variable (stored in GMT) * @since 0.1 */ class VarTim extends VarDur { public static function sanitize($val, &$info) { if (empty($val)) { return 0; } if (preg_match('/^[0-9]+$/', $val)) { // number of seconds, must be coming from SQL return intval($val); } if (preg_match('/^([0-2]?[0-9])\:([0-5][0-9])(\:([0-5][0-9]))?$/', $val, $arr)) { // coming from a form $t = 0; switch(count($arr)) { case 5: // seconds $t += intval($arr[4]); case 3: // minutes $t += intval($arr[2])*60; $t += intval($arr[1])*3600; } // now make GMT return $t - self::getUserTimeZoneOffset(); } $info['error'] = 'model_time_invalid'; return false; } /** * work on date to return human readable value * considers user's time zone */ public static function workout($val, $seconds=true) { $val += self::getUserTimeZoneOffset(); return parent::workout($val); } } /** * Date / Time Variable * @todo form field format * @since 0.1 */ class VarDtm extends VarAbstract { public static function sanitize($val, &$info) { if (empty($val)) { return '0000-00-00 00:00:00'; } if (preg_match('/^[0|2|9][0|1|9][0-9]{2}\-[0-1][0-9]\-[0-3][0-9]( ([0-2][0-9]\:[0-5][0-9])(\:[0-5][0-9])?)?$/', $val)) { // SQL format, return it as it is return $val; } if ($val == 'NOW') { return APP_SQL_NOW; } $d = ''; $t = 0; $arr = explode(' ',$val); foreach($arr as $v) { if ($tmp = VarTim::sanitize($v, $err)) { $t = $tmp; } else if ($tmp = VarDte::sanitize($v, $err)) { $d = $tmp; } } if ($d && is_integer($t)) { $dh = 3600*24; if ($t < 0) { // got to go one day back $d = strftime(APP_DATE_SQL,strtotime($d)-$dh); $t = $dh+$t; // + means - as $t is < 0 } else if ($t > $dh) { // got to move on one day $d = strftime(APP_DATE_SQL,strtotime($d)+$dh); $t = $t-$dh; } // return datetime in SQL format return $d.' '.VarDur::workout($t); } $info['error'] = 'model_datetime_invalid'; return false; } public static function get($val) { return $val; } public static function html($val, $format='', $default='') { if (!$format) { $format = $GLOBALS['config']['datetime']['us_format']?APP_DATETIME_USA:APP_DATETIME_EUR; } $t = VarDtm::strToUnix($val); if ($t === false) { return '/!\\'; } if ($t) { return strftime($format, $t); } else { return $default; } return $val; } public static function value($val) { // -TODO- back as form readable value return $val; } public static function strToUnix($val) { if (!$val || preg_match('/^(0000|9999)/',$val)) { return 0; } $t = strtotime($val); if ($t === false) { return false; } $t += self::getUserTimeZoneOffset(); return $t; } /** * work on date format to return human readable value */ public static function workout($val, $seconds=true) { $val += self::getUserTimeZoneOffset(); return parent::workout($val); } } /** * String Variable * @since 0.1 * @todo Check the workout and specialchars methods */ class VarStr extends VarAbstract { public static function sanitize($val, &$info) { if (is_array($val)) { throw new AppException('VarStr Sanitize Hell : '.implode(', ',$val)); } return strip_tags($val); } public static function html($val) { return self::specialchars($val); } public static function value($val) { return str_replace('"','"',$val); } public static function workout($value, $cut = 0, $pos = 1) { return $value; // -TODO- if (is_int($arg[1])) { $cut = $arg[1]; $pos++; } $default = $arg[$pos++]; $style = $arg[$pos]; $value = self::sanitize($value); if ($cut) { $value = str_replace("\r\n"," ",$value); if (($cut > 2) && (strlen($value) > $cut)) { $value = trim(substr($value,0,($cut-2))).".."; } } return $value; } public static function specialchars($val) { if (is_array($val)) { throw new AppException('VarStr SpecialChars Hell : '.implode(', ',$val)); } switch ($GLOBALS['config']['lang']['specialchars']) { case 3: $val = htmlentities($val); break; case 2: $val = htmlspecialchars($val); break; case 1: default: $spe = array('&','<','>'); $sfe = array('&','<','>'); $val = str_replace($spe,$sfe,$val); break; } return str_replace('"','"',$val); } } /** * Username variable - simple text, no special chars, no spaces * @since 0.1 */ class VarUsr extends VarAbstract { public static function sanitize($val, &$info) { if (!$val && in_array('compulsory', $info)) { $info['error'] = 'user_name_invalid'; return false; } if ((strlen($val) < APP_USER_NAME_MIN) || (strlen($val) > APP_USER_NAME_MAX)) { $info['error'] = 'user_name_length'; return false; } else if (preg_match(APP_USER_SANITIZE, $val)) { return $val; } else { $info['error'] = 'user_name_invalid'; return false; } return $val; } public static function value($val) { return str_replace('"','"',$val); } } /** * Password variable * @since 0.1 */ class VarPss extends VarAbstract { public static function sanitize($val, &$info) { if (empty($val)) { if (in_array('compulsory',$info)) { $info['error'] = 'password_required'; return false; } else { return true; } } if (preg_match(APP_PASSWORD_SANITIZE, $val)) { return $val; } else { $info['error'] = 'password_invalid'; return false; } return $val; } } /** * Text Variable - unformatted * @since 0.1 */ class VarTxt extends VarAbstract { public static function sanitize($val, &$info) { return preg_replace("/]*>[^<]+<\/script[^>]*>/is","", $val); } public static function html($val, $cut=0) { if ($cut && $cut < strlen($val)) { $val = substr($val,0,$cut).' [...]'; } return nl2br(VarStr::specialchars($val)); } public static function value($val) { return str_replace('"','"',$val); } } /** * Text Variable - simple style * @since 0.1 */ class VarBbs extends VarAbstract { public static function sanitize($val, &$info) { $val = preg_replace("/]*>[^<]+<\/script[^>]*>/is" ,"", $val); $val = preg_replace("/<\/?(div|span|iframe|frame|input|" ."textarea|script|style|applet|object|param|embed|form)[^>]*>/is" ,"", $val); return $val; } public static function html($val, $cut=0) { if ($cut) { $val = strip_tags($val); if ($cut < strlen($val)) { $val = substr($val,0,$cut).' [...]'; } } else { $val = preg_replace("/(?\s]+)/i", "\\0", $val); } return nl2br(str_replace('"','"',$val)); } public static function value($val) { return str_replace('"','"',$val); } } /** * Text Variable - Full HTML (but no scripting) * @since 0.1 */ class VarHtm extends VarAbstract { public static function sanitize($val, &$info) { $val = preg_replace("/]*>[^<]+<\/script[^>]*>/is","", $val); return $val; } public static function value($val) { return str_replace('"','"',$val); } } /** * Text Variable - Full HTML (even scripting) * better be careful with that one ! really not secure... * @since 0.1 */ class VarXml extends VarAbstract { public static function sanitize($val, &$info) { return $val; } public static function value($val) { return str_replace('"','"',$val); } } /** * URL Variable - URL Address * @since 0.1 */ class VarUrl extends VarAbstract { public static function sanitize($val, &$info) { $val = trim($val); if ($val && (!preg_match("/^(http|https|ftp)?:\/\//i",$val))) { $val = "http://".$val; } if ($val == "http://") { $val = ""; } // -TODO- check if URL is valid return $val; } public static function html($val) { // -TODO- might want to create a link there return $val; } } /** * Email Variable * @since 0.1 */ class VarEml extends VarAbstract { public static function sanitize($val, &$info) { if (empty($val) || preg_match("/^[a-z0-9]([a-z0-9_\-\.\+]*)@([a-z0-9_\-\.]*)\.([a-z]{2,4})$/i",$val)) { return $val; } else { $info['error'] = 'model_email_invalid'; // -TODO-TRANSLATE- return ''; } } public static function html($val) { // -TODO- might want to create a link there return $val; } } /** * Document Variable * @todo Everything * @since 0.4 */ class VarDoc extends VarAbstract { public static function sanitize($val, &$info) { // -TODO- } public static function get($val) { // -TODO- } public static function html($val) { // -TODO- } public static function value($val) { // -TODO- } } /** * Image Variable * @todo Everything * @since 0.4 */ class VarImg extends VarAbstract { public static function sanitize($val, &$info) { // -TODO- } public static function get($val) { // -TODO- } public static function html($val) { // -TODO- } public static function value($val) { // -TODO- } } /** * Boolean Variable - Just one or zero, true or false * @since 0.4 */ class VarBol extends VarAbstract { public static function sanitize($val, &$info) { return ($val)?1:0; } } /** * Level Variable - Used for preferences, rights and switches * @todo Everything * @since 0.5 */ class VarLvl extends VarAbstract { public static function sanitize($val, &$info) { // -TODO- return intval($val); } public static function get($val) { // -TODO- return $val; } public static function html($val) { // -TODO- return $val; } public static function value($val) { // -TODO- return $val; } } /** * Level Variable - Used for preferences, rights and switches * @since 0.1 */ class VarObj extends VarAbstract { public static function sanitize($val, &$info) { echo 'VarObj::sanitize should not be called'; exit; } public static function html($val) { throw new AppException('can not render object'); } public static function value($val) { throw new AppException('can not render object'); } }