diff options
author | Kirylka <kirylanoshko@gmail.com> | 2015-03-31 17:56:47 +0300 |
---|---|---|
committer | Kirylka <kirylanoshko@gmail.com> | 2015-03-31 17:56:47 +0300 |
commit | f5f99c335707d9b11d40f1eb0f6ddb5a993fd31a (patch) | |
tree | d9c0d3532ec9f0f2fb68e31d2611282ae0642181 /codebase | |
parent | 458f0aead573842f1df00ce2ae00334c27f66585 (diff) | |
download | connector-php-f5f99c335707d9b11d40f1eb0f6ddb5a993fd31a.zip connector-php-f5f99c335707d9b11d40f1eb0f6ddb5a993fd31a.tar.gz connector-php-f5f99c335707d9b11d40f1eb0f6ddb5a993fd31a.tar.bz2 |
Creating a new connector for yii2.
Diffstat (limited to 'codebase')
85 files changed, 4845 insertions, 8440 deletions
diff --git a/codebase/Connector.php b/codebase/Connector.php new file mode 100644 index 0000000..9c28872 --- /dev/null +++ b/codebase/Connector.php @@ -0,0 +1,645 @@ +<?php + +namespace DHTMLX\Connector; + +use DHTMLX\Connector\Tools\EventMaster; +use DHTMLX\Connector\Tools\AccessMaster; +use DHTMLX\Connector\Tools\LogMaster; +use DHTMLX\Connector\Output\RenderStrategy; +use DHTMLX\Connector\Output\OutputWriter; +use DHTMLX\Connector\DataStorage\DataConfig; +use DHTMLX\Connector\DataStorage\DataAction; +use DHTMLX\Connector\DataStorage\DataRequestConfig; +use DHTMLX\Connector\DataStorage\MySQLDBDataWrapper; +use DHTMLX\Connector\DataStorage\ArrayDBDataWrapper; +use DHTMLX\Connector\DataStorage\PHPYii2DBDataWrapper; +use DHTMLX\Connector\XSSFilter\ConnectorSecurity; +use DHTMLX\Connector\Event\SortInterface; +use DHTMLX\Connector\Event\FilterInterface; + +class Connector { + protected $config;//DataConfig instance + protected $request;//DataRequestConfig instance + protected $names;//!< hash of names for used classes + protected $encoding="utf-8";//!< assigned encoding (UTF-8 by default) + protected $editing=false;//!< flag of edit mode ( response for dataprocessor ) + + public static $filter_var="dhx_filter"; + public static $sort_var="dhx_sort"; + public static $kids_var="dhx_kids"; + + public $model=false; + + private $updating=false;//!< flag of update mode ( response for data-update ) + private $db; //!< db connection resource + protected $dload;//!< flag of dyn. loading mode + public $access; //!< AccessMaster instance + protected $data_separator = "\n"; + + public $sql; //DataWrapper instance + public $event; //EventMaster instance + public $limit=false; + + private $id_seed=0; //!< default value, used to generate auto-IDs + protected $live_update = false; // actions table name for autoupdating + protected $extra_output="";//!< extra info which need to be sent to client side + protected $options=array();//!< hash of OptionsConnector + protected $as_string = false; // render() returns string, don't send result in response + protected $simple = false; // render only data without any other info + protected $filters; + protected $sorts; + protected $mix; + protected $order = false; + + /*! constructor + + Here initilization of all Masters occurs, execution timer initialized + @param db + db connection resource + @param type + string , which hold type of database ( MySQL or Postgre ), optional, instead of short DB name, full name of DataWrapper-based class can be provided + @param item_type + name of class, which will be used for item rendering, optional, DataItem will be used by default + @param data_type + name of class which will be used for dataprocessor calls handling, optional, DataProcessor class will be used by default. + */ + public function __construct($db,$type=false, $item_type=false, $data_type=false, $render_type = false){ + $this->exec_time=microtime(true); + $dsnamespace = "DHTMLX\\Connector\\DataStorage\\"; + if (!$type) $type=$dsnamespace."MySQLDBDataWrapper"; + + //die(var_dump(class_exists("DataConfig",true), new MySQLDBDataWrapper)); + if (class_exists($dsnamespace.$type."DBDataWrapper",true)) + $type.="DBDataWrapper"; + if (!$item_type) $item_type="DHTMLX\\Connector\\Data\\DataItem"; + if (!$data_type) $data_type="DHTMLX\\Connector\\Data\\DataProcessor"; + if (!$render_type) $render_type="DHTMLX\\Connector\\Output\\RenderStrategy"; + + $this->names=array( + "db_class"=>$type, + "item_class"=>$item_type, + "data_class"=>$data_type, + "render_class"=>$render_type + ); + $this->attributes = array(); + $this->filters = array(); + $this->sorts = array(); + $this->mix = array(); + + $this->config = new DataConfig(); + $this->request = new DataRequestConfig(); + $this->event = new EventMaster(); + $this->access = new AccessMaster(); + +// if (!class_exists($this->names["db_class"],false)) +// throw new \Exception("DB class not found: ".$this->names["db_class"]); + $dbClass = $dsnamespace.$this->names["db_class"]; + $this->sql = new $dbClass($db,$this->config); + $this->render = new $this->names["render_class"]($this); + + $this->db=$db;//saved for options connectors, if any + + EventMaster::trigger_static("connectorCreate",$this); + } + + /*! return db connection resource + nested class may neeed to access live connection object + @return + DB connection resource + */ + protected function get_connection(){ + return $this->db; + } + + public function get_config(){ + return new DataConfig($this->config); + } + + public function get_request(){ + return new DataRequestConfig($this->request); + } + + + protected $attributes; + public function add_top_attribute($name, $string){ + $this->attributes[$name] = $string; + } + + //model is a class, which will be used for all data operations + //we expect that it has next methods get, update, insert, delete + //if method was not defined - we will use default logic + public function useModel($model){ + $this->model = $model; + } + + + /*! config connector based on table + + @param table + name of table in DB + @param id + name of id field + @param fields + list of fields names + @param extra + list of extra fields, optional, such fields will not be included in data rendering, but will be accessible in all inner events + @param relation_id + name of field used to define relations for hierarchical data organization, optional + */ + public function render_table($table,$id="",$fields=false,$extra=false,$relation_id=false){ + $this->configure($table,$id,$fields,$extra,$relation_id); + return $this->render(); + } + public function configure($table,$id="",$fields=false,$extra=false,$relation_id=false){ + if ($fields === false){ + //auto-config + $info = $this->sql->fields_list($table); + $fields = implode(",",$info["fields"]); + if ($info["key"]) + $id = $info["key"]; + } + $this->config->init($id,$fields,$extra,$relation_id); + if (strpos(trim($table), " ")!==false) + $this->request->parse_sql($table); + else + $this->request->set_source($table); + } + + public function uuid(){ + return time()."x".$this->id_seed++; + } + + /*! config connector based on sql + + @param sql + sql query used as base of configuration + @param id + name of id field + @param fields + list of fields names + @param extra + list of extra fields, optional, such fields will not be included in data rendering, but will be accessible in all inner events + @param relation_id + name of field used to define relations for hierarchical data organization, optional + */ + public function render_sql($sql,$id,$fields,$extra=false,$relation_id=false){ + $this->config->init($id,$fields,$extra,$relation_id); + $this->request->parse_sql($sql); + return $this->render(); + } + + public function render_array($data, $id, $fields, $extra=false, $relation_id=false){ + $this->configure("-",$id,$fields,$extra,$relation_id); + $this->sql = new ArrayDBDataWrapper($data, $this->config); + return $this->render(); + } + + public function render_complex_sql($sql,$id,$fields,$extra=false,$relation_id=false){ + $this->config->init($id,$fields,$extra,$relation_id); + $this->request->parse_sql($sql, true); + return $this->render(); + } + + /*! render already configured connector + + @param config + configuration of data + @param request + configuraton of request + */ + public function render_connector($config,$request){ + $this->config->copy($config); + $this->request->copy($request); + return $this->render(); + } + + /*! render self + process commands, output requested data as XML + */ + public function render(){ + $this->event->trigger("onInit", $this); + EventMaster::trigger_static("connectorInit",$this); + + if (!$this->as_string) + $this->parse_request(); + $this->set_relation(); + + if ($this->live_update !== false && $this->updating!==false) { + $this->live_update->get_updates(); + } else { + if ($this->editing){ + //die($this->names["data_class"]); + $dp = new $this->names["data_class"]($this,$this->config,$this->request); + $dp->process($this->config,$this->request); + } else { + if (!$this->access->check("read")){ + LogMaster::log("Access control: read operation blocked"); + echo "Access denied"; + die(); + } + $wrap = new SortInterface($this->request); + $this->apply_sorts($wrap); + $this->event->trigger("beforeSort",$wrap); + $wrap->store(); + + $wrap = new FilterInterface($this->request); + $this->apply_filters($wrap); + $this->event->trigger("beforeFilter",$wrap); + $wrap->store(); + + if ($this->model && method_exists($this->model, "get")){ + $this->sql = new ArrayDBDataWrapper(); + $result = new ArrayQueryWrapper(call_user_func(array($this->model, "get"), $this->request)); + $out = $this->output_as_xml($result); + } else { + $out = $this->output_as_xml($this->get_resource()); + + if ($out !== null) return $out; + } + + } + } + $this->end_run(); + } + + + /*! empty call which used for tree-logic + * to prevent code duplicating + */ + protected function set_relation() {} + + /*! gets resource for rendering + */ + protected function get_resource() { + //die(var_dump($this->sql->select($this->request))); + return $this->sql->select($this->request); + } + + + /*! prevent SQL injection through column names + replace dangerous chars in field names + @param str + incoming field name + @return + safe field name + */ + protected function safe_field_name($str){ + return strtok($str, " \n\t;',"); + } + + /*! limit max count of records + connector will ignore any records after outputing max count + @param limit + max count of records + @return + none + */ + public function set_limit($limit){ + $this->limit = $limit; + } + + + public function limit($start, $count, $sort_field=false, $sort_dir=false){ + $this->request->set_limit($start, $count); + if ($sort_field) + $this->request->set_sort($sort_field, $sort_dir); + } + + protected function parse_request_mode(){ + //detect edit mode + if (isset($_GET["editing"])){ + $this->editing=true; + } else if (isset($_POST["ids"])){ + $this->editing=true; + LogMaster::log('While there is no edit mode mark, POST parameters similar to edit mode detected. \n Switching to edit mode ( to disable behavior remove POST[ids]'); + } else if (isset($_GET['dhx_version'])){ + $this->updating = true; + } + } + + /*! parse incoming request, detects commands and modes + */ + protected function parse_request(){ + //set default dyn. loading params, can be reset in child classes + if ($this->dload) + $this->request->set_limit(0,$this->dload); + else if ($this->limit) + $this->request->set_limit(0,$this->limit); + + if (isset($_GET["posStart"]) && isset($_GET["count"])) { + $this->request->set_limit($_GET["posStart"],$_GET["count"]); + } + + $this->parse_request_mode(); + + if ($this->live_update && ($this->updating || $this->editing)){ + $this->request->set_version($_GET["dhx_version"]); + $this->request->set_user($_GET["dhx_user"]); + } + + if (isset($_GET[Connector::$sort_var])) + foreach($_GET[Connector::$sort_var] as $k => $v){ + $k = $this->safe_field_name($k); + $this->request->set_sort($this->resolve_parameter($k),$v); + } + + if (isset($_GET[Connector::$filter_var])) + foreach($_GET[Connector::$filter_var] as $k => $v){ + $k = $this->safe_field_name($k); + if ($v !== "") + $this->request->set_filter($this->resolve_parameter($k),$v); + } + + $this->check_csrf(); + } + + protected function check_csrf(){ + $key = ConnectorSecurity::checkCSRF($this->editing); + if ($key !== "") + $this->add_top_attribute(ConnectorSecurity::$security_var, $key); + } + + /*! convert incoming request name to the actual DB name + @param name + incoming parameter name + @return + name of related DB field + */ + protected function resolve_parameter($name){ + return $name; + } + + + /*! replace xml unsafe characters + + @param string + string to be escaped + @return + escaped string + */ + protected function xmlentities($string) { + return str_replace( array( '&', '"', "'", '<', '>', '’' ), array( '&' , '"', ''' , '<' , '>', ''' ), $string); + } + + public function getRecord($id){ + LogMaster::log("Retreiving data for record: ".$id); + $source = new DataRequestConfig($this->request); + $source->set_filter($this->config->id["name"],$id, "="); + + $res = $this->sql->select($source); + + $temp = $this->data_separator; + $this->data_separator=""; + $output = $this->render_set($res); + $this->data_separato=$temp; + + return $output; + } + + /*! render from DB resultset + @param res + DB resultset + process commands, output requested data as XML + */ + protected function render_set($res){ + return $this->render->render_set($res, $this->names["item_class"], $this->dload, $this->data_separator, $this->config, $this->mix); + } + + /*! output fetched data as XML + @param res + DB resultset + */ + protected function output_as_xml($res){ + $result = $this->render_set($res); + if ($this->simple) return $result; + + $start="<?xml version='1.0' encoding='".$this->encoding."' ?>".$this->xml_start(); + $end=$result.$this->xml_end(); + + if ($this->as_string) return $start.$end; + + $out = new OutputWriter($start, $end); + $this->event->trigger("beforeOutput", $this, $out); + $out->output("", true, $this->encoding); + } + + + /*! end processing + stop execution timer, kill the process + */ + protected function end_run(){ + $time=microtime(true)-$this->exec_time; + LogMaster::log("Done in {$time}s"); + flush(); + die(); + } + + /*! set xml encoding + + methods sets only attribute in XML, no real encoding conversion occurs + @param encoding + value which will be used as XML encoding + */ + public function set_encoding($encoding){ + $this->encoding=$encoding; + } + + /*! enable or disable dynamic loading mode + + @param count + count of rows loaded from server, actual only for grid-connector, can be skiped in other cases. + If value is a false or 0 - dyn. loading will be disabled + */ + public function dynamic_loading($count){ + $this->dload=$count; + } + + /*! enable or disable data reordering + + @param name + name of field, which will be used for order storing, optional + by default 'sortorder' field will be used + */ + public function enable_order($name = true){ + if ($name === true) + $name = "sortorder"; + + $this->sort($name); + $this->access->allow("order"); + $this->request->set_order($name); + $this->order = $name; + } + + /*! enable logging + + @param path + path to the log file. If set as false or empty strig - logging will be disabled + @param client_log + enable output of log data to the client side + */ + public function enable_log($path=true,$client_log=false){ + LogMaster::enable_log($path,$client_log); + } + + /*! provides infor about current processing mode + @return + true if processing dataprocessor command, false otherwise + */ + public function is_select_mode(){ + $this->parse_request_mode(); + return !$this->editing; + } + + public function is_first_call(){ + $this->parse_request_mode(); + return !($this->editing || $this->updating || $this->request->get_start() || isset($_GET['dhx_no_header'])); + + } + + /*! renders self as xml, starting part + */ + protected function xml_start(){ + $attributes = ""; + + if ($this->dload){ + //info for dyn. loadin + if ($pos=$this->request->get_start()) + $attributes .= " pos='".$pos."'"; + else + $attributes .= " total_count='".$this->sql->get_size($this->request)."'"; + } + foreach($this->attributes as $k=>$v) + $attributes .= " ".$k."='".$v."'"; + + return "<data".$attributes.">"; + } + /*! renders self as xml, ending part + */ + protected function xml_end(){ + $this->fill_collections(); + if (isset($this->extra_output)) + return $this->extra_output."</data>"; + else + return "</data>"; + } + + protected function fill_collections($list=""){ + foreach ($this->options as $k=>$v) { + $name = $k; + $this->extra_output.="<coll_options for='{$name}'>"; + if (!is_string($this->options[$name])) + $this->extra_output.=$this->options[$name]->render(); + else + $this->extra_output.=$this->options[$name]; + $this->extra_output.="</coll_options>"; + } + } + + /*! assign options collection to the column + + @param name + name of the column + @param options + array or connector object + */ + public function set_options($name,$options){ + if (is_array($options)){ + $str=""; + foreach($options as $k => $v) + $str.="<item value='".$this->xmlentities($k)."' label='".$this->xmlentities($v)."' />"; + $options=$str; + } + $this->options[$name]=$options; + } + + + public function insert($data) { + $action = new DataAction('inserted', false, $data); + $request = new DataRequestConfig(); + $request->set_source($this->request->get_source()); + + $this->config->limit_fields($data); + $this->sql->insert($action,$request); + $this->config->restore_fields($data); + + return $action->get_new_id(); + } + + public function delete($id) { + $action = new DataAction('deleted', $id, array()); + $request = new DataRequestConfig(); + $request->set_source($this->request->get_source()); + + $this->sql->delete($action,$request); + return $action->get_status(); + } + + public function update($data) { + $action = new DataAction('updated', $data[$this->config->id["name"]], $data); + $request = new DataRequestConfig(); + $request->set_source($this->request->get_source()); + + $this->config->limit_fields($data); + $this->sql->update($action,$request); + $this->config->restore_fields($data); + + return $action->get_status(); + } + + /*! sets actions_table for Optimistic concurrency control mode and start it + @param table_name + name of database table which will used for saving actions + @param url + url used for update notifications + */ + public function enable_live_update($table, $url=false){ + $this->live_update = new DataUpdate($this->sql, $this->config, $this->request, $table,$url); + $this->live_update->set_event($this->event,$this->names["item_class"]); + $this->event->attach("beforeOutput", Array($this->live_update, "version_output")); + $this->event->attach("beforeFiltering", Array($this->live_update, "get_updates")); + $this->event->attach("beforeProcessing", Array($this->live_update, "check_collision")); + $this->event->attach("afterProcessing", Array($this->live_update, "log_operations")); + } + + /*! render() returns result as string or send to response + */ + public function asString($as_string) { + $this->as_string = $as_string; + } + + public function simple_render() { + $this->simple = true; + return $this->render(); + } + + public function filter($name, $value = false, $operation = '=') { + $this->filters[] = array('name' => $name, 'value' => $value, 'operation' => $operation); + } + + public function clear_filter() { + $this->filters = array(); + $this->request->set_filters(array()); + } + + protected function apply_filters($wrap) { + for ($i = 0; $i < count($this->filters); $i++) { + $f = $this->filters[$i]; + $wrap->add($f['name'], $f['value'], $f['operation']); + } + } + + public function sort($name, $direction = false) { + $this->sorts[] = array('name' => $name, 'direction' => $direction); + } + + protected function apply_sorts($wrap) { + for ($i = 0; $i < count($this->sorts); $i++) { + $s = $this->sorts[$i]; + $wrap->add($s['name'], $s['direction']); + } + } + + public function mix($name, $value, $filter=false) { + $this->mix[] = Array('name'=>$name, 'value'=>$value, 'filter'=>$filter); + } +}
\ No newline at end of file diff --git a/codebase/convert.php b/codebase/ConvertService.php index f24922c..9fa3261 100644 --- a/codebase/convert.php +++ b/codebase/ConvertService.php @@ -1,4 +1,8 @@ <?php + +namespace DHTMLX\Connector; + +use DHTMLX\Connector\Tools\EventMaster; /* @author dhtmlx.com @license GPL, see license.txt @@ -8,9 +12,9 @@ class ConvertService{ private $type; private $name; private $inline; - + public function __construct($url){ - $this->url = $url; + $this->url = $url; $this->pdf(); EventMaster::attach_static("connectorInit",array($this, "handle")); } @@ -31,16 +35,16 @@ class ConvertService{ header('Content-Type: application/force-download'); header('Content-Type: application/octet-stream'); header('Content-Type: application/download'); - header('Content-Transfer-Encoding: binary'); - + header('Content-Transfer-Encoding: binary'); + header('Content-Length: '.$size); if ($inline) - header('Content-Disposition: inline; filename="'.$name.'";'); + header('Content-Disposition: inline; filename="'.$name.'";'); else header('Content-Disposition: attachment; filename="'.basename($name).'";'); - } + } public function convert($conn, $out){ - + $str_out = str_replace("<rows>","<rows profile='color'>", $out); $str_out = str_replace("<head>","<head><columns>", $str_out); $str_out = str_replace("</head>","</columns></head>", $str_out); @@ -55,15 +59,13 @@ class ConvertService{ curl_setopt($handle, CURLOPT_HEADER, false); curl_setopt($handle, CURLOPT_RETURNTRANSFER, true); curl_setopt($handle, CURLOPT_POSTFIELDS, "grid_xml=".urlencode($str_out)); - - + + $out->reset(); $out->set_type("pdf"); $out->add(curl_exec($handle)); $this->as_file(strlen((string)$out), $this->name, $this->inline); - + curl_close($handle); } -} - -?>
\ No newline at end of file +}
\ No newline at end of file diff --git a/codebase/Data/DataAction.php b/codebase/Data/DataAction.php new file mode 100644 index 0000000..8e4b5dd --- /dev/null +++ b/codebase/Data/DataAction.php @@ -0,0 +1,276 @@ +<?php +namespace DHTMLX\Connector\Data; + +use DHTMLX\Connector\Tools\LogMaster; +/*! contain all info related to action and controls customizaton +**/ +class DataAction{ + private $status; //!< cuurent status of record + private $id;//!< id of record + private $data;//!< data hash of record + private $userdata;//!< hash of extra data , attached to record + private $nid;//!< new id value , after operation executed + private $output;//!< custom output to client side code + private $attrs;//!< hash of custtom attributes + private $ready;//!< flag of operation's execution + private $addf;//!< array of added fields + private $delf;//!< array of deleted fields + + + /*! constructor + + @param status + current operation status + @param id + record id + @param data + hash of data + */ + function __construct($status,$id,$data){ + $this->status=$status; + $this->id=$id; + $this->data=$data; + $this->nid=$id; + + $this->output=""; + $this->attrs=array(); + $this->ready=false; + + $this->addf=array(); + $this->delf=array(); + } + + + /*! add custom field and value to DB operation + + @param name + name of field which will be added to DB operation + @param value + value which will be used for related field in DB operation + */ + function add_field($name,$value){ + LogMaster::log("adding field: ".$name.", with value: ".$value); + $this->data[$name]=$value; + $this->addf[]=$name; + } + /*! remove field from DB operation + + @param name + name of field which will be removed from DB operation + */ + function remove_field($name){ + LogMaster::log("removing field: ".$name); + $this->delf[]=$name; + } + + /*! sync field configuration with external object + + @param slave + SQLMaster object + @todo + check , if all fields removed then cancel action + */ + function sync_config($slave){ + foreach ($this->addf as $k => $v) + $slave->add_field($v); + foreach ($this->delf as $k => $v) + $slave->remove_field($v); + } + /*! get value of some record's propery + + @param name + name of record's property ( name of db field or alias ) + @return + value of related property + */ + function get_value($name){ + //die(var_dump($this->data["c0"])); + if (!array_key_exists($name,$this->data)){ + LogMaster::log("Incorrect field name used: ".$name); + LogMaster::log("data",$this->data); + return ""; + } + return $this->data[$name]; + } + /*! set value of some record's propery + + @param name + name of record's property ( name of db field or alias ) + @param value + value of related property + */ + function set_value($name,$value){ + LogMaster::log("change value of: ".$name." as: ".$value); + $this->data[$name]=$value; + } + /*! get hash of data properties + + @return + hash of data properties + */ + function get_data(){ + return $this->data; + } + /*! get some extra info attached to record + deprecated, exists just for backward compatibility, you can use set_value instead of it + @param name + name of userdata property + @return + value of related userdata property + */ + function get_userdata_value($name){ + return $this->get_value($name); + } + /*! set some extra info attached to record + deprecated, exists just for backward compatibility, you can use get_value instead of it + @param name + name of userdata property + @param value + value of userdata property + */ + function set_userdata_value($name,$value){ + return $this->set_value($name,$value); + } + /*! get current status of record + + @return + string with status value + */ + function get_status(){ + return $this->status; + } + /*! assign new status to the record + + @param status + new status value + */ + function set_status($status){ + $this->status=$status; + } + /*! set id + @param id + id value + */ + function set_id($id) { + $this->id = $id; + LogMaster::log("Change id: ".$id); + } + /*! set id + @param id + id value + */ + function set_new_id($id) { + $this->nid = $id; + LogMaster::log("Change new id: ".$id); + } + /*! get id of current record + + @return + id of record + */ + function get_id(){ + return $this->id; + } + /*! sets custom response text + + can be accessed through defineAction on client side. Text wrapped in CDATA, so no extra escaping necessary + @param text + custom response text + */ + function set_response_text($text){ + $this->set_response_xml("<![CDATA[".$text."]]>"); + } + /*! sets custom response xml + + can be accessed through defineAction on client side + @param text + string with XML data + */ + function set_response_xml($text){ + $this->output=$text; + } + /*! sets custom response attributes + + can be accessed through defineAction on client side + @param name + name of custom attribute + @param value + value of custom attribute + */ + function set_response_attribute($name,$value){ + $this->attrs[$name]=$value; + } + /*! check if action finished + + @return + true if action finished, false otherwise + */ + function is_ready(){ + return $this->ready; + } + /*! return new id value + + equal to original ID normally, after insert operation - value assigned for new DB record + @return + new id value + */ + function get_new_id(){ + return $this->nid; + } + + /*! set result of operation as error + */ + function error(){ + $this->status="error"; + $this->ready=true; + } + /*! set result of operation as invalid + */ + function invalid(){ + $this->status="invalid"; + $this->ready=true; + } + /*! confirm successful opeation execution + @param id + new id value, optional + */ + function success($id=false){ + if ($id!==false) + $this->nid = $id; + $this->ready=true; + } + /*! convert DataAction to xml format compatible with client side dataProcessor + @return + DataAction operation report as XML string + */ + function to_xml(){ + $str="<action type='{$this->status}' sid='{$this->id}' tid='{$this->nid}' "; + foreach ($this->attrs as $k => $v) { + $str.=$k."='".$this->xmlentities($v)."' "; + } + $str.=">{$this->output}</action>"; + return $str; + } + + /*! replace xml unsafe characters + + @param string + string to be escaped + @return + escaped string + */ + public function xmlentities($string) { + return str_replace( array( '&', '"', "'", '<', '>', '’' ), array( '&' , '"', ''' , '<' , '>', ''' ), $string); + } + + /*! convert self to string ( for logs ) + + @return + DataAction operation report as plain string + */ + function __toString(){ + return "action:{$this->status}; sid:{$this->id}; tid:{$this->nid};"; + } + + +}
\ No newline at end of file diff --git a/codebase/Data/DataItem.php b/codebase/Data/DataItem.php new file mode 100644 index 0000000..b980d9c --- /dev/null +++ b/codebase/Data/DataItem.php @@ -0,0 +1,128 @@ +<?php + +namespace DHTMLX\Connector\Data; +/*! base class for component item representation +**/ +class DataItem{ + protected $data; //!< hash of data + protected $config;//!< DataConfig instance + protected $index;//!< index of element + protected $skip;//!< flag , which set if element need to be skiped during rendering + protected $userdata; + + /*! constructor + + @param data + hash of data + @param config + DataConfig object + @param index + index of element + */ + function __construct($data,$config,$index){ + $this->config=$config; + $this->data=$data; + $this->index=$index; + $this->skip=false; + $this->userdata=false; + } + + //set userdata for the item + function set_userdata($name, $value){ + if ($this->userdata === false) + $this->userdata = array(); + + $this->userdata[$name]=$value; + } + /*! get named value + + @param name + name or alias of field + @return + value from field with provided name or alias + */ + public function get_value($name){ + return $this->data[$name]; + } + /*! set named value + + @param name + name or alias of field + @param value + value for field with provided name or alias + */ + public function set_value($name,$value){ + return $this->data[$name]=$value; + } + /*! get id of element + @return + id of element + */ + public function get_id(){ + $id = $this->config->id["name"]; + if (array_key_exists($id,$this->data)) + return $this->data[$id]; + return false; + } + /*! change id of element + + @param value + new id value + */ + public function set_id($value){ + $this->data[$this->config->id["name"]]=$value; + } + /*! get index of element + + @return + index of element + */ + public function get_index(){ + return $this->index; + } + /*! mark element for skiping ( such element will not be rendered ) + */ + public function skip(){ + $this->skip=true; + } + + /*! return self as XML string + */ + public function to_xml(){ + return $this->to_xml_start().$this->to_xml_end(); + } + + /*! replace xml unsafe characters + + @param string + string to be escaped + @return + escaped string + */ + public function xmlentities($string) { + return str_replace( array( '&', '"', "'", '<', '>', '’' ), array( '&' , '"', ''' , '<' , '>', ''' ), $string); + } + + /*! return starting tag for self as XML string + */ + public function to_xml_start(){ + $str="<item"; + for ($i=0; $i < sizeof($this->config->data); $i++){ + $name=$this->config->data[$i]["name"]; + $db_name=$this->config->data[$i]["db_name"]; + $str.=" ".$name."='".$this->xmlentities($this->data[$name])."'"; + } + //output custom data + if ($this->userdata !== false) + foreach ($this->userdata as $key => $value){ + $str.=" ".$key."='".$this->xmlentities($value)."'"; + } + + return $str.">"; + } + /*! return ending tag for XML string + */ + public function to_xml_end(){ + return "</item>"; + } +}
\ No newline at end of file diff --git a/codebase/Data/DataItemUpdate.php b/codebase/Data/DataItemUpdate.php new file mode 100644 index 0000000..ad97be2 --- /dev/null +++ b/codebase/Data/DataItemUpdate.php @@ -0,0 +1,105 @@ +<?php + +/* + @author dhtmlx.com + @license GPL, see license.txt +*/ + +/*! DataItemUpdate class for realization Optimistic concurrency control + Wrapper for DataItem object + It's used during outputing updates instead of DataItem object + Create wrapper for every data item with update information. +*/ + +namespace DHTMLX\Connector\Data; + +class DataItemUpdate extends DataItem { + + + /*! constructor + @param data + hash of data + @param config + DataConfig object + @param index + index of element + */ + public function __construct($data,$config,$index,$type){ + $this->config=$config; + $this->data=$data; + $this->index=$index; + $this->skip=false; + $this->child = new $type($data, $config, $index); + } + + /*! returns parent_id (for Tree and TreeGrid components) + */ + public function get_parent_id(){ + if (method_exists($this->child, 'get_parent_id')) { + return $this->child->get_parent_id(); + } else { + return ''; + } + } + + + /*! generate XML on the data hash base + */ + public function to_xml(){ + $str= "<update "; + $str .= 'status="'.$this->data['type'].'" '; + $str .= 'id="'.$this->data['dataId'].'" '; + $str .= 'parent="'.$this->get_parent_id().'"'; + $str .= '>'; + $str .= $this->child->to_xml(); + $str .= '</update>'; + return $str; + } + + /*! return starting tag for XML string + */ + public function to_xml_start(){ + $str="<update "; + $str .= 'status="'.$this->data['type'].'" '; + $str .= 'id="'.$this->data['dataId'].'" '; + $str .= 'parent="'.$this->get_parent_id().'"'; + $str .= '>'; + $str .= $this->child->to_xml_start(); + return $str; + } + + /*! return ending tag for XML string + */ + public function to_xml_end(){ + $str = $this->child->to_xml_end(); + $str .= '</update>'; + return $str; + } + + /*! returns false for outputing only current item without child items + */ + public function has_kids(){ + return false; + } + + /*! sets count of child items + @param value + count of child items + */ + public function set_kids($value){ + if (method_exists($this->child, 'set_kids')) { + $this->child->set_kids($value); + } + } + + /*! sets attribute for item + */ + public function set_attribute($name, $value){ + if (method_exists($this->child, 'set_attribute')) { + LogMaster::log("setting attribute: \nname = {$name}\nvalue = {$value}"); + $this->child->set_attribute($name, $value); + } else { + LogMaster::log("set_attribute method doesn't exists"); + } + } +}
\ No newline at end of file diff --git a/codebase/Data/DataProcessor.php b/codebase/Data/DataProcessor.php new file mode 100644 index 0000000..973753a --- /dev/null +++ b/codebase/Data/DataProcessor.php @@ -0,0 +1,253 @@ +<?php +/*! Base DataProcessor handling +**/ +namespace DHTMLX\Connector\Data; +use DHTMLX\Connector\Tools\LogMaster; +use DHTMLX\Connector\XSSFilter\ConnectorSecurity; +use DHTMLX\Connector\DataStorage\DataConfig; + +class DataProcessor{ + protected $connector;//!< Connector instance + protected $config;//!< DataConfig instance + protected $request;//!< DataRequestConfig instance + static public $action_param ="!nativeeditor_status"; + + /*! constructor + + @param connector + Connector object + @param config + DataConfig object + @param request + DataRequestConfig object + */ + function __construct($connector,$config,$request){ + $this->connector= $connector; + $this->config=$config; + $this->request=$request; + } + + /*! convert incoming data name to valid db name + redirect to Connector->name_data by default + @param data + data name from incoming request + @return + related db_name + */ + function name_data($data){ + return $data; + } + /*! retrieve data from incoming request and normalize it + + @param ids + array of extected IDs + @return + hash of data + */ + protected function get_post_values($ids){ + $data=array(); + for ($i=0; $i < sizeof($ids); $i++) + $data[$ids[$i]]=array(); + + foreach ($_POST as $key => $value) { + $details=explode("_",$key,2); + if (sizeof($details)==1) continue; + + $name=$this->name_data($details[1]); + $data[$details[0]][$name]=ConnectorSecurity::filter($value); + } + + return $data; + } + protected function get_ids(){ + if (!isset($_POST["ids"])) + throw new \Exception("Incorrect incoming data, ID of incoming records not recognized"); + return explode(",",$_POST["ids"]); + } + + protected function get_operation($rid){ + if (!isset($_POST[$rid."_".DataProcessor::$action_param])) + throw new \Exception("Status of record [{$rid}] not found in incoming request"); + return $_POST[$rid."_".DataProcessor::$action_param]; + } + /*! process incoming request ( save|update|delete ) + */ + function process(){ + LogMaster::log("DataProcessor object initialized",$_POST); + + $results=array(); + + $ids=$this->get_ids(); + $rows_data=$this->get_post_values($ids); + $failed=false; + + try{ + if ($this->connector->sql->is_global_transaction()) + $this->connector->sql->begin_transaction(); + + for ($i=0; $i < sizeof($ids); $i++) { + $rid = $ids[$i]; + LogMaster::log("Row data [{$rid}]",$rows_data[$rid]); + $status = $this->get_operation($rid); + + $action=new DataAction($status,$rid,$rows_data[$rid]); + + $results[]=$action; + $this->inner_process($action); + } + + } catch(\Exception $e){ + LogMaster::log($e); + $failed=true; + } + + if ($this->connector->sql->is_global_transaction()){ + if (!$failed) + for ($i=0; $i < sizeof($results); $i++) + if ($results[$i]->get_status()=="error" || $results[$i]->get_status()=="invalid"){ + $failed=true; + break; + } + if ($failed){ + for ($i=0; $i < sizeof($results); $i++) + $results[$i]->error(); + $this->connector->sql->rollback_transaction(); + } + else + $this->connector->sql->commit_transaction(); + } + + $this->output_as_xml($results); + } + + /*! converts status string to the inner mode name + + @param status + external status string + @return + inner mode name + */ + protected function status_to_mode($status){ + switch($status){ + case "updated": + return "update"; + break; + case "inserted": + return "insert"; + break; + case "deleted": + return "delete"; + break; + default: + return $status; + break; + } + } + /*! process data updated request received + + @param action + DataAction object + @return + DataAction object with details of processing + */ + protected function inner_process($action){ + + if ($this->connector->sql->is_record_transaction()) + $this->connector->sql->begin_transaction(); + + + + try{ + + $mode = $this->status_to_mode($action->get_status()); + if (!$this->connector->access->check($mode)){ + LogMaster::log("Access control: {$mode} operation blocked"); + $action->error(); + } else { + $check = $this->connector->event->trigger("beforeProcessing",$action); + + + if (!$action->is_ready()) + $this->check_exts($action,$mode); + if ($mode == "insert" && $action->get_status() != "error" && $action->get_status() != "invalid") + $this->connector->sql->new_record_order($action, $this->request); + + $check = $this->connector->event->trigger("afterProcessing",$action); + } + + } catch (\Exception $e){ + LogMaster::log($e); + $action->set_status("error"); + if ($action) + $this->connector->event->trigger("onDBError", $action, $e); + } + + if ($this->connector->sql->is_record_transaction()){ + if ($action->get_status()=="error" || $action->get_status()=="invalid") + $this->connector->sql->rollback_transaction(); + else + $this->connector->sql->commit_transaction(); + } + + return $action; + } + + /*! check if some event intercepts processing, send data to DataWrapper in other case + + @param action + DataAction object + @param mode + name of inner mode ( will be used to generate event names ) + */ + function check_exts($action,$mode){ + $old_config = new DataConfig($this->config); + + + $this->connector->event->trigger("before".$mode,$action); + if ($action->is_ready()) + LogMaster::log("Event code for ".$mode." processed"); + else { + //check if custom sql defined + $sql = $this->connector->sql->get_sql($mode,$action); + if ($sql){ + $this->connector->sql->query($sql); + } + else{ + $action->sync_config($this->config); + + + if ($this->connector->model && method_exists($this->connector->model, $mode)){ + call_user_func(array($this->connector->model, $mode), $action); + LogMaster::log("Model object process action: ".$mode); + } + if (!$action->is_ready()){ + + $method=array($this->connector->sql,$mode); + if (!is_callable($method)) + throw new \Exception("Unknown dataprocessing action: ".$mode); + call_user_func($method,$action,$this->request); + } + } + } + $this->connector->event->trigger("after".$mode,$action); + + $this->config->copy($old_config); + } + + /*! output xml response for dataprocessor + + @param results + array of DataAction objects + */ + function output_as_xml($results){ + LogMaster::log("Edit operation finished",$results); + ob_clean(); + header("Content-type:text/xml"); + echo "<?xml version='1.0' ?>"; + echo "<data>"; + for ($i=0; $i < sizeof($results); $i++) + echo $results[$i]->to_xml(); + echo "</data>"; + } + +}
\ No newline at end of file diff --git a/codebase/Data/DataUpdate.php b/codebase/Data/DataUpdate.php new file mode 100644 index 0000000..8fc1c46 --- /dev/null +++ b/codebase/Data/DataUpdate.php @@ -0,0 +1,163 @@ +<?php + +class DataUpdate{ + + protected $table; //!< table , where actions are stored + protected $url; //!< url for notification service, optional + protected $sql; //!< DB wrapper object + protected $config; //!< DBConfig object + protected $request; //!< DBRequestConfig object + protected $event; + protected $item_class; + protected $demu; + + //protected $config;//!< DataConfig instance + //protected $request;//!< DataRequestConfig instance + + /*! constructor + + @param connector + Connector object + @param config + DataConfig object + @param request + DataRequestConfig object + */ + function __construct($sql, $config, $request, $table, $url){ + $this->config= $config; + $this->request= $request; + $this->sql = $sql; + $this->table=$table; + $this->url=$url; + $this->demu = false; + } + + public function set_demultiplexor($path){ + $this->demu = $path; + } + + public function set_event($master, $name){ + $this->event = $master; + $this->item_class = $name; + } + + private function select_update($actions_table, $join_table, $id_field_name, $version, $user) { + $sql = "SELECT * FROM {$actions_table}"; + $sql .= " LEFT OUTER JOIN {$join_table} ON "; + $sql .= "{$actions_table}.DATAID = {$join_table}.{$id_field_name} "; + $sql .= "WHERE {$actions_table}.ID > '{$version}' AND {$actions_table}.USER <> '{$user}'"; + return $sql; + } + + private function get_update_max_version() { + $sql = "SELECT MAX(id) as VERSION FROM {$this->table}"; + $res = $this->sql->query($sql); + $data = $this->sql->get_next($res); + + if ($data == false || $data['VERSION'] == false) + return 1; + else + return $data['VERSION']; + } + + private function log_update_action($actions_table, $dataId, $status, $user) { + $sql = "INSERT INTO {$actions_table} (DATAID, TYPE, USER) VALUES ('{$dataId}', '{$status}', '{$user}')"; + $this->sql->query($sql); + if ($this->demu) + file_get_contents($this->demu); + } + + + + + /*! records operations in actions_table + @param action + DataAction object + */ + public function log_operations($action) { + $type = $this->sql->escape($action->get_status()); + $dataId = $this->sql->escape($action->get_new_id()); + $user = $this->sql->escape($this->request->get_user()); + if ($type!="error" && $type!="invalid" && $type !="collision") { + $this->log_update_action($this->table, $dataId, $type, $user); + } + } + + + /*! return action version in XMl format + */ + public function get_version() { + $version = $this->get_update_max_version(); + return "<userdata name='version'>".$version."</userdata>"; + } + + + /*! adds action version in output XML as userdata + */ + public function version_output($conn, $out) { + $out->add($this->get_version()); + } + + + /*! create update actions in XML-format and sends it to output + */ + public function get_updates() { + $sub_request = new DataRequestConfig($this->request); + $version = $this->request->get_version(); + $user = $this->request->get_user(); + + $sub_request->parse_sql($this->select_update($this->table, $this->request->get_source(), $this->config->id['db_name'], $version, $user)); + $sub_request->set_relation(false); + + $output = $this->render_set($this->sql->select($sub_request), $this->item_class); + + ob_clean(); + header("Content-type:text/xml"); + + echo $this->updates_start(); + echo $this->get_version(); + echo $output; + echo $this->updates_end(); + } + + + protected function render_set($res, $name){ + $output=""; + $index=0; + while ($data=$this->sql->get_next($res)){ + $data = new DataItemUpdate($data,$this->config,$index, $name); + $this->event->trigger("beforeRender",$data); + $output.=$data->to_xml(); + $index++; + } + return $output; + } + + /*! returns update start string + */ + protected function updates_start() { + $start = '<updates>'; + return $start; + } + + /*! returns update end string + */ + protected function updates_end() { + $start = '</updates>'; + return $start; + } + + /*! checks if action version given by client is deprecated + @param action + DataAction object + */ + public function check_collision($action) { + $version = $this->sql->escape($this->request->get_version()); + //$user = $this->sql->escape($this->request->get_user()); + $last_version = $this->get_update_max_version(); + if (($last_version > $version)&&($action->get_status() == 'update')) { + $action->error(); + $action->set_status('collision'); + } + } +}
\ No newline at end of file diff --git a/codebase/Data/GridDataProcessor.php b/codebase/Data/GridDataProcessor.php new file mode 100644 index 0000000..9b487eb --- /dev/null +++ b/codebase/Data/GridDataProcessor.php @@ -0,0 +1,23 @@ +<?php +namespace DHTMLX\Connector\Data; + +/*! DataProcessor class for Grid component +**/ +class GridDataProcessor extends DataProcessor{ + + /*! convert incoming data name to valid db name + converts c0..cN to valid field names + @param data + data name from incoming request + @return + related db_name + */ + function name_data($data){ + if ($data == "gr_id") return $this->config->id["name"]; + $parts=explode("c",$data); + if ($parts[0]=="" && ((string)intval($parts[1]))==$parts[1]) + if (sizeof($this->config->text)>intval($parts[1])) + return $this->config->text[intval($parts[1])]["name"]; + return $data; + } +}
\ No newline at end of file diff --git a/codebase/Data/TreeDataItem.php b/codebase/Data/TreeDataItem.php new file mode 100644 index 0000000..561d495 --- /dev/null +++ b/codebase/Data/TreeDataItem.php @@ -0,0 +1,157 @@ +<?php + +namespace DHTMLX\Connector\Data; + +class TreeDataItem extends DataItem +{ + private $im0;//!< image of closed folder + private $im1;//!< image of opened folder + private $im2;//!< image of leaf item + private $check;//!< checked state + private $kids = -1;//!< checked state + private $attrs;//!< collection of custom attributes + + function __construct($data, $config, $index) + { + parent::__construct($data, $config, $index); + + $this->im0 = false; + $this->im1 = false; + $this->im2 = false; + $this->check = false; + $this->attrs = array(); + } + + /*! get id of parent record + + @return + id of parent record + */ + function get_parent_id() + { + return $this->data[$this->config->relation_id["name"]]; + } + + /*! get state of items checkbox + + @return + state of item's checkbox as int value, false if state was not defined + */ + function get_check_state() + { + return $this->check; + } + + /*! set state of item's checkbox + + @param value + int value, 1 - checked, 0 - unchecked, -1 - third state + */ + function set_check_state($value) + { + $this->check = $value; + } + + /*! return count of child items + -1 if there is no info about childs + @return + count of child items + */ + function has_kids() + { + return $this->kids; + } + + /*! sets count of child items + @param value + count of child items + */ + function set_kids($value) + { + $this->kids = $value; + } + + /*! set custom attribute + + @param name + name of the attribute + @param value + new value of the attribute + */ + function set_attribute($name, $value) + { + switch ($name) { + case "id": + $this->set_id($value); + break; + case "text": + $this->data[$this->config->text[0]["name"]] = $value; + break; + case "checked": + $this->set_check_state($value); + break; + case "im0": + $this->im0 = $value; + break; + case "im1": + $this->im1 = $value; + break; + case "im2": + $this->im2 = $value; + break; + case "child": + $this->set_kids($value); + break; + default: + $this->attrs[$name] = $value; + } + } + + + /*! assign image for tree's item + + @param img_folder_closed + image for item, which represents folder in closed state + @param img_folder_open + image for item, which represents folder in opened state, optional + @param img_leaf + image for item, which represents leaf item, optional + */ + function set_image($img_folder_closed, $img_folder_open = false, $img_leaf = false) + { + $this->im0 = $img_folder_closed; + $this->im1 = $img_folder_open ? $img_folder_open : $img_folder_closed; + $this->im2 = $img_leaf ? $img_leaf : $img_folder_closed; + } + + /*! return self as XML string, starting part + */ + function to_xml_start() + { + if ($this->skip) return ""; + + $str1 = "<item id='" . $this->get_id() . "' text='" . $this->xmlentities($this->data[$this->config->text[0]["name"]]) . "' "; + if ($this->has_kids() == true) $str1 .= "child='" . $this->has_kids() . "' "; + if ($this->im0) $str1 .= "im0='" . $this->im0 . "' "; + if ($this->im1) $str1 .= "im1='" . $this->im1 . "' "; + if ($this->im2) $str1 .= "im2='" . $this->im2 . "' "; + if ($this->check) $str1 .= "checked='" . $this->check . "' "; + foreach ($this->attrs as $key => $value) + $str1 .= $key . "='" . $this->xmlentities($value) . "' "; + $str1 .= ">"; + if ($this->userdata !== false) + foreach ($this->userdata as $key => $value) + $str1 .= "<userdata name='" . $key . "'><![CDATA[" . $value . "]]></userdata>"; + + return $str1; + } + + /*! return self as XML string, ending part + */ + function to_xml_end() + { + if ($this->skip) return ""; + return "</item>"; + } + +}
\ No newline at end of file diff --git a/codebase/Data/TreeDataProcessor.php b/codebase/Data/TreeDataProcessor.php new file mode 100644 index 0000000..dca6a8f --- /dev/null +++ b/codebase/Data/TreeDataProcessor.php @@ -0,0 +1,25 @@ +<?php +namespace DHTMLX\Connector\Data; + +class TreeDataProcessor extends DataProcessor{ + + function __construct($connector,$config,$request){ + parent::__construct($connector,$config,$request); + $request->set_relation(false); + } + + /*! convert incoming data name to valid db name + converts c0..cN to valid field names + @param data + data name from incoming request + @return + related db_name + */ + function name_data($data){ + if ($data=="tr_pid") + return $this->config->relation_id["db_name"]; + if ($data=="tr_text") + return $this->config->text[0]["db_name"]; + return $data; + } +}
\ No newline at end of file diff --git a/codebase/DataStorage/ArrayDBDataWrapper.php b/codebase/DataStorage/ArrayDBDataWrapper.php new file mode 100644 index 0000000..a806161 --- /dev/null +++ b/codebase/DataStorage/ArrayDBDataWrapper.php @@ -0,0 +1,50 @@ +<?php + +namespace DHTMLX\Connector\DataStorage; + +class ArrayDBDataWrapper extends DBDataWrapper +{ + public function get_next($res) + { + if ($res->index < sizeof($res->data)) + return $res->data[$res->index++]; + } + + public function select($sql) + { + if ($this->config->relation_id["db_name"] == "") { + if ($sql->get_relation() == "0" || $sql->get_relation() == "") { + return new ArrayQueryWrapper($this->connection); + } else { + return new ArrayQueryWrapper(array()); + } + } + + $relation_id = $this->config->relation_id["db_name"]; + + for ($i = 0; $i < count($this->connection); $i++) { + $item = $this->connection[$i]; + if (!isset($item[$relation_id])) continue; + if ($item[$relation_id] == $sql->get_relation()) + $result[] = $item; + + } + + return new ArrayQueryWrapper($result); + } + + public function query($sql) + { + throw new Exception("Not implemented"); + } + + public function escape($value) + { + throw new Exception("Not implemented"); + } + + public function get_new_id() + { + throw new Exception("Not implemented"); + } +}
\ No newline at end of file diff --git a/codebase/DataStorage/ArrayQueryWrapper.php b/codebase/DataStorage/ArrayQueryWrapper.php new file mode 100644 index 0000000..c922bd8 --- /dev/null +++ b/codebase/DataStorage/ArrayQueryWrapper.php @@ -0,0 +1,9 @@ +<?php +namespace DHTMLX\Connector\DataStorage; + +class ArrayQueryWrapper{ + public function __construct($data){ + $this->data = $data; + $this->index = 0; + } +}
\ No newline at end of file diff --git a/codebase/DataStorage/DBDataWrapper.php b/codebase/DataStorage/DBDataWrapper.php new file mode 100644 index 0000000..1311866 --- /dev/null +++ b/codebase/DataStorage/DBDataWrapper.php @@ -0,0 +1,456 @@ +<?php +/** + * Created by PhpStorm. + * User: user + * Date: 26.3.15 + * Time: 15.50 + */ + +namespace DHTMLX\Connector\DataStorage; + +abstract class DBDataWrapper extends DataWrapper +{ + private $transaction = false; //!< type of transaction + private $sequence = false;//!< sequence name + private $sqls = array();//!< predefined sql actions + + + /*! assign named sql query + @param name + name of sql query + @param data + sql query text + */ + public function attach($name, $data) + { + $name = strtolower($name); + $this->sqls[$name] = $data; + } + + /*! replace vars in sql string with actual values + + @param matches + array of field name matches + @return + value for the var name + */ + public function get_sql_callback($matches) + { + return $this->escape($this->temp->get_value($matches[1])); + } + + public function get_sql($name, $data) + { + $name = strtolower($name); + if (!array_key_exists($name, $this->sqls)) return ""; + + + $str = $this->sqls[$name]; + $this->temp = $data; //dirty + $str = preg_replace_callback('|\{([^}]+)\}|', array($this, "get_sql_callback"), $str); + unset ($this->temp); //dirty + return $str; + } + + public function new_record_order($action, $source) + { + $order = $source->get_order(); + if ($order) { + $table = $source->get_source(); + $id = $this->config->id["db_name"]; + $idvalue = $action->get_new_id(); + + $max = $this->queryOne("SELECT MAX($order) as dhx_maxvalue FROM $table"); + $dhx_maxvalue = $max["dhx_maxvalue"] + 1; + + $this->query("UPDATE $table SET $order = $dhx_maxvalue WHERE $id = $idvalue"); + } + } + + public function order($data, $source) + { + //id of moved item + $id1 = $this->escape($data->get_value("id")); + //id of target item + $target = $data->get_value("target"); + if (strpos($target, "next:") !== false) { + $dropnext = true; + $id2 = str_replace("next:", "", $target); + } else { + $id2 = $target; + } + $id2 = $this->escape($id2); + + + //for tree like components we need to limit out queries to the affected branch only + $relation_select = $relation_update = $relation_sql_out = $relation_sql = ""; + if ($this->config->relation_id["name"]) { + $relation = $data->get_value($this->config->relation_id["name"]); + if ($relation !== false && $relation !== "") { + $relation_sql = " " . $this->config->relation_id["db_name"] . " = '" . $this->escape($relation) . "' AND "; + $relation_select = $this->config->relation_id["db_name"] . " as dhx_parent, "; + $relation_update = " " . $this->config->relation_id["db_name"] . " = '" . $this->escape($relation) . "', "; + } + } + + + $name = $source->get_order(); + $table = $source->get_source(); + $idkey = $this->config->id["db_name"]; + + $source = $this->queryOne("select $relation_select $name as dhx_index from $table where $idkey = '$id1'"); + $source_index = $source["dhx_index"] ? $source["dhx_index"] : 0; + if ($relation_sql) + $relation_sql_out = " " . $this->config->relation_id["db_name"] . " = '" . $this->escape($source["dhx_parent"]) . "' AND "; + + $this->query("update $table set $name = $name - 1 where $relation_sql_out $name >= $source_index"); + + if ($id2 !== "") { + $target = $this->queryOne("select $name as dhx_index from $table where $idkey = '$id2'"); + $target_index = $target["dhx_index"]; + if (!$target_index) + $target_index = 0; + if ($dropnext) + $target_index += 1; + $this->query("update $table set $name = $name + 1 where $relation_sql $name >= $target_index"); + } else { + $target = $this->queryOne("select max($name) as dhx_index from $table"); + $target_index = ($target["dhx_index"] ? $target["dhx_index"] : 0) + 1; + } + + $this->query("update $table set $relation_update $name = $target_index where $idkey = '$id1'"); + } + + public function insert($data, $source) + { + $sql = $this->insert_query($data, $source); + $this->query($sql); + $data->success($this->get_new_id()); + } + + public function delete($data, $source) + { + $sql = $this->delete_query($data, $source); + $this->query($sql); + $data->success(); + } + + public function update($data, $source) + { + $sql = $this->update_query($data, $source); + $this->query($sql); + $data->success(); + } + + public function select($source) + { + $select = $source->get_fieldset(); + if (!$select) { + $select = $this->config->db_names_list($this); + $select = implode(",", $select); + } + + $where = $this->build_where($source->get_filters(), $source->get_relation()); + $sort = $this->build_order($source->get_sort_by()); + + return $this->query($this->select_query($select, $source->get_source(), $where, $sort, $source->get_start(), $source->get_count())); + } + + public function queryOne($sql) + { + $res = $this->query($sql); + if ($res) + return $this->get_next($res); + return false; + } + + public function get_size($source) + { + $count = new DataRequestConfig($source); + + $count->set_fieldset("COUNT(*) as DHX_COUNT "); + $count->set_sort(null); + $count->set_limit(0, 0); + + $res = $this->select($count); + $data = $this->get_next($res); + if (array_key_exists("DHX_COUNT", $data)) return $data["DHX_COUNT"]; + else return $data["dhx_count"]; //postgresql + } + + public function get_variants($name, $source) + { + $count = new DataRequestConfig($source); + $count->set_fieldset("DISTINCT " . $this->escape_name($name) . " as value"); + $sort = new SortInterface($source); + $count->set_sort(null); + for ($i = 0; $i < count($sort->rules); $i++) { + if ($sort->rules[$i]['name'] == $name) + $count->set_sort($sort->rules[$i]['name'], $sort->rules[$i]['direction']); + } + $count->set_limit(0, 0); + return $this->select($count); + } + + public function sequence($sec) + { + $this->sequence = $sec; + } + + /*! create an sql string for filtering rules + + @param rules + set of filtering rules + @param relation + name of relation id field + @return + sql string with filtering rules + */ + protected function build_where($rules,$relation=false){ + $sql=array(); + for ($i=0; $i < sizeof($rules); $i++) + if (is_string($rules[$i])) + array_push($sql,"(".$rules[$i].")"); + else + if ($rules[$i]["value"]!=""){ + if (!$rules[$i]["operation"]) + array_push($sql,$this->escape_name($rules[$i]["name"])." LIKE '%".$this->escape($rules[$i]["value"])."%'"); + else + array_push($sql,$this->escape_name($rules[$i]["name"])." ".$rules[$i]["operation"]." '".$this->escape($rules[$i]["value"])."'"); + } + + if ($relation !== false && $relation !== ""){ + $relsql = $this->escape_name($this->config->relation_id["db_name"])." = '".$this->escape($relation)."'"; + if ($relation == "0") + $relsql = "( ".$relsql." OR ".$this->escape_name($this->config->relation_id["db_name"])." IS NULL )"; + + array_push($sql,$relsql); + } + return implode(" AND ",$sql); + } + /*! convert sorting rules to sql string + + @param by + set of sorting rules + @return + sql string for set of sorting rules + */ + protected function build_order($by){ + if (!sizeof($by)) return ""; + $out = array(); + for ($i=0; $i < sizeof($by); $i++) + if (is_string($by[$i])) + $out[] = $by[$i]; + else if ($by[$i]["name"]) + $out[]=$this->escape_name($by[$i]["name"])." ".$by[$i]["direction"]; + return implode(",",$out); + } + + /*! generates sql code for select operation + + @param select + list of fields in select + @param from + table name + @param where + list of filtering rules + @param sort + list of sorting rules + @param start + start index of fetching + @param count + count of records to fetch + @return + sql string for select operation + */ + protected function select_query($select,$from,$where,$sort,$start,$count){ + if (!$from) + return $select; + + $sql="SELECT ".$select." FROM ".$from; + if ($where) $sql.=" WHERE ".$where; + if ($sort) $sql.=" ORDER BY ".$sort; + if ($start || $count) $sql.=" LIMIT ".$start.",".$count; + return $sql; + } + /*! generates update sql + + @param data + DataAction object + @param request + DataRequestConfig object + @return + sql string, which updates record with provided data + */ + protected function update_query($data,$request){ + $sql="UPDATE ".$request->get_source()." SET "; + $temp=array(); + for ($i=0; $i < sizeof($this->config->text); $i++) { + $step=$this->config->text[$i]; + + if ($data->get_value($step["name"])===Null) + $step_value ="Null"; + else + $step_value = "'".$this->escape($data->get_value($step["name"]))."'"; + $temp[$i]= $this->escape_name($step["db_name"])."=". $step_value; + } + if ($relation = $this->config->relation_id["db_name"]){ + $temp[]= $this->escape_name($relation)."='".$this->escape($data->get_value($relation))."'"; + } + $sql.=implode(",",$temp)." WHERE ".$this->escape_name($this->config->id["db_name"])."='".$this->escape($data->get_id())."'"; + + //if we have limited set - set constraints + $where=$this->build_where($request->get_filters()); + if ($where) $sql.=" AND (".$where.")"; + + return $sql; + } + + /*! generates delete sql + + @param data + DataAction object + @param request + DataRequestConfig object + @return + sql string, which delete record + */ + protected function delete_query($data,$request){ + $sql="DELETE FROM ".$request->get_source(); + $sql.=" WHERE ".$this->escape_name($this->config->id["db_name"])."='".$this->escape($data->get_id())."'"; + + //if we have limited set - set constraints + $where=$this->build_where($request->get_filters()); + if ($where) $sql.=" AND (".$where.")"; + + return $sql; + } + + /*! generates insert sql + + @param data + DataAction object + @param request + DataRequestConfig object + @return + sql string, which inserts new record with provided data + */ + protected function insert_query($data,$request){ + $temp_n=array(); + $temp_v=array(); + foreach($this->config->text as $k => $v){ + $temp_n[$k]=$this->escape_name($v["db_name"]); + if ($data->get_value($v["name"])===Null) + $temp_v[$k]="Null"; + else + $temp_v[$k]="'".$this->escape($data->get_value($v["name"]))."'"; + } + if ($relation = $this->config->relation_id["db_name"]){ + $temp_n[]=$this->escape_name($relation); + $temp_v[]="'".$this->escape($data->get_value($relation))."'"; + } + if ($this->sequence){ + $temp_n[]=$this->escape_name($this->config->id["db_name"]); + $temp_v[]=$this->sequence; + } + + $sql="INSERT INTO ".$request->get_source()."(".implode(",",$temp_n).") VALUES (".implode(",",$temp_v).")"; + + return $sql; + } + + /*! sets the transaction mode, used by dataprocessor + + @param mode + mode name + */ + public function set_transaction_mode($mode){ + if ($mode!="none" && $mode!="global" && $mode!="record") + throw new Exception("Unknown transaction mode"); + $this->transaction=$mode; + } + /*! returns true if global transaction mode was specified + @return + true if global transaction mode was specified + */ + public function is_global_transaction(){ + return $this->transaction == "global"; + } + /*! returns true if record transaction mode was specified + @return + true if record transaction mode was specified + */ + public function is_record_transaction(){ + return $this->transaction == "record"; + } + + + public function begin_transaction(){ + $this->query("BEGIN"); + } + public function commit_transaction(){ + $this->query("COMMIT"); + } + public function rollback_transaction(){ + $this->query("ROLLBACK"); + } + + /*! exec sql string + + @param sql + sql string + @return + sql result set + */ + abstract public function query($sql); + /*! returns next record from result set + + @param res + sql result set + @return + hash of data + */ + abstract public function get_next($res); + /*! returns new id value, for newly inserted row + @return + new id value, for newly inserted row + */ + abstract public function get_new_id(); + /*! escape data to prevent sql injections + @param data + unescaped data + @return + escaped data + */ + abstract public function escape($data); + + /*! escape field name to prevent sql reserved words conflict + @param data + unescaped data + @return + escaped data + */ + public function escape_name($data){ + return $data; + } + + /*! get list of tables in the database + + @return + array of table names + */ + public function tables_list() { + throw new Exception("Not implemented"); + } + + /*! returns list of fields for the table in question + + @param table + name of table in question + @return + array of field names + */ + public function fields_list($table) { + throw new Exception("Not implemented"); + } +}
\ No newline at end of file diff --git a/codebase/DataStorage/DataConfig.php b/codebase/DataStorage/DataConfig.php new file mode 100644 index 0000000..c10fd2d --- /dev/null +++ b/codebase/DataStorage/DataConfig.php @@ -0,0 +1,227 @@ +<?php + +namespace DHTMLX\Connector\DataStorage; +/*! manager of data configuration +**/ +class DataConfig{ + public $id;////!< name of ID field + public $relation_id;//!< name or relation ID field + public $text;//!< array of text fields + public $data;//!< array of all known fields , fields which exists only in this collection will not be included in dataprocessor's operations + + + /*! converts self to the string, for logging purposes + **/ + public function __toString(){ + $str="ID:{$this->id['db_name']}(ID:{$this->id['name']})\n"; + $str.="Relation ID:{$this->relation_id['db_name']}({$this->relation_id['name']})\n"; + $str.="Data:"; + for ($i=0; $i<sizeof($this->text); $i++) + $str.="{$this->text[$i]['db_name']}({$this->text[$i]['name']}),"; + + $str.="\nExtra:"; + for ($i=0; $i<sizeof($this->data); $i++) + $str.="{$this->data[$i]['db_name']}({$this->data[$i]['name']}),"; + + return $str; + } + + /*! removes un-used fields from configuration + @param name + name of field , which need to be preserved + */ + public function minimize($name){ + for ($i=0; $i < sizeof($this->text); $i++){ + if ($this->text[$i]["db_name"]==$name || $this->text[$i]["name"]==$name){ + $this->text[$i]["name"]="value"; + $this->data=array($this->text[$i]); + $this->text=array($this->text[$i]); + return; + } + } + throw new Exception("Incorrect dataset minimization, master field not found."); + } + + public function limit_fields($data){ + if (isset($this->full_field_list)) + $this->restore_fields(); + $this->full_field_list = $this->text; + $this->text = array(); + + for ($i=0; $i < sizeof($this->full_field_list); $i++) { + if (array_key_exists($this->full_field_list[$i]["name"],$data)) + $this->text[] = $this->full_field_list[$i]; + } + } + + public function restore_fields(){ + if (isset($this->full_field_list)) + $this->text = $this->full_field_list; + } + + /*! initialize inner state by parsing configuration parameters + + @param id + name of id field + @param fields + name of data field(s) + @param extra + name of extra field(s) + @param relation + name of relation field + + */ + public function init($id,$fields,$extra,$relation){ + $this->id = $this->parse($id,false); + $this->text = $this->parse($fields,true); + $this->data = array_merge($this->text,$this->parse($extra,true)); + $this->relation_id = $this->parse($relation,false); + } + + /*! parse configuration string + + @param key + key string from configuration + @param mode + multi names flag + @return + parsed field name object + */ + private function parse($key,$mode){ + if ($mode){ + if (!$key) return array(); + $key=explode(",",$key); + for ($i=0; $i < sizeof($key); $i++) + $key[$i]=$this->parse($key[$i],false); + return $key; + } + $key=explode("(",$key); + $data=array("db_name"=>trim($key[0]), "name"=>trim($key[0])); + if (sizeof($key)>1) + $data["name"]=substr(trim($key[1]),0,-1); + return $data; + } + + /*! constructor + init public collectons + @param proto + DataConfig object used as prototype for new one, optional + */ + public function __construct($proto=false){ + if ($proto!==false) + $this->copy($proto); + else { + $this->text=array(); + $this->data=array(); + $this->id=array("name"=>"dhx_auto_id", "db_name"=>"dhx_auto_id"); + $this->relation_id=array("name"=>"", "db_name"=>""); + } + } + + /*! copy properties from source object + + @param proto + source object + */ + public function copy($proto){ + $this->id = $proto->id; + $this->relation_id = $proto->relation_id; + $this->text = $proto->text; + $this->data = $proto->data; + } + + /*! returns list of data fields (db_names) + @return + list of data fields ( ready to be used in SQL query ) + */ + public function db_names_list($db){ + $out=array(); + if ($this->id["db_name"]) + array_push($out,$db->escape_name($this->id["db_name"])); + if ($this->relation_id["db_name"]) + array_push($out,$db->escape_name($this->relation_id["db_name"])); + + for ($i=0; $i < sizeof($this->data); $i++){ + if ($this->data[$i]["db_name"]!=$this->data[$i]["name"]) + $out[]=$db->escape_name($this->data[$i]["db_name"])." as ".$this->data[$i]["name"]; + else + $out[]=$db->escape_name($this->data[$i]["db_name"]); + } + + return $out; + } + + /*! add field to dataset config ($text collection) + + added field will be used in all auto-generated queries + @param name + name of field + @param aliase + aliase of field, optional + */ + public function add_field($name,$aliase=false){ + if ($aliase===false) $aliase=$name; + + //adding to list of data-active fields + if ($this->id["db_name"]==$name || $this->relation_id["db_name"] == $name){ + LogMaster::log("Field name already used as ID, be sure that it is really necessary."); + } + if ($this->is_field($name,$this->text)!=-1) + throw new Exception('Data field already registered: '.$name); + array_push($this->text,array("db_name"=>$name,"name"=>$aliase)); + + //adding to list of all fields as well + if ($this->is_field($name,$this->data)==-1) + array_push($this->data,array("db_name"=>$name,"name"=>$aliase)); + + } + + /*! remove field from dataset config ($text collection) + + removed field will be excluded from all auto-generated queries + @param name + name of field, or aliase of field + */ + public function remove_field($name){ + $ind = $this->is_field($name); + if ($ind==-1) throw new Exception('There was no such data field registered as: '.$name); + array_splice($this->text,$ind,1); + //we not deleting field from $data collection, so it will not be included in data operation, but its data still available + } + + /*! remove field from dataset config ($text and $data collections) + + removed field will be excluded from all auto-generated queries + @param name + name of field, or aliase of field + */ + public function remove_field_full($name){ + $ind = $this->is_field($name); + if ($ind==-1) throw new Exception('There was no such data field registered as: '.$name); + array_splice($this->text,$ind,1); + + $ind = $this->is_field($name, $this->data); + if ($ind==-1) throw new Exception('There was no such data field registered as: '.$name); + array_splice($this->data,$ind,1); + } + + /*! check if field is a part of dataset + + @param name + name of field + @param collection + collection, against which check will be done, $text collection by default + @return + returns true if field already a part of dataset, otherwise returns true + */ + public function is_field($name,$collection = false){ + if (!$collection) + $collection=$this->text; + + for ($i=0; $i<sizeof($collection); $i++) + if ($collection[$i]["name"] == $name || $collection[$i]["db_name"] == $name) return $i; + return -1; + } + + +}
\ No newline at end of file diff --git a/codebase/DataStorage/DataRequestConfig.php b/codebase/DataStorage/DataRequestConfig.php new file mode 100644 index 0000000..bb2c750 --- /dev/null +++ b/codebase/DataStorage/DataRequestConfig.php @@ -0,0 +1,284 @@ +<?php + +namespace DHTMLX\Connector\DataStorage; + +/*! manager of data request +**/ +class DataRequestConfig{ + private $filters; //!< array of filtering rules + private $relation=false; //!< ID or other element used for linking hierarchy + private $sort_by; //!< sorting field + private $start; //!< start of requested data + private $count; //!< length of requested data + + private $order = false; + private $user; + private $version; + + //for render_sql + private $source; //!< souce table or another source destination + private $fieldset; //!< set of data, which need to be retrieved from source + + /*! constructor + + @param proto + DataRequestConfig object, optional, if provided then new request object will copy all properties from provided one + */ + public function __construct($proto=false){ + if ($proto) + $this->copy($proto); + else{ + $start=0; + $this->filters=array(); + $this->sort_by=array(); + } + } + + /*! copy parameters of source object into self + + @param proto + source object + */ + public function copy($proto){ + $this->filters =$proto->get_filters(); + $this->sort_by =$proto->get_sort_by(); + $this->count =$proto->get_count(); + $this->start =$proto->get_start(); + $this->source =$proto->get_source(); + $this->fieldset =$proto->get_fieldset(); + $this->relation =$proto->get_relation(); + $this->user = $proto->user; + $this->version = $proto->version; + } + + /*! convert self to string ( for logs ) + @return + self as plain string, + */ + public function __toString(){ + $str="Source:{$this->source}\nFieldset:{$this->fieldset}\nWhere:"; + for ($i=0; $i < sizeof($this->filters); $i++) + $str.=$this->filters[$i]["name"]." ".$this->filters[$i]["operation"]." ".$this->filters[$i]["value"].";"; + $str.="\nStart:{$this->start}\nCount:{$this->count}\n"; + for ($i=0; $i < sizeof($this->sort_by); $i++) + $str.=$this->sort_by[$i]["name"]."=".$this->sort_by[$i]["direction"].";"; + $str.="\nRelation:{$this->relation}"; + return $str; + } + + /*! returns set of filtering rules + @return + set of filtering rules + */ + public function get_filters(){ + return $this->filters; + } + public function &get_filters_ref(){ + return $this->filters; + } + public function set_filters($data){ + $this->filters=$data; + } + + + public function get_order(){ + return $this->order; + } + public function set_order($order){ + $this->order = $order; + } + public function get_user(){ + return $this->user; + } + public function set_user($user){ + $this->user = $user; + } + public function get_version(){ + return $this->version; + } + public function set_version($version){ + $this->version = $version; + } + + /*! returns list of used fields + @return + list of used fields + */ + public function get_fieldset(){ + return $this->fieldset; + } + /*! returns name of source table + @return + name of source table + */ + public function get_source(){ + return $this->source; + } + /*! returns set of sorting rules + @return + set of sorting rules + */ + public function get_sort_by(){ + return $this->sort_by; + } + public function &get_sort_by_ref(){ + return $this->sort_by; + } + public function set_sort_by($data){ + $this->sort_by=$data; + } + + /*! returns start index + @return + start index + */ + public function get_start(){ + return $this->start; + } + /*! returns count of requested records + @return + count of requested records + */ + public function get_count(){ + return $this->count; + } + /*! returns name of relation id + @return + relation id name + */ + public function get_relation(){ + return $this->relation; + } + + /*! sets sorting rule + + @param field + name of column + @param order + direction of sorting + */ + public function set_sort($field,$order=false){ + if (!$field && !$order) + $this->sort_by=array(); + else{ + if ($order===false) + $this->sort_by[] = $field; + else { + $order=strtolower($order)=="asc"?"ASC":"DESC"; + $this->sort_by[]=array("name"=>$field,"direction" => $order); + } + } + } + /*! sets filtering rule + + @param field + name of column + @param value + value for filtering + @param operation + operation for filtering, optional , LIKE by default + */ + public function set_filter($field,$value=false,$operation=false){ + if ($value === false) + array_push($this->filters,$field); + else + array_push($this->filters,array("name"=>$field,"value"=>$value,"operation"=>$operation)); + } + + /*! sets list of used fields + + @param value + list of used fields + */ + public function set_fieldset($value){ + $this->fieldset=$value; + } + /*! sets name of source table + + @param value + name of source table + */ + public function set_source($value){ + if (is_string($value)) + $value = trim($value); + $this->source = $value; + if (!$this->source) throw new Exception("Source of data can't be empty"); + } + /*! sets data limits + + @param start + start index + @param count + requested count of data + */ + public function set_limit($start,$count){ + $this->start=$start; + $this->count=$count; + } + /*! sets name of relation id + + @param value + name of relation id field + */ + public function set_relation($value){ + $this->relation=$value; + } + /*! parse incoming sql, to fill other properties + + @param sql + incoming sql string + */ + public function parse_sql($sql, $as_is = false){ + if ($as_is){ + $this->fieldset = $sql; + return; + } + + $sql= preg_replace("/[ \n\t]+limit[\n\t ,0-9]*$/i","",$sql); + + $data = preg_split("/[ \n\t]+\\_from\\_/i",$sql,2); + if (count($data)!=2) + $data = preg_split("/[ \n\t]+from/i",$sql,2); + $this->fieldset = preg_replace("/^[\s]*select/i","",$data[0],1); + + //Ignore next type of calls + //direct call to stored procedure without FROM + if ((count($data) == 1) || + //UNION select + preg_match("#[ \n\r\t]union[ \n\t\r]#i", $sql)){ + $this->fieldset = $sql; + return; + } + + $table_data = preg_split("/[ \n\t]+where/i",$data[1],2); + /* + if sql code contains group_by we will place all sql query in the FROM + it will not allow to use any filtering against the query + still it is better than just generate incorrect sql commands for any group by query + */ + if (sizeof($table_data)>1 && !preg_match("#.*group by.*#i",$table_data[1])){ //where construction exists + $this->set_source($table_data[0]); + $where_data = preg_split("/[ \n\t]+order[ ]+by/i",$table_data[1],2); + $this->filters[]=$where_data[0]; + if (sizeof($where_data)==1) return; //end of line detected + $data=$where_data[1]; + } else { + $table_data = preg_split("/[ \n\t]+order[ ]+by/i",$data[1],2); + $this->set_source($table_data[0]); + if (sizeof($table_data)==1) return; //end of line detected + $data=$table_data[1]; + } + + if (trim($data)){ //order by construction exists + $s_data = preg_split("/\\,/",trim($data)); + for ($i=0; $i < count($s_data); $i++) { + $data=preg_split("/[ ]+/",trim($s_data[$i]),2); + if (sizeof($data)>1) + $this->set_sort($data[0],$data[1]); + else + $this->set_sort($data[0]); + } + + } + } +}
\ No newline at end of file diff --git a/codebase/DataStorage/DataWrapper.php b/codebase/DataStorage/DataWrapper.php new file mode 100644 index 0000000..19158cc --- /dev/null +++ b/codebase/DataStorage/DataWrapper.php @@ -0,0 +1,100 @@ +<?php + +namespace DHTMLX\Connector\DataStorage; +/*! Base abstraction class, used for data operations + Class abstract access to data, it is a base class to all DB wrappers +**/ +abstract class DataWrapper{ + protected $connection; + protected $config;//!< DataConfig instance + /*! constructor + @param connection + DB connection + @param config + DataConfig instance + */ + public function __construct($connection = false,$config = false){ + $this->config=$config; + $this->connection=$connection; + } + + /*! insert record in storage + + @param data + DataAction object + @param source + DataRequestConfig object + */ + abstract function insert($data,$source); + + /*! delete record from storage + + @param data + DataAction object + @param source + DataRequestConfig object + */ + abstract function delete($data,$source); + + /*! update record in storage + + @param data + DataAction object + @param source + DataRequestConfig object + */ + abstract function update($data,$source); + + /*! select record from storage + + @param source + DataRequestConfig object + */ + abstract function select($source); + + /*! get size of storage + + @param source + DataRequestConfig object + */ + abstract function get_size($source); + + /*! get all variations of field in storage + + @param name + name of field + @param source + DataRequestConfig object + */ + abstract function get_variants($name,$source); + + /*! checks if there is a custom sql string for specified db operation + + @param name + name of DB operation + @param data + hash of data + @return + sql string + */ + public function get_sql($name,$data){ + return ""; //custom sql not supported by default + } + + /*! begins DB transaction + */ + public function begin_transaction(){ + throw new Exception("Data wrapper not supports transactions."); + } + /*! commits DB transaction + */ + public function commit_transaction(){ + throw new Exception("Data wrapper not supports transactions."); + } + /*! rollbacks DB transaction + */ + public function rollback_transaction(){ + throw new Exception("Data wrapper not supports transactions."); + } +} + diff --git a/codebase/DataStorage/MsSQLDBDataWrapper.php b/codebase/DataStorage/MsSQLDBDataWrapper.php new file mode 100644 index 0000000..1d245b2 --- /dev/null +++ b/codebase/DataStorage/MsSQLDBDataWrapper.php @@ -0,0 +1,78 @@ +<?php + +namespace DHTMLX\Connector\DataStorage; + +use DHTMLX\Connector\Tools\LogMaster; + +class MsSQLDBDataWrapper extends DBDataWrapper +{ + private $last_id = ""; //!< ID of previously inserted record + private $insert_operation = false; //!< flag of insert operation + private $start_from = false; //!< index of start position + + public function query($sql) + { + LogMaster::log($sql); + $res = mssql_query($sql, $this->connection); + if ($this->insert_operation) { + $last = mssql_fetch_assoc($res); + $this->last_id = $last["dhx_id"]; + mssql_free_result($res); + } + if ($this->start_from) + mssql_data_seek($res, $this->start_from); + return $res; + } + + public function get_next($res) + { + return mssql_fetch_assoc($res); + } + + public function get_new_id() + { + /* + MSSQL doesn't support identity or auto-increment fields + Insert SQL returns new ID value, which stored in last_id field + */ + return $this->last_id; + } + + protected function insert_query($data, $request) + { + $sql = parent::insert_query($data, $request); + $this->insert_operation = true; + return $sql . ";SELECT @@IDENTITY AS dhx_id"; + } + + protected function select_query($select, $from, $where, $sort, $start, $count) + { + if (!$from) + return $select; + + $sql = "SELECT "; + if ($count) + $sql .= " TOP " . ($count + $start); + $sql .= " " . $select . " FROM " . $from; + if ($where) $sql .= " WHERE " . $where; + if ($sort) $sql .= " ORDER BY " . $sort; + if ($start && $count) + $this->start_from = $start; + else + $this->start_from = false; + return $sql; + } + + public function escape($data) + { + /* + there is no special escaping method for mssql - use common logic + */ + return str_replace("'", "''", $data); + } + + public function begin_transaction() + { + $this->query("BEGIN TRAN"); + } +}
\ No newline at end of file diff --git a/codebase/DataStorage/MySQLDBDataWrapper.php b/codebase/DataStorage/MySQLDBDataWrapper.php new file mode 100644 index 0000000..3f13492 --- /dev/null +++ b/codebase/DataStorage/MySQLDBDataWrapper.php @@ -0,0 +1,69 @@ +<?php +namespace DHTMLX\Connector\DataStorage; + + +/*! Implementation of DataWrapper for MySQL +**/ +class MySQLDBDataWrapper extends DBDataWrapper{ + protected $last_result; + public function query($sql){ + LogMaster::log($sql); + $res=mysql_query($sql,$this->connection); + if ($res===false) throw new Exception("MySQL operation failed\n".mysql_error($this->connection)); + $this->last_result = $res; + return $res; + } + + public function get_next($res){ + if (!$res) + $res = $this->last_result; + + return mysql_fetch_assoc($res); + } + + public function get_new_id(){ + return mysql_insert_id($this->connection); + } + + public function escape($data){ + return mysql_real_escape_string($data, $this->connection); + } + + public function tables_list() { + $result = mysql_query("SHOW TABLES"); + if ($result===false) throw new Exception("MySQL operation failed\n".mysql_error($this->connection)); + + $tables = array(); + while ($table = mysql_fetch_array($result)) { + $tables[] = $table[0]; + } + return $tables; + } + + public function fields_list($table) { + $result = mysql_query("SHOW COLUMNS FROM `".$table."`"); + if ($result===false) throw new Exception("MySQL operation failed\n".mysql_error($this->connection)); + + $fields = array(); + $id = ""; + while ($field = mysql_fetch_assoc($result)) { + if ($field['Key'] == "PRI") + $id = $field["Field"]; + else + $fields[] = $field["Field"]; + } + return array("fields" => $fields, "key" => $id ); + } + + /*! escape field name to prevent sql reserved words conflict + @param data + unescaped data + @return + escaped data + */ + public function escape_name($data){ + if ((strpos($data,"`")!==false || is_int($data)) || (strpos($data,".")!==false)) + return $data; + return '`'.$data.'`'; + } +}
\ No newline at end of file diff --git a/codebase/db_pdo.php b/codebase/DataStorage/PDODBDataWrapper.php index 1417462..5a08e57 100644 --- a/codebase/db_pdo.php +++ b/codebase/DataStorage/PDODBDataWrapper.php @@ -1,32 +1,30 @@ <?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("db_common.php"); + +namespace DHTMLX\Connector\DataStorage; + /*! Implementation of DataWrapper for PDO if you plan to use it for Oracle - use Oracle connection type instead **/ class PDODBDataWrapper extends DBDataWrapper{ private $last_result;//!< store result or last operation - + public function query($sql){ LogMaster::log($sql); - + $res=$this->connection->query($sql); if ($res===false) { $message = $this->connection->errorInfo(); throw new Exception("PDO - sql execution failed\n".$message[2]); } - + return new PDOResultSet($res); } protected function select_query($select,$from,$where,$sort,$start,$count){ if (!$from) return $select; - + $sql="SELECT ".$select." FROM ".$from; if ($where) $sql.=" WHERE ".$where; if ($sort) $sql.=" ORDER BY ".$sort; @@ -38,7 +36,7 @@ class PDODBDataWrapper extends DBDataWrapper{ } return $sql; } - + public function tables_list() { $result = $this->query("SHOW TABLES"); if ($result===false) throw new Exception("MySQL operation failed\n".mysql_error($this->connection)); @@ -55,46 +53,30 @@ class PDODBDataWrapper extends DBDataWrapper{ if ($result===false) throw new Exception("MySQL operation failed\n".mysql_error($this->connection)); $fields = array(); - $id = ""; + $id = ""; while ($field = $result->next()) { if ($field['Key'] == "PRI") $id = $field["Field"]; - else - $fields[] = $field["Field"]; + else + $fields[] = $field["Field"]; } return array("fields" => $fields, "key" => $id ); } - + public function get_next($res){ $data = $res->next(); return $data; } - + public function get_new_id(){ return $this->connection->lastInsertId(); } - + public function escape($str){ $res=$this->connection->quote($str); if ($res===false) //not supported by pdo driver - return str_replace("'","''",$str); + return str_replace("'","''",$str); return substr($res,1,-1); } - -} -class PDOResultSet{ - private $res; - public function __construct($res){ - $this->res = $res; - } - public function next(){ - $data = $this->res->fetch(PDO::FETCH_ASSOC); - if (!$data){ - $this->res->closeCursor(); - return null; - } - return $data; - } -} -?>
\ No newline at end of file +}
\ No newline at end of file diff --git a/codebase/DataStorage/PDOResultSet.php b/codebase/DataStorage/PDOResultSet.php new file mode 100644 index 0000000..536f75c --- /dev/null +++ b/codebase/DataStorage/PDOResultSet.php @@ -0,0 +1,18 @@ +<?php + +namespace DHTMLX\Connector\DataStorage; + +class PDOResultSet{ + private $res; + public function __construct($res){ + $this->res = $res; + } + public function next(){ + $data = $this->res->fetch(PDO::FETCH_ASSOC); + if (!$data){ + $this->res->closeCursor(); + return null; + } + return $data; + } +}
\ No newline at end of file diff --git a/codebase/db_phpyii.php b/codebase/DataStorage/PHPYii2DBDataWrapper.php index 616d7f3..95af1b7 100644 --- a/codebase/db_phpyii.php +++ b/codebase/DataStorage/PHPYii2DBDataWrapper.php @@ -1,28 +1,25 @@ <?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ +namespace DHTMLX\Connector\DataStorage; -require_once("db_common.php"); +class PHPYii2DBDataWrapper extends ArrayDBDataWrapper { -class PHPYiiDBDataWrapper extends ArrayDBDataWrapper{ public function select($sql){ if (is_array($this->connection)) //result of findAll $res = $this->connection; else - $res = $this->connection->findAll(); + $res = $this->connection->find()->all(); $temp = array(); if (sizeof($res)){ foreach ($res as $obj) $temp[]=$obj->getAttributes(); } + //die(var_dump($temp)); return new ArrayQueryWrapper($temp); } protected function getErrorMessage(){ - $errors = $this->connection->invalidFields(); + $errors = $this->connection->getErrors(); $text = array(); foreach ($errors as $key => $value){ $text[] = $key." - ".$value[0]; @@ -32,11 +29,11 @@ class PHPYiiDBDataWrapper extends ArrayDBDataWrapper{ public function insert($data,$source){ $name = get_class($this->connection); $obj = new $name(); - + //die(var_dump($data)); $this->fill_model_and_save($obj, $data); } public function delete($data,$source){ - $obj = $this->connection->findByPk($data->get_id()); + $obj = $this->connection->findOne($data->get_id()); if ($obj->delete()){ $data->success(); $data->set_new_id($obj->getPrimaryKey()); @@ -46,18 +43,22 @@ class PHPYiiDBDataWrapper extends ArrayDBDataWrapper{ } } public function update($data,$source){ - $obj = $this->connection->findByPk($data->get_id()); + //$obj = get_class($this->connection); + //$obj->setAttribute($obj->getPrimaryKey); + + $obj = $this->connection->findOne($data->get_id()); +; $this->fill_model_and_save($obj, $data); - } + } protected function fill_model_and_save($obj, $data){ - $values = $data->get_data(); //map data to model object for ($i=0; $i < sizeof($this->config->text); $i++){ $step=$this->config->text[$i]; - $obj->setAttribute($step["name"], $data->get_value($step["name"])); + $obj->setAttribute($step["name"], $data->get_value("c".$i)); //TODO make array with corresponding names } + if ($relation = $this->config->relation_id["db_name"]) $obj->setAttribute($relation, $data->get_value($relation)); @@ -86,6 +87,5 @@ class PHPYiiDBDataWrapper extends ArrayDBDataWrapper{ public function get_new_id(){ throw new Exception("Not implemented"); } -} -?>
\ No newline at end of file +}
\ No newline at end of file diff --git a/codebase/DataStorage/PostgreDBDataWrapper.php b/codebase/DataStorage/PostgreDBDataWrapper.php new file mode 100644 index 0000000..56eaa48 --- /dev/null +++ b/codebase/DataStorage/PostgreDBDataWrapper.php @@ -0,0 +1,70 @@ +<?php + +namespace DHTMLX\Connector\DataStorage; + +use DHTMLX\Connector\Tools\LogMaster; + +class PostgreDBDataWrapper extends DBDataWrapper{ + public function query($sql){ + LogMaster::log($sql); + + $res=pg_query($this->connection,$sql); + if ($res===false) throw new \Exception("Postgre - sql execution failed\n".pg_last_error($this->connection)); + + return $res; + } + + protected function select_query($select,$from,$where,$sort,$start,$count){ + if (!$from) + return $select; + + $sql="SELECT ".$select." FROM ".$from; + if ($where) $sql.=" WHERE ".$where; + if ($sort) $sql.=" ORDER BY ".$sort; + if ($start || $count) + $sql.=" OFFSET ".$start." LIMIT ".$count; + return $sql; + } + + public function get_next($res){ + return pg_fetch_assoc($res); + } + + public function get_new_id(){ + $res = pg_query( $this->connection, "SELECT LASTVAL() AS seq"); + $data = pg_fetch_assoc($res); + pg_free_result($res); + return $data['seq']; + } + + public function escape($data){ + //need to use oci_bind_by_name + return pg_escape_string($this->connection,$data); + } + + public function tables_list() { + $sql = "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'"; + $res = pg_query($this->connection, $sql); + $tables = array(); + while ($table = pg_fetch_assoc($res)) { + $tables[] = $table['table_name']; + } + return $tables; + } + + public function fields_list($table) { + $sql = "SELECT * FROM information_schema.constraint_column_usage"; + $result = pg_query($this->connection, $sql); + $field = pg_fetch_assoc($result); + $id = $field['column_name']; + + $sql = "SELECT * FROM information_schema.columns WHERE table_name ='".$table."';"; + $result = pg_query($this->connection, $sql); + $fields = array(); + $id = ""; + while ($field = pg_fetch_assoc($result)) { + $fields[] = $field["column_name"]; + } + return array('fields' => $fields, 'key' => $id ); + } +}
\ No newline at end of file diff --git a/codebase/DistinctOptionsConnector.php b/codebase/DistinctOptionsConnector.php new file mode 100644 index 0000000..273ec6b --- /dev/null +++ b/codebase/DistinctOptionsConnector.php @@ -0,0 +1,18 @@ +<?php +namespace DHTMLX\Connector; + +class DistinctOptionsConnector extends OptionsConnector{ + /*! render self + process commands, return data as XML, not output data to stdout, ignore parameters in incoming request + @return + data as XML string + */ + public function render(){ + if (!$this->init_flag){ + $this->init_flag=true; + return ""; + } + $res = $this->sql->get_variants($this->config->text[0]["db_name"],$this->request); + return $this->render_set($res); + } +}
\ No newline at end of file diff --git a/codebase/Event/EventInterface.php b/codebase/Event/EventInterface.php new file mode 100644 index 0000000..645d89b --- /dev/null +++ b/codebase/Event/EventInterface.php @@ -0,0 +1,37 @@ +<?php +namespace DHTMLX\Connector\Event; + +class EventInterface{ + protected $request; ////!< DataRequestConfig instance + public $rules=array(); //!< array of sorting rules + + /*! constructor + creates a new interface based on existing request + @param request + DataRequestConfig object + */ + public function __construct($request){ + $this->request = $request; + } + + /*! remove all elements from collection + */ + public function clear(){ + array_splice($rules,0); + } + /*! get index by name + + @param name + name of field + @return + index of named field + */ + public function index($name){ + $len = sizeof($this->rules); + for ($i=0; $i < $len; $i++) { + if ($this->rules[$i]["name"]==$name) + return $i; + } + return false; + } +} diff --git a/codebase/Event/FilterInterface.php b/codebase/Event/FilterInterface.php new file mode 100644 index 0000000..e37489d --- /dev/null +++ b/codebase/Event/FilterInterface.php @@ -0,0 +1,32 @@ +<?php + +namespace DHTMLX\Connector\Event; + +/*! Wrapper for collection of filtering rules +**/ +class FilterInterface extends EventInterface{ + /*! constructor + creates a new interface based on existing request + @param request + DataRequestConfig object + */ + public function __construct($request){ + $this->request = $request; + $this->rules = &$request->get_filters_ref(); + } + /*! add new filatering rule + + @param name + name of field + @param value + value to filter by + @param rule + filtering rule + */ + public function add($name,$value,$rule){ + $this->request->set_filter($name,$value,$rule); + } + public function store(){ + $this->request->set_filters($this->rules); + } +}
\ No newline at end of file diff --git a/codebase/Event/SortInterface.php b/codebase/Event/SortInterface.php new file mode 100644 index 0000000..5e6aef4 --- /dev/null +++ b/codebase/Event/SortInterface.php @@ -0,0 +1,31 @@ +<?php + +namespace DHTMLX\Connector\Event; + +class SortInterface extends EventInterface{ + /*! constructor + creates a new interface based on existing request + @param request + DataRequestConfig object + */ + public function __construct($request){ + parent::__construct($request); + $this->rules = &$request->get_sort_by_ref(); + } + /*! add new sorting rule + + @param name + name of field + @param dir + direction of sorting + */ + public function add($name,$dir){ + if ($dir === false) + $this->request->set_sort($name); + else + $this->request->set_sort($name,$dir); + } + public function store(){ + $this->request->set_sort_by($this->rules); + } +}
\ No newline at end of file diff --git a/codebase/GridConfiguration.php b/codebase/GridConfiguration.php new file mode 100644 index 0000000..d67a0b6 --- /dev/null +++ b/codebase/GridConfiguration.php @@ -0,0 +1,445 @@ +<?php +namespace DHTMLX\Connector; + +class GridConfiguration +{ + + /*! attaching header functionality + */ + protected $headerDelimiter = ','; + protected $headerNames = false; + protected $headerAttaches = array(); + protected $footerAttaches = array(); + protected $headerWidthsUnits = 'px'; + + protected $headerIds = false; + protected $headerWidths = false; + protected $headerTypes = false; + protected $headerAlign = false; + protected $headerVAlign = false; + protected $headerSorts = false; + protected $headerColors = false; + protected $headerHidden = false; + protected $headerFormat = false; + + protected $convert_mode = false; + + function __construct($headers = false) + { + if ($headers === false || $headers === true) + $this->headerNames = $headers; + else + $this->setHeader($headers); + } + + /*! brief convert list of parameters to an array + @param param + list of values or array of values + @return array of parameters + */ + private function parse_param_array($param, $check = false, $default = "") + { + if (gettype($param) == 'string') + $param = explode($this->headerDelimiter, $param); + + if ($check) { + for ($i = 0; $i < sizeof($param); $i++) { + if (!array_key_exists($param[$i], $check)) + $param[$i] = $default; + } + } + return $param; + } + + /*! sets delimiter for string arguments in attach header functions (default is ,) + @param headerDelimiter + string delimiter + */ + public function setHeaderDelimiter($headerDelimiter) + { + $this->headerDelimiter = $headerDelimiter; + } + + /*! sets header + @param names + array of names or string of names, delimited by headerDelimiter (default is ,) + */ + public function setHeader($names) + { + if ($names instanceof DataConfig) { + $out = array(); + for ($i = 0; $i < sizeof($names->text); $i++) + $out[] = $names->text[$i]["name"]; + $names = $out; + } + + $this->headerNames = $this->parse_param_array($names); + } + + /*! sets init columns width in pixels + @param wp + array of widths or string of widths, delimited by headerDelimiter (default is ,) + */ + public function setInitWidths($wp) + { + $this->headerWidths = $this->parse_param_array($wp); + $this->headerWidthsUnits = 'px'; + } + + /*! sets init columns width in persents + @param wp + array of widths or string of widths, delimited by headerDelimiter (default is ,) + */ + public function setInitWidthsP($wp) + { + $this->setInitWidths($wp); + $this->headerWidthsUnits = '%'; + } + + /*! sets columns align + @param alStr + array of aligns or string of aligns, delimited by headerDelimiter (default is ,) + */ + public function setColAlign($alStr) + { + $this->headerAlign = $this->parse_param_array($alStr, + array("right" => 1, "left" => 1, "center" => 1, "justify" => 1), + "left"); + } + + /*! sets columns vertical align + @param alStr + array of vertical aligns or string of vertical aligns, delimited by headerDelimiter (default is ,) + */ + public function setColVAlign($alStr) + { + $this->headerVAlign = $this->parse_param_array($alStr, + array("baseline" => 1, "sub" => 1, "super" => 1, "top" => 1, "text-top" => 1, "middle" => 1, "bottom" => 1, "text-bottom" => 1), + "top"); + } + + /*! sets column types + @param typeStr + array of types or string of types, delimited by headerDelimiter (default is ,) + */ + public function setColTypes($typeStr) + { + $this->headerTypes = $this->parse_param_array($typeStr); + } + + /*! sets columns sorting + @param sortStr + array if sortings or string of sortings, delimited by headerDelimiter (default is ,) + */ + public function setColSorting($sortStr) + { + $this->headerSorts = $this->parse_param_array($sortStr); + } + + /*! sets columns colors + @param colorStr + array of colors or string of colors, delimited by headerDelimiter (default is ,) + if (color should not be applied it's value should be null) + */ + public function setColColor($colorStr) + { + $this->headerColors = $this->parse_param_array($colorStr); + } + + /*! sets hidden columns + @param hidStr + array of bool values or string of bool values, delimited by headerDelimiter (default is ,) + */ + public function setColHidden($hidStr) + { + $this->headerHidden = $this->parse_param_array($hidStr); + } + + /*! sets columns id + @param idsStr + array of ids or string of ids, delimited by headerDelimiter (default is ,) + */ + public function setColIds($idsStr) + { + $this->headerIds = $this->parse_param_array($idsStr); + } + + /*! sets number/date format + @param formatArr + array of mask formats for number/dates , delimited by headerDelimiter (default is ,) + */ + public function setColFormat($formatArr) + { + $this->headerFormat = $this->parse_param_array($formatArr); + } + + /*! attaches header + @param values + array of header names or string of header names, delimited by headerDelimiter (default is ,) + @param styles + array of header styles or string of header styles, delimited by headerDelimiter (default is ,) + */ + public function attachHeader($values, $styles = null, $footer = false) + { + $header = array(); + $header['values'] = $this->parse_param_array($values); + if ($styles != null) { + $header['styles'] = $this->parse_param_array($styles); + } else { + $header['styles'] = null; + } + if ($footer) + $this->footerAttaches[] = $header; + else + $this->headerAttaches[] = $header; + } + + /*! attaches footer + @param values + array of footer names or string of footer names, delimited by headerDelimiter (default is ,) + @param styles + array of footer styles or string of footer styles, delimited by headerDelimiter (default is ,) + */ + public function attachFooter($values, $styles = null) + { + $this->attachHeader($values, $styles, true); + } + + private function auto_fill($mode) + { + $headerWidths = array(); + $headerTypes = array(); + $headerSorts = array(); + $headerAttaches = array(); + + for ($i = 0; $i < sizeof($this->headerNames); $i++) { + $headerWidths[] = 100; + $headerTypes[] = "ro"; + $headerSorts[] = "connector"; + $headerAttaches[] = "#connector_text_filter"; + } + if ($this->headerWidths == false) + $this->setInitWidths($headerWidths); + if ($this->headerTypes == false) + $this->setColTypes($headerTypes); + + if ($mode) { + if ($this->headerSorts == false) + $this->setColSorting($headerSorts); + $this->attachHeader($headerAttaches); + } + } + + public function defineOptions($conn) + { + if (!$conn->is_first_call()) return; //render head only for first call + + $config = $conn->get_config(); + $full_header = ($this->headerNames === true); + + if (gettype($this->headerNames) == 'boolean') //auto-config + $this->setHeader($config); + $this->auto_fill($full_header); + + if (isset($_GET["dhx_colls"])) return; + + $fillList = array(); + for ($i = 0; $i < count($this->headerNames); $i++) + if ($this->headerTypes[$i] == "co" || $this->headerTypes[$i] == "coro") + $fillList[$i] = true; + + for ($i = 0; $i < count($this->headerAttaches); $i++) { + for ($j = 0; $j < count($this->headerAttaches[$i]['values']); $j++) { + if ($this->headerAttaches[$i]['values'][$j] == "#connector_select_filter" + || $this->headerAttaches[$i]['values'][$j] == "#select_filter" + ) { + $fillList[$j] = true;; + } + } + } + + $temp = array(); + foreach ($fillList as $k => $v) + $temp[] = $k; + if (count($temp)) + $_GET["dhx_colls"] = implode(",", $temp); + } + + + /*! gets header as array + */ + private function getHeaderArray() + { + $head = Array(); + $head[0] = $this->headerNames; + $head = $this->getAttaches($head, $this->headerAttaches); + return $head; + } + + + /*! get footer as array + */ + private function getFooterArray() + { + $foot = Array(); + $foot = $this->getAttaches($foot, $this->footerAttaches); + return $foot; + } + + + /*! gets array of data with attaches + */ + private function getAttaches($to, $from) + { + for ($i = 0; $i < count($from); $i++) { + $line = $from[$i]['values']; + $to[] = $line; + } + return $to; + } + + + /*! calculates rowspan array according #cspan markers + */ + private function processCspan($data) + { + $rspan = Array(); + for ($i = 0; $i < count($data); $i++) { + $last = 0; + $rspan[$i] = Array(); + for ($j = 0; $j < count($data[$i]); $j++) { + $rspan[$i][$j] = 0; + if ($data[$i][$j] === '#cspan') { + $rspan[$i][$last]++; + } else { + $last = $j; + } + } + } + return $rspan; + } + + + /*! calculates colspan array according #rspan markers + */ + private function processRspan($data) + { + $last = Array(); + $cspan = Array(); + for ($i = 0; $i < count($data); $i++) { + $cspan[$i] = Array(); + for ($j = 0; $j < count($data[$i]); $j++) { + $cspan[$i][$j] = 0; + if (!isset($last[$j])) $last[$j] = 0; + if ($data[$i][$j] === '#rspan') { + $cspan[$last[$j]][$j]++; + } else { + $last[$j] = $i; + } + } + } + return $cspan; + } + + + /*! sets mode of output format: usual mode or convert mode. + * @param mode + * true - convert mode, false - otherwise + */ + public function set_convert_mode($mode) + { + $this->convert_mode = $mode; + } + + + /*! adds header configuration in output XML + */ + public function attachHeaderToXML($conn, $out) + { + if (!$conn->is_first_call()) return; //render head only for first call + + $head = $this->getHeaderArray(); + $foot = $this->getFooterArray(); + $rspan = $this->processRspan($head); + $cspan = $this->processCspan($head); + + $str = '<head>'; + + if ($this->convert_mode) $str .= "<columns>"; + + for ($i = 0; $i < count($this->headerNames); $i++) { + $str .= '<column'; + $str .= ' type="' . $this->headerTypes[$i] . '"'; + $str .= ' width="' . $this->headerWidths[$i] . '"'; + $str .= $this->headerIds ? ' id="' . $this->headerIds[$i] . '"' : ''; + $str .= $this->headerAlign[$i] ? ' align="' . $this->headerAlign[$i] . '"' : ''; + $str .= $this->headerVAlign[$i] ? ' valign="' . $this->headerVAlign[$i] . '"' : ''; + $str .= $this->headerSorts[$i] ? ' sort="' . $this->headerSorts[$i] . '"' : ''; + $str .= $this->headerColors[$i] ? ' color="' . $this->headerColors[$i] . '"' : ''; + $str .= $this->headerHidden[$i] ? ' hidden="' . $this->headerHidden[$i] . '"' : ''; + $str .= $this->headerFormat[$i] ? ' format="' . $this->headerFormat[$i] . '"' : ''; + $str .= $cspan[0][$i] ? ' colspan="' . ($cspan[0][$i] + 1) . '"' : ''; + $str .= $rspan[0][$i] ? ' rowspan="' . ($rspan[0][$i] + 1) . '"' : ''; + $str .= '>' . $this->headerNames[$i] . '</column>'; + } + + if (!$this->convert_mode) { + $str .= '<settings><colwidth>' . $this->headerWidthsUnits . '</colwidth></settings>'; + if ((count($this->headerAttaches) > 0) || (count($this->footerAttaches) > 0)) { + $str .= '<afterInit>'; + } + for ($i = 0; $i < count($this->headerAttaches); $i++) { + $str .= '<call command="attachHeader">'; + $str .= '<param>' . implode(",", $this->headerAttaches[$i]['values']) . '</param>'; + if ($this->headerAttaches[$i]['styles'] != null) { + $str .= '<param>' . implode(",", $this->headerAttaches[$i]['styles']) . '</param>'; + } + $str .= '</call>'; + } + for ($i = 0; $i < count($this->footerAttaches); $i++) { + $str .= '<call command="attachFooter">'; + $str .= '<param>' . implode(",", $this->footerAttaches[$i]['values']) . '</param>'; + if ($this->footerAttaches[$i]['styles'] != null) { + $str .= '<param>' . implode(",", $this->footerAttaches[$i]['styles']) . '</param>'; + } + $str .= '</call>'; + } + if ((count($this->headerAttaches) > 0) || (count($this->footerAttaches) > 0)) { + $str .= '</afterInit>'; + } + } else { + $str .= "</columns>"; + for ($i = 1; $i < count($head); $i++) { + $str .= "<columns>"; + for ($j = 0; $j < count($head[$i]); $j++) { + $str .= '<column'; + $str .= $cspan[$i][$j] ? ' colspan="' . ($cspan[$i][$j] + 1) . '"' : ''; + $str .= $rspan[$i][$j] ? ' rowspan="' . ($rspan[$i][$j] + 1) . '"' : ''; + $str .= '>' . $head[$i][$j] . '</column>'; + } + $str .= "</columns>\n"; + } + } + $str .= '</head>'; + + + if ($this->convert_mode && count($foot) > 0) { + $rspan = $this->processRspan($foot); + $cspan = $this->processCspan($foot); + $str .= "<foot>"; + for ($i = 0; $i < count($foot); $i++) { + $str .= "<columns>"; + for ($j = 0; $j < count($foot[$i]); $j++) { + $str .= '<column'; + $str .= $cspan[$i][$j] ? ' colspan="' . ($cspan[$i][$j] + 1) . '"' : ''; + $str .= $rspan[$i][$j] ? ' rowspan="' . ($rspan[$i][$j] + 1) . '"' : ''; + $str .= '>' . $foot[$i][$j] . '</column>'; + } + $str .= "</columns>\n"; + } + $str .= "</foot>"; + } + + $out->add($str); + } +}
\ No newline at end of file diff --git a/codebase/GridConnector.php b/codebase/GridConnector.php new file mode 100644 index 0000000..1a0e216 --- /dev/null +++ b/codebase/GridConnector.php @@ -0,0 +1,125 @@ +<?php + +namespace DHTMLX\Connector; +/*! Connector for the dhtmlxgrid +**/ +class GridConnector extends Connector{ + + /*! constructor + + Here initilization of all Masters occurs, execution timer initialized + @param res + db connection resource + @param type + string , which hold type of database ( MySQL or Postgre ), optional, instead of short DB name, full name of DataWrapper-based class can be provided + @param item_type + name of class, which will be used for item rendering, optional, DataItem will be used by default + @param data_type + name of class which will be used for dataprocessor calls handling, optional, DataProcessor class will be used by default. + */ + public function __construct($res,$type=false,$item_type=false,$data_type=false,$render_type=false){ + if (!$item_type) $item_type="DHTMLX\\Connector\\GridDataItem"; + if (!$data_type) $data_type="DHTMLX\\Connector\\Data\\DataProcessor"; + if (!$render_type) $render_type="DHTMLX\\Connector\\Output\\RenderStrategy"; + parent::__construct($res,$type,$item_type,$data_type,$render_type); + } + + + protected function parse_request(){ + parent::parse_request(); + + if (isset($_GET["dhx_colls"])) + $this->fill_collections($_GET["dhx_colls"]); + } + protected function resolve_parameter($name){ + if (intval($name).""==$name) + return $this->config->text[intval($name)]["db_name"]; + return $name; + } + + /*! replace xml unsafe characters + + @param string + string to be escaped + @return + escaped string + */ + protected function xmlentities($string) { + return str_replace( array( '&', '"', "'", '<', '>', '’' ), array( '&' , '"', ''' , '<' , '>', ''' ), $string); + } + + /*! assign options collection to the column + + @param name + name of the column + @param options + array or connector object + */ + public function set_options($name,$options){ + if (is_array($options)){ + $str=""; + foreach($options as $k => $v) + $str.="<item value='".$this->xmlentities($k)."' label='".$this->xmlentities($v)."' />"; + $options=$str; + } + $this->options[$name]=$options; + } + /*! generates xml description for options collections + + @param list + comma separated list of column names, for which options need to be generated + */ + protected function fill_collections($list=""){ + $names=explode(",",$list); + for ($i=0; $i < sizeof($names); $i++) { + $name = $this->resolve_parameter($names[$i]); + if (!array_key_exists($name,$this->options)){ + $this->options[$name] = new DistinctOptionsConnector($this->get_connection(),$this->names["db_class"]); + $c = new DataConfig($this->config); + $r = new DataRequestConfig($this->request); + $c->minimize($name); + + $this->options[$name]->render_connector($c,$r); + } + + $this->extra_output.="<coll_options for='{$names[$i]}'>"; + if (!is_string($this->options[$name])) + $this->extra_output.=$this->options[$name]->render(); + else + $this->extra_output.=$this->options[$name]; + $this->extra_output.="</coll_options>"; + } + } + + /*! renders self as xml, starting part + */ + protected function xml_start(){ + $attributes = ""; + foreach($this->attributes as $k=>$v) + $attributes .= " ".$k."='".$v."'"; + + if ($this->dload){ + if ($pos=$this->request->get_start()) + return "<rows pos='".$pos."'".$attributes.">"; + else + return "<rows total_count='".$this->sql->get_size($this->request)."'".$attributes.">"; + } + else + return "<rows".$attributes.">"; + } + + + /*! renders self as xml, ending part + */ + protected function xml_end(){ + return $this->extra_output."</rows>"; + } + + public function set_config($config = false){ + if (gettype($config) == 'boolean') + $config = new GridConfiguration($config); + + $this->event->attach("beforeOutput", Array($config, "attachHeaderToXML")); + $this->event->attach("onInit", Array($config, "defineOptions")); + } +}
\ No newline at end of file diff --git a/codebase/GridDataItem.php b/codebase/GridDataItem.php new file mode 100644 index 0000000..a405f8b --- /dev/null +++ b/codebase/GridDataItem.php @@ -0,0 +1,120 @@ +<?php + +namespace DHTMLX\Connector; + +use DHTMLX\Connector\Data\DataItem; +/*! DataItem class for Grid component +**/ + +class GridDataItem extends DataItem{ + protected $row_attrs;//!< hash of row attributes + protected $cell_attrs;//!< hash of cell attributes + + function __construct($data,$name,$index=0){ + parent::__construct($data,$name,$index); + + $this->row_attrs=array(); + $this->cell_attrs=array(); + } + /*! set color of row + + @param color + color of row + */ + function set_row_color($color){ + $this->row_attrs["bgColor"]=$color; + } + /*! set style of row + + @param color + color of row + */ + function set_row_style($color){ + $this->row_attrs["style"]=$color; + } + /*! assign custom style to the cell + + @param name + name of column + @param value + css style string + */ + function set_cell_style($name,$value){ + $this->set_cell_attribute($name,"style",$value); + } + /*! assign custom class to specific cell + + @param name + name of column + @param value + css class name + */ + function set_cell_class($name,$value){ + $this->set_cell_attribute($name,"class",$value); + } + /*! set custom cell attribute + + @param name + name of column + @param attr + name of attribute + @param value + value of attribute + */ + function set_cell_attribute($name,$attr,$value){ + if (!array_key_exists($name, $this->cell_attrs)) $this->cell_attrs[$name]=array(); + $this->cell_attrs[$name][$attr]=$value; + } + + /*! set custom row attribute + + @param attr + name of attribute + @param value + value of attribute + */ + function set_row_attribute($attr,$value){ + $this->row_attrs[$attr]=$value; + } + + /*! return self as XML string, starting part + */ + public function to_xml_start(){ + if ($this->skip) return ""; + + $str="<row id='".$this->xmlentities($this->get_id())."'"; + foreach ($this->row_attrs as $k=>$v) + $str.=" ".$k."='".$v."'"; + $str.=">"; + for ($i=0; $i < sizeof($this->config->text); $i++){ + $str.="<cell"; + $name=$this->config->text[$i]["name"]; + $xmlcontent = false; + if (isset($this->cell_attrs[$name])){ + $cattrs=$this->cell_attrs[$name]; + foreach ($cattrs as $k => $v){ + $str.=" ".$k."='".$this->xmlentities($v)."'"; + if ($k == "xmlcontent") + $xmlcontent = true; + } + } + $value = isset($this->data[$name]) ? $this->data[$name] : ''; + if (!$xmlcontent) + $str.="><![CDATA[".$value."]]></cell>"; + else + $str.=">".$value."</cell>"; + } + if ($this->userdata !== false) + foreach ($this->userdata as $key => $value) + $str.="<userdata name='".$key."'><![CDATA[".$value."]]></userdata>"; + + return $str; + } + /*! return self as XML string, ending part + */ + public function to_xml_end(){ + if ($this->skip) return ""; + + return "</row>"; + } +}
\ No newline at end of file diff --git a/codebase/MixedConnector.php b/codebase/MixedConnector.php new file mode 100644 index 0000000..898bfa9 --- /dev/null +++ b/codebase/MixedConnector.php @@ -0,0 +1,24 @@ +<?php +namespace DHTMLX\Connector; + +use DHTMLX\Connector\Connector; + +class MixedConnector extends Connector { + + protected $connectors = array(); + + public function add($name, $conn) { + $this->connectors[$name] = $conn; + } + + public function render() { + $result = "{"; + $parts = array(); + foreach($this->connectors as $name => $conn) { + $conn->asString(true); + $parts[] = "\"".$name."\":".($conn->render())."\n"; + } + $result .= implode(",\n", $parts)."}"; + echo $result; + } +}
\ No newline at end of file diff --git a/codebase/OptionsConnector.php b/codebase/OptionsConnector.php new file mode 100644 index 0000000..4c0ab16 --- /dev/null +++ b/codebase/OptionsConnector.php @@ -0,0 +1,27 @@ +<?php + +namespace DHTMLX\Connector; + +/*! wrapper around options collection, used for comboboxes and filters +**/ +class OptionsConnector extends Connector{ + protected $init_flag=false;//!< used to prevent rendering while initialization + public function __construct($res,$type=false,$item_type=false,$data_type=false){ + if (!$item_type) $item_type="DataItem"; + if (!$data_type) $data_type=""; //has not sense, options not editable + parent::__construct($res,$type,$item_type,$data_type); + } + /*! render self + process commands, return data as XML, not output data to stdout, ignore parameters in incoming request + @return + data as XML string + */ + public function render(){ + if (!$this->init_flag){ + $this->init_flag=true; + return ""; + } + $res = $this->sql->select($this->request); + return $this->render_set($res); + } +}
\ No newline at end of file diff --git a/codebase/Output/JSONRenderStrategy.php b/codebase/Output/JSONRenderStrategy.php new file mode 100644 index 0000000..ea196e0 --- /dev/null +++ b/codebase/Output/JSONRenderStrategy.php @@ -0,0 +1,30 @@ +<?php +class JSONRenderStrategy extends RenderStrategy { + + /*! render from DB resultset + @param res + DB resultset + process commands, output requested data as json + */ + public function render_set($res, $name, $dload, $sep, $config, $mix){ + $output=array(); + $index=0; + $conn = $this->conn; + $this->mix($config, $mix); + $conn->event->trigger("beforeRenderSet",$conn,$res,$config); + while ($data=$conn->sql->get_next($res)){ + $data = $this->complex_mix($mix, $data); + $data = new $name($data,$config,$index); + if ($data->get_id()===false) + $data->set_id($conn->uuid()); + $conn->event->trigger("beforeRender",$data); + $item = $data->to_xml(); + if ($item !== false) + $output[]=$item; + $index++; + } + $this->unmix($config, $mix); + return $output; + } + +} diff --git a/codebase/Output/JSONTreeRenderStrategy.php b/codebase/Output/JSONTreeRenderStrategy.php new file mode 100644 index 0000000..04a8672 --- /dev/null +++ b/codebase/Output/JSONTreeRenderStrategy.php @@ -0,0 +1,39 @@ +<?php +namespace DHTMLX\Connector\Output; + +class JSONTreeRenderStrategy extends TreeRenderStrategy { + + public function render_set($res, $name, $dload, $sep, $config,$mix){ + $output=array(); + $index=0; + $conn = $this->conn; + $config_copy = new DataConfig($config); + $this->mix($config, $mix); + while ($data=$conn->sql->get_next($res)){ + $data = $this->complex_mix($mix, $data); + $data = new $name($data,$config,$index); + $conn->event->trigger("beforeRender",$data); + //there is no info about child elements, + //if we are using dyn. loading - assume that it has, + //in normal mode just exec sub-render routine + if ($data->has_kids()===-1 && $dload) + $data->set_kids(true); + $record = $data->to_xml_start(); + if ($data->has_kids()===-1 || ( $data->has_kids()==true && !$dload)){ + $sub_request = new DataRequestConfig($conn->get_request()); + //$sub_request->set_fieldset(implode(",",$config_copy->db_names_list($conn->sql))); + $sub_request->set_relation($data->get_id()); + //$sub_request->set_filters(array()); + $temp = $this->render_set($conn->sql->select($sub_request), $name, $dload, $sep, $config_copy, $mix); + if (sizeof($temp)) + $record["data"] = $temp; + } + if ($record !== false) + $output[] = $record; + $index++; + } + $this->unmix($config, $mix); + return $output; + } + +}
\ No newline at end of file diff --git a/codebase/Output/OutputWriter.php b/codebase/Output/OutputWriter.php new file mode 100644 index 0000000..96bb49a --- /dev/null +++ b/codebase/Output/OutputWriter.php @@ -0,0 +1,40 @@ +<?php + +namespace DHTMLX\Connector\Output; + +class OutputWriter{ + private $start; + private $end; + private $type; + + public function __construct($start, $end = ""){ + $this->start = $start; + $this->end = $end; + $this->type = "xml"; + } + public function add($add){ + $this->start.=$add; + } + public function reset(){ + $this->start=""; + $this->end=""; + } + public function set_type($add){ + $this->type=$add; + } + public function output($name="", $inline=true, $encoding=""){ + ob_clean(); + + if ($this->type == "xml"){ + $header = "Content-type: text/xml"; + if ("" != $encoding) + $header.="; charset=".$encoding; + header($header); + } + + echo $this->__toString(); + } + public function __toString(){ + return $this->start.$this->end; + } +}
\ No newline at end of file diff --git a/codebase/Output/RenderStrategy.php b/codebase/Output/RenderStrategy.php new file mode 100644 index 0000000..9431d0d --- /dev/null +++ b/codebase/Output/RenderStrategy.php @@ -0,0 +1,115 @@ +<?php +namespace DHTMLX\Connector\Output; + +use DHTMLX\Connector\Data\DataItem; +use DHTMLX\Connector\GridDataItem; +class RenderStrategy { + + protected $conn = null; + + public function __construct($conn) { + $this->conn = $conn; + } + + /*! adds mix fields into DataConfig + * @param config + * DataConfig object + * @param mix + * mix structure + */ + protected function mix($config, $mix) { + for ($i = 0; $i < count($mix); $i++) { + if ($config->is_field($mix[$i]['name'])===-1) { + $config->add_field($mix[$i]['name']); + } + } + } + + /*! remove mix fields from DataConfig + * @param config + * DataConfig object + * @param mix + * mix structure + */ + protected function unmix($config, $mix) { + for ($i = 0; $i < count($mix); $i++) { + if ($config->is_field($mix[$i]['name'])!==-1) { + $config->remove_field_full($mix[$i]['name']); + } + } + } + + /*! adds mix fields in item + * simple mix adds only strings specified by user + * @param mix + * mix structure + * @param data + * array of selected data + */ + protected function simple_mix($mix, $data) { + // get mix details + for ($i = 0; $i < count($mix); $i++) + $data[$mix[$i]["name"]] = is_object($mix[$i]["value"]) ? "" : $mix[$i]["value"]; + return $data; + } + + /*! adds mix fields in item + * complex mix adds strings specified by user and results of subrequests + * @param mix + * mix structure + * @param data + * array of selected data + */ + protected function complex_mix($mix, $data) { + // get mix details + for ($i = 0; $i < count($mix); $i++) { + $mixname = $mix[$i]["name"]; + if ($mix[$i]['filter'] !== false) { + $subconn = $mix[$i]["value"]; + $filter = $mix[$i]["filter"]; + + // setting relationships + $subconn->clear_filter(); + foreach ($filter as $k => $v) + if (isset($data[$v])) + $subconn->filter($k, $data[$v], "="); + else + throw new Exception('There was no such data field registered as: '.$k); + + $subconn->asString(true); + $data[$mixname]=$subconn->simple_render(); + if (is_array($data[$mixname]) && count($data[$mixname]) == 1) + $data[$mixname] = $data[$mixname][0]; + } else { + $data[$mixname] = $mix[$i]["value"]; + } + } + return $data; + } + + /*! render from DB resultset + @param res + DB resultset + process commands, output requested data as XML + */ + public function render_set($res, $name, $dload, $sep, $config, $mix){ + $output=""; + $index=0; + $conn = $this->conn; + $this->mix($config, $mix); + $conn->event->trigger("beforeRenderSet",$conn,$res,$config); + while ($data=$conn->sql->get_next($res)){ + $data = $this->simple_mix($mix, $data); + + $data = new $name($data,$config,$index); + if ($data->get_id()===false) + $data->set_id($conn->uuid()); + $conn->event->trigger("beforeRender",$data); + $output.=$data->to_xml().$sep; + $index++; + } + $this->unmix($config, $mix); + return $output; + } + +}
\ No newline at end of file diff --git a/codebase/Output/TreeRenderStrategy.php b/codebase/Output/TreeRenderStrategy.php new file mode 100644 index 0000000..d66e58e --- /dev/null +++ b/codebase/Output/TreeRenderStrategy.php @@ -0,0 +1,64 @@ +<?php +namespace DHTMLX\Connector\Output; + +use DHTMLX\Connector\DataStorage\DataConfig; + +class TreeRenderStrategy extends RenderStrategy { + + protected $id_swap = array(); + + public function __construct($conn) { + parent::__construct($conn); + $conn->event->attach("afterInsert",array($this,"parent_id_correction_a")); + $conn->event->attach("beforeProcessing",array($this,"parent_id_correction_b")); + } + + public function render_set($res, $name, $dload, $sep, $config, $mix){ + $output=""; + $index=0; + $conn = $this->conn; + $config_copy = new DataConfig($config); + $this->mix($config, $mix); + while ($data=$conn->sql->get_next($res)){ + $data = $this->simple_mix($mix, $data); + $data = new $name($data,$config,$index); + $conn->event->trigger("beforeRender",$data); + //there is no info about child elements, + //if we are using dyn. loading - assume that it has, + //in normal mode juse exec sub-render routine + if ($data->has_kids()===-1 && $dload) + $data->set_kids(true); + $output.=$data->to_xml_start(); + if ($data->has_kids()===-1 || ( $data->has_kids()==true && !$dload)){ + $sub_request = new DataRequestConfig($conn->get_request()); + //$sub_request->set_fieldset(implode(",",$config_copy->db_names_list($conn->sql))); + $sub_request->set_relation($data->get_id()); + $output.=$this->render_set($conn->sql->select($sub_request), $name, $dload, $sep, $config_copy, $mix); + } + $output.=$data->to_xml_end(); + $index++; + } + $this->unmix($config, $mix); + return $output; + } + + /*! store info about ID changes during insert operation + @param dataAction + data action object during insert operation + */ + public function parent_id_correction_a($dataAction){ + $this->id_swap[$dataAction->get_id()]=$dataAction->get_new_id(); + } + + /*! update ID if it was affected by previous operation + @param dataAction + data action object, before any processing operation + */ + public function parent_id_correction_b($dataAction){ + $relation = $this->conn->get_config()->relation_id["db_name"]; + $value = $dataAction->get_value($relation); + + if (array_key_exists($value,$this->id_swap)) + $dataAction->set_value($relation,$this->id_swap[$value]); + } +}
\ No newline at end of file diff --git a/codebase/Tools/AccessMaster.php b/codebase/Tools/AccessMaster.php new file mode 100644 index 0000000..6c84e20 --- /dev/null +++ b/codebase/Tools/AccessMaster.php @@ -0,0 +1,57 @@ +<?php +namespace DHTMLX\Connector\Tools; +/*! Class which handles access rules. +**/ +class AccessMaster{ + private $rules,$local; + /*! constructor + + Set next access right to "allowed" by default : read, insert, update, delete + Basically - all common data operations allowed by default + */ + function __construct(){ + $this->rules=array("read" => true, "insert" => true, "update" => true, "delete" => true); + $this->local=true; + } + /*! change access rule to "allow" + @param name + name of access right + */ + public function allow($name){ + $this->rules[$name]=true; + } + /*! change access rule to "deny" + + @param name + name of access right + */ + public function deny($name){ + $this->rules[$name]=false; + } + + /*! change all access rules to "deny" + */ + public function deny_all(){ + $this->rules=array(); + } + + /*! check access rule + + @param name + name of access right + @return + true if access rule allowed, false otherwise + */ + public function check($name){ + if ($this->local){ + /*! + todo + add referrer check, to prevent access from remote points + */ + } + if (!isset($this->rules[$name]) || !$this->rules[$name]){ + return false; + } + return true; + } +}
\ No newline at end of file diff --git a/codebase/Tools/EventMaster.php b/codebase/Tools/EventMaster.php new file mode 100644 index 0000000..ec849d8 --- /dev/null +++ b/codebase/Tools/EventMaster.php @@ -0,0 +1,107 @@ +<?php + +namespace DHTMLX\Connector\Tools; +/*! Class which allows to assign|fire events. +*/ +class EventMaster{ + private $events;//!< hash of event handlers + private $master; + private static $eventsStatic=array(); + + /*! constructor + */ + function __construct(){ + $this->events=array(); + $this->master = false; + } + /*! Method check if event with such name already exists. + @param name + name of event, case non-sensitive + @return + true if event with such name registered, false otherwise + */ + public function exist($name){ + $name=strtolower($name); + return (isset($this->events[$name]) && sizeof($this->events[$name])); + } + /*! Attach custom code to event. + + Only on event handler can be attached in the same time. If new event handler attached - old will be detached. + + @param name + name of event, case non-sensitive + @param method + function which will be attached. You can use array(class, method) if you want to attach the method of the class. + */ + public function attach($name,$method=false){ + //use class for event handling + if ($method === false){ + $this->master = $name; + return; + } + //use separate functions + $name=strtolower($name); + if (!array_key_exists($name,$this->events)) + $this->events[$name]=array(); + $this->events[$name][]=$method; + } + + public static function attach_static($name, $method){ + $name=strtolower($name); + if (!array_key_exists($name,EventMaster::$eventsStatic)) + EventMaster::$eventsStatic[$name]=array(); + EventMaster::$eventsStatic[$name][]=$method; + } + + public static function trigger_static($name, $method){ + $arg_list = func_get_args(); + $name=strtolower(array_shift($arg_list)); + + if (isset(EventMaster::$eventsStatic[$name])) + foreach(EventMaster::$eventsStatic[$name] as $method){ + if (is_array($method) && !method_exists($method[0],$method[1])) + throw new Exception("Incorrect method assigned to event: ".$method[0].":".$method[1]); + if (!is_array($method) && !function_exists($method)) + throw new Exception("Incorrect function assigned to event: ".$method); + call_user_func_array($method, $arg_list); + } + return true; + } + + /*! Detach code from event + @param name + name of event, case non-sensitive + */ + public function detach($name){ + $name=strtolower($name); + unset($this->events[$name]); + } + /*! Trigger event. + @param name + name of event, case non-sensitive + @param data + value which will be provided as argument for event function, + you can provide multiple data arguments, method accepts variable number of parameters + @return + true if event handler was not assigned , result of event hangler otherwise + */ + public function trigger($name,$data){ + $arg_list = func_get_args(); + $name=strtolower(array_shift($arg_list)); + + if (isset($this->events[$name])) + foreach($this->events[$name] as $method){ + if (is_array($method) && !method_exists($method[0],$method[1])) + throw new Exception("Incorrect method assigned to event: ".$method[0].":".$method[1]); + if (!is_array($method) && !function_exists($method)) + throw new Exception("Incorrect function assigned to event: ".$method); + call_user_func_array($method, $arg_list); + } + + if ($this->master !== false) + if (method_exists($this->master, $name)) + call_user_func_array(array($this->master, $name), $arg_list); + + return true; + } +}
\ No newline at end of file diff --git a/codebase/Tools/LogMaster.php b/codebase/Tools/LogMaster.php new file mode 100644 index 0000000..c9459cc --- /dev/null +++ b/codebase/Tools/LogMaster.php @@ -0,0 +1,101 @@ +<?php + +namespace DHTMLX\Connector\Tools; +/*! Controls error and debug logging. + Class designed to be used as static object. +**/ +class LogMaster{ + private static $_log=false;//!< logging mode flag + private static $_output=false;//!< output error infor to client flag + private static $session="";//!< all messages generated for current request + + /*! convert array to string representation ( it is a bit more readable than var_dump ) + + @param data + data object + @param pref + prefix string, used for formating, optional + @return + string with array description + */ + private static function log_details($data,$pref=""){ + if (is_array($data)){ + $str=array(""); + foreach($data as $k=>$v) + array_push($str,$pref.$k." => ".LogMaster::log_details($v,$pref."\t")); + return implode("\n",$str); + } + return $data; + } + /*! put record in log + + @param str + string with log info, optional + @param data + data object, which will be added to log, optional + */ + public static function log($str="",$data=""){ + if (LogMaster::$_log){ + $message = $str.LogMaster::log_details($data)."\n\n"; + LogMaster::$session.=$message; + error_log($message,3,LogMaster::$_log); + } + } + + /*! get logs for current request + @return + string, which contains all log messages generated for current request + */ + public static function get_session_log(){ + return LogMaster::$session; + } + + /*! error handler, put normal php errors in log file + + @param errn + error number + @param errstr + error description + @param file + error file + @param line + error line + @param context + error cntext + */ + public static function error_log($errn,$errstr,$file,$line,$context){ + LogMaster::log($errstr." at ".$file." line ".$line); + } + + /*! exception handler, used as default reaction on any error - show execution log and stop processing + + @param exception + instance of Exception + */ + public static function exception_log($exception){ + LogMaster::log("!!!Uncaught Exception\nCode: " . $exception->getCode() . "\nMessage: " . $exception->getMessage()); + if (LogMaster::$_output){ + echo "<pre><xmp>\n"; + echo LogMaster::get_session_log(); + echo "\n</xmp></pre>"; + } + die(); + } + + /*! enable logging + + @param name + path to the log file, if boolean false provided as value - logging will be disabled + @param output + flag of client side output, if enabled - session log will be sent to client side in case of an error. + */ + public static function enable_log($name,$output=false){ + LogMaster::$_log=$name; + LogMaster::$_output=$output; + if ($name){ + set_error_handler(array("LogMaster","error_log"),E_ALL); + set_exception_handler(array("LogMaster","exception_log")); + LogMaster::log("\n\n====================================\nLog started, ".date("d/m/Y h:i:s")."\n===================================="); + } + } +}
\ No newline at end of file diff --git a/codebase/TreeConnector.php b/codebase/TreeConnector.php new file mode 100644 index 0000000..b01e399 --- /dev/null +++ b/codebase/TreeConnector.php @@ -0,0 +1,63 @@ +<?php + +namespace DHTMLX\Connector; + +class TreeConnector extends Connector +{ + protected $parent_name = 'id'; + public $rootId = "0"; + + /*! constructor + + Here initilization of all Masters occurs, execution timer initialized + @param res + db connection resource + @param type + string , which hold type of database ( MySQL or Postgre ), optional, instead of short DB name, full name of DataWrapper-based class can be provided + @param item_type + name of class, which will be used for item rendering, optional, DataItem will be used by default + @param data_type + name of class which will be used for dataprocessor calls handling, optional, DataProcessor class will be used by default. + * @param render_type + * name of class which will provides data rendering + */ + public function __construct($res, $type = false, $item_type = false, $data_type = false, $render_type = false) + { + if (!$item_type) $item_type = "TreeDataItem"; + if (!$data_type) $data_type = "TreeDataProcessor"; + if (!$render_type) $render_type = "TreeRenderStrategy"; + parent::__construct($res, $type, $item_type, $data_type, $render_type); + } + + //parse GET scoope, all operations with incoming request must be done here + public function parse_request() + { + parent::parse_request(); + + if (isset($_GET[$this->parent_name])) + $this->request->set_relation($_GET[$this->parent_name]); + else + $this->request->set_relation($this->rootId); + + $this->request->set_limit(0, 0); //netralize default reaction on dyn. loading mode + } + + /*! renders self as xml, starting part + */ + public function xml_start() + { + $attributes = ""; + foreach ($this->attributes as $k => $v) + $attributes .= " " . $k . "='" . $v . "'"; + + return "<tree id='" . $this->request->get_relation() . "'" . $attributes . ">"; + } + + /*! renders self as xml, ending part + */ + public function xml_end() + { + $this->fill_collections(); + return $this->extra_output . "</tree>"; + } +} diff --git a/codebase/XSSFilter/ConnectorSecurity.php b/codebase/XSSFilter/ConnectorSecurity.php new file mode 100644 index 0000000..195e962 --- /dev/null +++ b/codebase/XSSFilter/ConnectorSecurity.php @@ -0,0 +1,67 @@ +<?php +namespace DHTMLX\Connector\XSSFilter; + + +use DHTMLX\Connector\Tools\LogMaster; + +define("DHX_SECURITY_SAFETEXT", 1); +define("DHX_SECURITY_SAFEHTML", 2); +define("DHX_SECURITY_TRUSTED", 3); + +class ConnectorSecurity{ + static public $xss = DHX_SECURITY_SAFETEXT; + static public $security_key = false; + static public $security_var = "dhx_security"; + + static private $filterClass = null; + static function filter($value, $mode = false){ + if ($mode === false) + $mode = ConnectorSecurity::$xss; + + if ($mode == DHX_SECURITY_TRUSTED) + return $value; + if ($mode == DHX_SECURITY_SAFETEXT) + return filter_var($value, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES); + if ($mode == DHX_SECURITY_SAFEHTML){ + if (ConnectorSecurity::$filterClass == null) + ConnectorSecurity::$filterClass = new dhxExternalInputClean(); + return ConnectorSecurity::$filterClass->basic($value); + } + throw new Error("Invalid security mode:"+$mode); + } + + static function CSRF_detected(){ + LogMaster::log("[SECURITY] Possible CSRF attack detected", array( + "referer" => $_SERVER["HTTP_REFERER"], + "remote" => $_SERVER["REMOTE_ADDR"] + )); + LogMaster::log("Request data", $_POST); + die(); + } + static function checkCSRF($edit){ + if (ConnectorSecurity::$security_key){ + if (!isset($_SESSION)) + @session_start(); + + if ($edit=== true){ + if (!isset($_POST[ConnectorSecurity::$security_var])) + return ConnectorSecurity::CSRF_detected(); + $master_key = $_SESSION[ConnectorSecurity::$security_var]; + $update_key = $_POST[ConnectorSecurity::$security_var]; + if ($master_key != $update_key) + return ConnectorSecurity::CSRF_detected(); + + return ""; + } + //data loading + if (!array_key_exists(ConnectorSecurity::$security_var,$_SESSION)){ + $_SESSION[ConnectorSecurity::$security_var] = md5(uniqid()); + } + + return $_SESSION[ConnectorSecurity::$security_var]; + } + + return ""; + } + +}
\ No newline at end of file diff --git a/codebase/XSSFilter/dhxExternalInputClean.php b/codebase/XSSFilter/dhxExternalInputClean.php new file mode 100644 index 0000000..4f3b526 --- /dev/null +++ b/codebase/XSSFilter/dhxExternalInputClean.php @@ -0,0 +1,120 @@ +<?php +namespace DHTMLX\Connector\XSSFilter; +//original name was lx_externalinput_clean +//renamed to prevent possible conflicts +class dhxExternalInputClean { + // this basic clean should clean html code from + // lot of possible malicious code for Cross Site Scripting + // use it whereever you get external input + + // you can also set $filterOut to some use html cleaning, but I don't know of any code, which could + // exploit that. But if you want to be sure, set it to eg. array("Tidy","Dom"); + static function basic($string, $filterIn = array("Tidy","Dom","Striptags"), $filterOut = "none") { + $string = self::tidyUp($string, $filterIn); + $string = str_replace(array("&", "<", ">"), array("&amp;", "&lt;", "&gt;"), $string); + + // fix &entitiy\n; + $string = preg_replace('#(&\#*\w+)[\x00-\x20]+;#u', "$1;", $string); + $string = preg_replace('#(&\#x*)([0-9A-F]+);*#iu', "$1$2;", $string); + + $string = html_entity_decode($string, ENT_COMPAT, "UTF-8"); + + // remove any attribute starting with "on" or xmlns + $string = preg_replace('#(<[^>]+[\x00-\x20\"\'\/])(on|xmlns)[^>]*>#iUu', "$1>", $string); + + // remove javascript: and vbscript: protocol + $string = preg_replace('#([a-z]*)[\x00-\x20\/]*=[\x00-\x20\/]*([\`\'\"]*)[\x00-\x20\/]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iUu', '$1=$2nojavascript...', $string); + $string = preg_replace('#([a-z]*)[\x00-\x20\/]*=[\x00-\x20\/]*([\`\'\"]*)[\x00-\x20\/]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iUu', '$1=$2novbscript...', $string); + $string = preg_replace('#([a-z]*)[\x00-\x20\/]*=[\x00-\x20\/]*([\`\'\"]*)[\x00-\x20\/]*-moz-binding[\x00-\x20]*:#Uu', '$1=$2nomozbinding...', $string); + $string = preg_replace('#([a-z]*)[\x00-\x20\/]*=[\x00-\x20\/]*([\`\'\"]*)[\x00-\x20\/]*data[\x00-\x20]*:#Uu', '$1=$2nodata...', $string); + + //remove any style attributes, IE allows too much stupid things in them, eg. + //<span style="width: expression(alert('Ping!'));"></span> + // and in general you really don't want style declarations in your UGC + + $string = preg_replace('#(<[^>]+[\x00-\x20\"\'\/])style[^>]*>#iUu', "$1>", $string); + + //remove namespaced elements (we do not need them...) + $string = preg_replace('#</*\w+:\w[^>]*>#i', "", $string); + + //remove really unwanted tags + do { + $oldstring = $string; + $string = preg_replace('#</*(applet|meta|xml|blink|link|style|script|embed|object|iframe|frame|frameset|ilayer|layer|bgsound|title|base)[^>]*>#i', "", $string); + } while ($oldstring != $string); + + return self::tidyUp($string, $filterOut); + } + + static function tidyUp($string, $filters) { + if (is_array($filters)) { + foreach ($filters as $filter) { + $return = self::tidyUpWithFilter($string, $filter); + if ($return !== false) { + return $return; + } + } + } else { + $return = self::tidyUpWithFilter($string, $filters); + } + // if no filter matched, use the Striptags filter to be sure. + if ($return === false) { + return self::tidyUpModuleStriptags($string); + } else { + return $return; + } + } + + static private function tidyUpWithFilter($string, $filter) { + if (is_callable(array("self", "tidyUpModule" . $filter))) { + return call_user_func(array("self", "tidyUpModule" . $filter), $string); + } + return false; + } + + static private function tidyUpModuleStriptags($string) { + + return strip_tags($string); + } + + static private function tidyUpModuleNone($string) { + return $string; + } + + static private function tidyUpModuleDom($string) { + $dom = new domdocument(); + @$dom->loadHTML("<html><body>" . $string . "</body></html>"); + $string = ''; + foreach ($dom->documentElement->firstChild->childNodes as $child) { + $string .= $dom->saveXML($child); + } + return $string; + } + + static private function tidyUpModuleTidy($string) { + if (class_exists("tidy")) { + $tidy = new tidy(); + $tidyOptions = array("output-xhtml" => true, + "show-body-only" => true, + "clean" => true, + "wrap" => "350", + "indent" => true, + "indent-spaces" => 1, + "ascii-chars" => false, + "wrap-attributes" => false, + "alt-text" => "", + "doctype" => "loose", + "numeric-entities" => true, + "drop-proprietary-attributes" => true, + "enclose-text" => false, + "enclose-block-text" => false + + ); + $tidy->parseString($string, $tidyOptions, "utf8"); + $tidy->cleanRepair(); + return (string) $tidy; + } else { + return false; + } + } +}
\ No newline at end of file diff --git a/codebase/base_connector.php b/codebase/base_connector.php deleted file mode 100644 index 26f1f8b..0000000 --- a/codebase/base_connector.php +++ /dev/null @@ -1,948 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("tools.php"); -require_once("db_common.php"); -require_once("dataprocessor.php"); -require_once("strategy.php"); -require_once("update.php"); - -//enable buffering to catch and ignore any custom output before XML generation -//because of this command, it strongly recommended to include connector's file before any other libs -//in such case it will handle any extra output from not well formed code of other libs -ini_set("output_buffering","On"); -ob_start(); - -class OutputWriter{ - private $start; - private $end; - private $type; - - public function __construct($start, $end = ""){ - $this->start = $start; - $this->end = $end; - $this->type = "xml"; - } - public function add($add){ - $this->start.=$add; - } - public function reset(){ - $this->start=""; - $this->end=""; - } - public function set_type($add){ - $this->type=$add; - } - public function output($name="", $inline=true, $encoding=""){ - ob_clean(); - - if ($this->type == "xml"){ - $header = "Content-type: text/xml"; - if ("" != $encoding) - $header.="; charset=".$encoding; - header($header); - } - - echo $this->__toString(); - } - public function __toString(){ - return $this->start.$this->end; - } -} - -/*! EventInterface - Base class , for iterable collections, which are used in event -**/ -class EventInterface{ - protected $request; ////!< DataRequestConfig instance - public $rules=array(); //!< array of sorting rules - - /*! constructor - creates a new interface based on existing request - @param request - DataRequestConfig object - */ - public function __construct($request){ - $this->request = $request; - } - - /*! remove all elements from collection - */ - public function clear(){ - array_splice($rules,0); - } - /*! get index by name - - @param name - name of field - @return - index of named field - */ - public function index($name){ - $len = sizeof($this->rules); - for ($i=0; $i < $len; $i++) { - if ($this->rules[$i]["name"]==$name) - return $i; - } - return false; - } -} -/*! Wrapper for collection of sorting rules -**/ -class SortInterface extends EventInterface{ - /*! constructor - creates a new interface based on existing request - @param request - DataRequestConfig object - */ - public function __construct($request){ - parent::__construct($request); - $this->rules = &$request->get_sort_by_ref(); - } - /*! add new sorting rule - - @param name - name of field - @param dir - direction of sorting - */ - public function add($name,$dir){ - if ($dir === false) - $this->request->set_sort($name); - else - $this->request->set_sort($name,$dir); - } - public function store(){ - $this->request->set_sort_by($this->rules); - } -} -/*! Wrapper for collection of filtering rules -**/ -class FilterInterface extends EventInterface{ - /*! constructor - creates a new interface based on existing request - @param request - DataRequestConfig object - */ - public function __construct($request){ - $this->request = $request; - $this->rules = &$request->get_filters_ref(); - } - /*! add new filatering rule - - @param name - name of field - @param value - value to filter by - @param rule - filtering rule - */ - public function add($name,$value,$rule){ - $this->request->set_filter($name,$value,$rule); - } - public function store(){ - $this->request->set_filters($this->rules); - } -} - -/*! base class for component item representation -**/ -class DataItem{ - protected $data; //!< hash of data - protected $config;//!< DataConfig instance - protected $index;//!< index of element - protected $skip;//!< flag , which set if element need to be skiped during rendering - protected $userdata; - - /*! constructor - - @param data - hash of data - @param config - DataConfig object - @param index - index of element - */ - function __construct($data,$config,$index){ - $this->config=$config; - $this->data=$data; - $this->index=$index; - $this->skip=false; - $this->userdata=false; - } - - //set userdata for the item - function set_userdata($name, $value){ - if ($this->userdata === false) - $this->userdata = array(); - - $this->userdata[$name]=$value; - } - /*! get named value - - @param name - name or alias of field - @return - value from field with provided name or alias - */ - public function get_value($name){ - return $this->data[$name]; - } - /*! set named value - - @param name - name or alias of field - @param value - value for field with provided name or alias - */ - public function set_value($name,$value){ - return $this->data[$name]=$value; - } - /*! get id of element - @return - id of element - */ - public function get_id(){ - $id = $this->config->id["name"]; - if (array_key_exists($id,$this->data)) - return $this->data[$id]; - return false; - } - /*! change id of element - - @param value - new id value - */ - public function set_id($value){ - $this->data[$this->config->id["name"]]=$value; - } - /*! get index of element - - @return - index of element - */ - public function get_index(){ - return $this->index; - } - /*! mark element for skiping ( such element will not be rendered ) - */ - public function skip(){ - $this->skip=true; - } - - /*! return self as XML string - */ - public function to_xml(){ - return $this->to_xml_start().$this->to_xml_end(); - } - - /*! replace xml unsafe characters - - @param string - string to be escaped - @return - escaped string - */ - public function xmlentities($string) { - return str_replace( array( '&', '"', "'", '<', '>', '’' ), array( '&' , '"', ''' , '<' , '>', ''' ), $string); - } - - /*! return starting tag for self as XML string - */ - public function to_xml_start(){ - $str="<item"; - for ($i=0; $i < sizeof($this->config->data); $i++){ - $name=$this->config->data[$i]["name"]; - $db_name=$this->config->data[$i]["db_name"]; - $str.=" ".$name."='".$this->xmlentities($this->data[$name])."'"; - } - //output custom data - if ($this->userdata !== false) - foreach ($this->userdata as $key => $value){ - $str.=" ".$key."='".$this->xmlentities($value)."'"; - } - - return $str.">"; - } - /*! return ending tag for XML string - */ - public function to_xml_end(){ - return "</item>"; - } -} - - - - - -/*! Base connector class - This class used as a base for all component specific connectors. - Can be used on its own to provide raw data. -**/ -class Connector { - protected $config;//DataConfig instance - protected $request;//DataRequestConfig instance - protected $names;//!< hash of names for used classes - protected $encoding="utf-8";//!< assigned encoding (UTF-8 by default) - protected $editing=false;//!< flag of edit mode ( response for dataprocessor ) - - public static $filter_var="dhx_filter"; - public static $sort_var="dhx_sort"; - public static $kids_var="dhx_kids"; - - public $model=false; - - private $updating=false;//!< flag of update mode ( response for data-update ) - private $db; //!< db connection resource - protected $dload;//!< flag of dyn. loading mode - public $access; //!< AccessMaster instance - protected $data_separator = "\n"; - - public $sql; //DataWrapper instance - public $event; //EventMaster instance - public $limit=false; - - private $id_seed=0; //!< default value, used to generate auto-IDs - protected $live_update = false; // actions table name for autoupdating - protected $extra_output="";//!< extra info which need to be sent to client side - protected $options=array();//!< hash of OptionsConnector - protected $as_string = false; // render() returns string, don't send result in response - protected $simple = false; // render only data without any other info - protected $filters; - protected $sorts; - protected $mix; - protected $order = false; - - /*! constructor - - Here initilization of all Masters occurs, execution timer initialized - @param db - db connection resource - @param type - string , which hold type of database ( MySQL or Postgre ), optional, instead of short DB name, full name of DataWrapper-based class can be provided - @param item_type - name of class, which will be used for item rendering, optional, DataItem will be used by default - @param data_type - name of class which will be used for dataprocessor calls handling, optional, DataProcessor class will be used by default. - */ - public function __construct($db,$type=false, $item_type=false, $data_type=false, $render_type = false){ - $this->exec_time=microtime(true); - - if (!$type) $type="MySQL"; - if (class_exists($type."DBDataWrapper",false)) $type.="DBDataWrapper"; - if (!$item_type) $item_type="DataItem"; - if (!$data_type) $data_type="DataProcessor"; - if (!$render_type) $render_type="RenderStrategy"; - - $this->names=array( - "db_class"=>$type, - "item_class"=>$item_type, - "data_class"=>$data_type, - "render_class"=>$render_type - ); - $this->attributes = array(); - $this->filters = array(); - $this->sorts = array(); - $this->mix = array(); - - $this->config = new DataConfig(); - $this->request = new DataRequestConfig(); - $this->event = new EventMaster(); - $this->access = new AccessMaster(); - - if (!class_exists($this->names["db_class"],false)) - throw new Exception("DB class not found: ".$this->names["db_class"]); - $this->sql = new $this->names["db_class"]($db,$this->config); - $this->render = new $this->names["render_class"]($this); - - $this->db=$db;//saved for options connectors, if any - - EventMaster::trigger_static("connectorCreate",$this); - } - - /*! return db connection resource - nested class may neeed to access live connection object - @return - DB connection resource - */ - protected function get_connection(){ - return $this->db; - } - - public function get_config(){ - return new DataConfig($this->config); - } - - public function get_request(){ - return new DataRequestConfig($this->request); - } - - - protected $attributes; - public function add_top_attribute($name, $string){ - $this->attributes[$name] = $string; - } - - //model is a class, which will be used for all data operations - //we expect that it has next methods get, update, insert, delete - //if method was not defined - we will use default logic - public function useModel($model){ - $this->model = $model; - } - - - /*! config connector based on table - - @param table - name of table in DB - @param id - name of id field - @param fields - list of fields names - @param extra - list of extra fields, optional, such fields will not be included in data rendering, but will be accessible in all inner events - @param relation_id - name of field used to define relations for hierarchical data organization, optional - */ - public function render_table($table,$id="",$fields=false,$extra=false,$relation_id=false){ - $this->configure($table,$id,$fields,$extra,$relation_id); - return $this->render(); - } - public function configure($table,$id="",$fields=false,$extra=false,$relation_id=false){ - if ($fields === false){ - //auto-config - $info = $this->sql->fields_list($table); - $fields = implode(",",$info["fields"]); - if ($info["key"]) - $id = $info["key"]; - } - $this->config->init($id,$fields,$extra,$relation_id); - if (strpos(trim($table), " ")!==false) - $this->request->parse_sql($table); - else - $this->request->set_source($table); - } - - public function uuid(){ - return time()."x".$this->id_seed++; - } - - /*! config connector based on sql - - @param sql - sql query used as base of configuration - @param id - name of id field - @param fields - list of fields names - @param extra - list of extra fields, optional, such fields will not be included in data rendering, but will be accessible in all inner events - @param relation_id - name of field used to define relations for hierarchical data organization, optional - */ - public function render_sql($sql,$id,$fields,$extra=false,$relation_id=false){ - $this->config->init($id,$fields,$extra,$relation_id); - $this->request->parse_sql($sql); - return $this->render(); - } - - public function render_array($data, $id, $fields, $extra=false, $relation_id=false){ - $this->configure("-",$id,$fields,$extra,$relation_id); - $this->sql = new ArrayDBDataWrapper($data, $this->config); - return $this->render(); - } - - public function render_complex_sql($sql,$id,$fields,$extra=false,$relation_id=false){ - $this->config->init($id,$fields,$extra,$relation_id); - $this->request->parse_sql($sql, true); - return $this->render(); - } - - /*! render already configured connector - - @param config - configuration of data - @param request - configuraton of request - */ - public function render_connector($config,$request){ - $this->config->copy($config); - $this->request->copy($request); - return $this->render(); - } - - /*! render self - process commands, output requested data as XML - */ - public function render(){ - $this->event->trigger("onInit", $this); - EventMaster::trigger_static("connectorInit",$this); - - if (!$this->as_string) - $this->parse_request(); - $this->set_relation(); - - if ($this->live_update !== false && $this->updating!==false) { - $this->live_update->get_updates(); - } else { - if ($this->editing){ - $dp = new $this->names["data_class"]($this,$this->config,$this->request); - $dp->process($this->config,$this->request); - } else { - if (!$this->access->check("read")){ - LogMaster::log("Access control: read operation blocked"); - echo "Access denied"; - die(); - } - $wrap = new SortInterface($this->request); - $this->apply_sorts($wrap); - $this->event->trigger("beforeSort",$wrap); - $wrap->store(); - - $wrap = new FilterInterface($this->request); - $this->apply_filters($wrap); - $this->event->trigger("beforeFilter",$wrap); - $wrap->store(); - - if ($this->model && method_exists($this->model, "get")){ - $this->sql = new ArrayDBDataWrapper(); - $result = new ArrayQueryWrapper(call_user_func(array($this->model, "get"), $this->request)); - $out = $this->output_as_xml($result); - } else { - $out = $this->output_as_xml($this->get_resource()); - - if ($out !== null) return $out; - } - - } - } - $this->end_run(); - } - - - /*! empty call which used for tree-logic - * to prevent code duplicating - */ - protected function set_relation() {} - - /*! gets resource for rendering - */ - protected function get_resource() { - return $this->sql->select($this->request); - } - - - /*! prevent SQL injection through column names - replace dangerous chars in field names - @param str - incoming field name - @return - safe field name - */ - protected function safe_field_name($str){ - return strtok($str, " \n\t;',"); - } - - /*! limit max count of records - connector will ignore any records after outputing max count - @param limit - max count of records - @return - none - */ - public function set_limit($limit){ - $this->limit = $limit; - } - - - public function limit($start, $count, $sort_field=false, $sort_dir=false){ - $this->request->set_limit($start, $count); - if ($sort_field) - $this->request->set_sort($sort_field, $sort_dir); - } - - protected function parse_request_mode(){ - //detect edit mode - if (isset($_GET["editing"])){ - $this->editing=true; - } else if (isset($_POST["ids"])){ - $this->editing=true; - LogMaster::log('While there is no edit mode mark, POST parameters similar to edit mode detected. \n Switching to edit mode ( to disable behavior remove POST[ids]'); - } else if (isset($_GET['dhx_version'])){ - $this->updating = true; - } - } - - /*! parse incoming request, detects commands and modes - */ - protected function parse_request(){ - //set default dyn. loading params, can be reset in child classes - if ($this->dload) - $this->request->set_limit(0,$this->dload); - else if ($this->limit) - $this->request->set_limit(0,$this->limit); - - if (isset($_GET["posStart"]) && isset($_GET["count"])) { - $this->request->set_limit($_GET["posStart"],$_GET["count"]); - } - - $this->parse_request_mode(); - - if ($this->live_update && ($this->updating || $this->editing)){ - $this->request->set_version($_GET["dhx_version"]); - $this->request->set_user($_GET["dhx_user"]); - } - - if (isset($_GET[Connector::$sort_var])) - foreach($_GET[Connector::$sort_var] as $k => $v){ - $k = $this->safe_field_name($k); - $this->request->set_sort($this->resolve_parameter($k),$v); - } - - if (isset($_GET[Connector::$filter_var])) - foreach($_GET[Connector::$filter_var] as $k => $v){ - $k = $this->safe_field_name($k); - if ($v !== "") - $this->request->set_filter($this->resolve_parameter($k),$v); - } - - $this->check_csrf(); - } - - protected function check_csrf(){ - $key = ConnectorSecurity::checkCSRF($this->editing); - if ($key !== "") - $this->add_top_attribute(ConnectorSecurity::$security_var, $key); - } - - /*! convert incoming request name to the actual DB name - @param name - incoming parameter name - @return - name of related DB field - */ - protected function resolve_parameter($name){ - return $name; - } - - - /*! replace xml unsafe characters - - @param string - string to be escaped - @return - escaped string - */ - protected function xmlentities($string) { - return str_replace( array( '&', '"', "'", '<', '>', '’' ), array( '&' , '"', ''' , '<' , '>', ''' ), $string); - } - - public function getRecord($id){ - LogMaster::log("Retreiving data for record: ".$id); - $source = new DataRequestConfig($this->request); - $source->set_filter($this->config->id["name"],$id, "="); - - $res = $this->sql->select($source); - - $temp = $this->data_separator; - $this->data_separator=""; - $output = $this->render_set($res); - $this->data_separato=$temp; - - return $output; - } - - /*! render from DB resultset - @param res - DB resultset - process commands, output requested data as XML - */ - protected function render_set($res){ - return $this->render->render_set($res, $this->names["item_class"], $this->dload, $this->data_separator, $this->config, $this->mix); - } - - /*! output fetched data as XML - @param res - DB resultset - */ - protected function output_as_xml($res){ - $result = $this->render_set($res); - if ($this->simple) return $result; - - $start="<?xml version='1.0' encoding='".$this->encoding."' ?>".$this->xml_start(); - $end=$result.$this->xml_end(); - - if ($this->as_string) return $start.$end; - - $out = new OutputWriter($start, $end); - $this->event->trigger("beforeOutput", $this, $out); - $out->output("", true, $this->encoding); - } - - - /*! end processing - stop execution timer, kill the process - */ - protected function end_run(){ - $time=microtime(true)-$this->exec_time; - LogMaster::log("Done in {$time}s"); - flush(); - die(); - } - - /*! set xml encoding - - methods sets only attribute in XML, no real encoding conversion occurs - @param encoding - value which will be used as XML encoding - */ - public function set_encoding($encoding){ - $this->encoding=$encoding; - } - - /*! enable or disable dynamic loading mode - - @param count - count of rows loaded from server, actual only for grid-connector, can be skiped in other cases. - If value is a false or 0 - dyn. loading will be disabled - */ - public function dynamic_loading($count){ - $this->dload=$count; - } - - /*! enable or disable data reordering - - @param name - name of field, which will be used for order storing, optional - by default 'sortorder' field will be used - */ - public function enable_order($name = true){ - if ($name === true) - $name = "sortorder"; - - $this->sort($name); - $this->access->allow("order"); - $this->request->set_order($name); - $this->order = $name; - } - - /*! enable logging - - @param path - path to the log file. If set as false or empty strig - logging will be disabled - @param client_log - enable output of log data to the client side - */ - public function enable_log($path=true,$client_log=false){ - LogMaster::enable_log($path,$client_log); - } - - /*! provides infor about current processing mode - @return - true if processing dataprocessor command, false otherwise - */ - public function is_select_mode(){ - $this->parse_request_mode(); - return !$this->editing; - } - - public function is_first_call(){ - $this->parse_request_mode(); - return !($this->editing || $this->updating || $this->request->get_start() || isset($_GET['dhx_no_header'])); - - } - - /*! renders self as xml, starting part - */ - protected function xml_start(){ - $attributes = ""; - - if ($this->dload){ - //info for dyn. loadin - if ($pos=$this->request->get_start()) - $attributes .= " pos='".$pos."'"; - else - $attributes .= " total_count='".$this->sql->get_size($this->request)."'"; - } - foreach($this->attributes as $k=>$v) - $attributes .= " ".$k."='".$v."'"; - - return "<data".$attributes.">"; - } - /*! renders self as xml, ending part - */ - protected function xml_end(){ - $this->fill_collections(); - if (isset($this->extra_output)) - return $this->extra_output."</data>"; - else - return "</data>"; - } - - protected function fill_collections($list=""){ - foreach ($this->options as $k=>$v) { - $name = $k; - $this->extra_output.="<coll_options for='{$name}'>"; - if (!is_string($this->options[$name])) - $this->extra_output.=$this->options[$name]->render(); - else - $this->extra_output.=$this->options[$name]; - $this->extra_output.="</coll_options>"; - } - } - - /*! assign options collection to the column - - @param name - name of the column - @param options - array or connector object - */ - public function set_options($name,$options){ - if (is_array($options)){ - $str=""; - foreach($options as $k => $v) - $str.="<item value='".$this->xmlentities($k)."' label='".$this->xmlentities($v)."' />"; - $options=$str; - } - $this->options[$name]=$options; - } - - - public function insert($data) { - $action = new DataAction('inserted', false, $data); - $request = new DataRequestConfig(); - $request->set_source($this->request->get_source()); - - $this->config->limit_fields($data); - $this->sql->insert($action,$request); - $this->config->restore_fields($data); - - return $action->get_new_id(); - } - - public function delete($id) { - $action = new DataAction('deleted', $id, array()); - $request = new DataRequestConfig(); - $request->set_source($this->request->get_source()); - - $this->sql->delete($action,$request); - return $action->get_status(); -} - - public function update($data) { - $action = new DataAction('updated', $data[$this->config->id["name"]], $data); - $request = new DataRequestConfig(); - $request->set_source($this->request->get_source()); - - $this->config->limit_fields($data); - $this->sql->update($action,$request); - $this->config->restore_fields($data); - - return $action->get_status(); - } - - /*! sets actions_table for Optimistic concurrency control mode and start it - @param table_name - name of database table which will used for saving actions - @param url - url used for update notifications - */ - public function enable_live_update($table, $url=false){ - $this->live_update = new DataUpdate($this->sql, $this->config, $this->request, $table,$url); - $this->live_update->set_event($this->event,$this->names["item_class"]); - $this->event->attach("beforeOutput", Array($this->live_update, "version_output")); - $this->event->attach("beforeFiltering", Array($this->live_update, "get_updates")); - $this->event->attach("beforeProcessing", Array($this->live_update, "check_collision")); - $this->event->attach("afterProcessing", Array($this->live_update, "log_operations")); - } - - /*! render() returns result as string or send to response - */ - public function asString($as_string) { - $this->as_string = $as_string; - } - - public function simple_render() { - $this->simple = true; - return $this->render(); - } - - public function filter($name, $value = false, $operation = '=') { - $this->filters[] = array('name' => $name, 'value' => $value, 'operation' => $operation); - } - - public function clear_filter() { - $this->filters = array(); - $this->request->set_filters(array()); - } - - protected function apply_filters($wrap) { - for ($i = 0; $i < count($this->filters); $i++) { - $f = $this->filters[$i]; - $wrap->add($f['name'], $f['value'], $f['operation']); - } - } - - public function sort($name, $direction = false) { - $this->sorts[] = array('name' => $name, 'direction' => $direction); - } - - protected function apply_sorts($wrap) { - for ($i = 0; $i < count($this->sorts); $i++) { - $s = $this->sorts[$i]; - $wrap->add($s['name'], $s['direction']); - } - } - - public function mix($name, $value, $filter=false) { - $this->mix[] = Array('name'=>$name, 'value'=>$value, 'filter'=>$filter); - } -} - - -/*! wrapper around options collection, used for comboboxes and filters -**/ -class OptionsConnector extends Connector{ - protected $init_flag=false;//!< used to prevent rendering while initialization - public function __construct($res,$type=false,$item_type=false,$data_type=false){ - if (!$item_type) $item_type="DataItem"; - if (!$data_type) $data_type=""; //has not sense, options not editable - parent::__construct($res,$type,$item_type,$data_type); - } - /*! render self - process commands, return data as XML, not output data to stdout, ignore parameters in incoming request - @return - data as XML string - */ - public function render(){ - if (!$this->init_flag){ - $this->init_flag=true; - return ""; - } - $res = $this->sql->select($this->request); - return $this->render_set($res); - } -} - - - -class DistinctOptionsConnector extends OptionsConnector{ - /*! render self - process commands, return data as XML, not output data to stdout, ignore parameters in incoming request - @return - data as XML string - */ - public function render(){ - if (!$this->init_flag){ - $this->init_flag=true; - return ""; - } - $res = $this->sql->get_variants($this->config->text[0]["db_name"],$this->request); - return $this->render_set($res); - } -} - -?>
\ No newline at end of file diff --git a/codebase/chart_connector.php b/codebase/chart_connector.php deleted file mode 100644 index 247d1e6..0000000 --- a/codebase/chart_connector.php +++ /dev/null @@ -1,18 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ - - require_once("dataview_connector.php"); - - -/*! Connector class for DataView -**/ -class ChartConnector extends DataViewConnector{ - public function __construct($res,$type=false,$item_type=false,$data_type=false){ - parent::__construct($res,$type,$item_type,$data_type); - } -} - -?>
\ No newline at end of file diff --git a/codebase/combo_connector.php b/codebase/combo_connector.php deleted file mode 100644 index 8fb5416..0000000 --- a/codebase/combo_connector.php +++ /dev/null @@ -1,94 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ - -require_once("base_connector.php"); -/*! DataItem class for Combo component -**/ -class ComboDataItem extends DataItem{ - private $selected;//!< flag of selected option - - function __construct($data,$config,$index){ - parent::__construct($data,$config,$index); - - $this->selected=false; - } - /*! mark option as selected - */ - function select(){ - $this->selected=true; - } - /*! return self as XML string, starting part - */ - function to_xml_start(){ - if ($this->skip) return ""; - - return "<option ".($this->selected?"selected='true'":"")."value='".$this->xmlentities($this->get_id())."'><![CDATA[".$this->data[$this->config->text[0]["name"]]."]]>"; - } - /*! return self as XML string, ending part - */ - function to_xml_end(){ - if ($this->skip) return ""; - return "</option>"; - } -} - -/*! Connector for the dhtmlxCombo -**/ -class ComboConnector extends Connector{ - private $filter; //!< filtering mask from incoming request - private $position; //!< position from incoming request - - /*! constructor - - Here initilization of all Masters occurs, execution timer initialized - @param res - db connection resource - @param type - string , which hold type of database ( MySQL or Postgre ), optional, instead of short DB name, full name of DataWrapper-based class can be provided - @param item_type - name of class, which will be used for item rendering, optional, DataItem will be used by default - @param data_type - name of class which will be used for dataprocessor calls handling, optional, DataProcessor class will be used by default. - */ - public function __construct($res,$type=false,$item_type=false,$data_type=false){ - if (!$item_type) $item_type="ComboDataItem"; - parent::__construct($res,$type,$item_type,$data_type); - } - - //parse GET scoope, all operations with incoming request must be done here - function parse_request(){ - parent::parse_request(); - - if (isset($_GET["pos"])){ - if (!$this->dload) //not critical, so just write a log message - LogMaster::log("Dyn loading request received, but server side was not configured to process dyn. loading. "); - else - $this->request->set_limit($_GET["pos"],$this->dload); - } - - if (isset($_GET["mask"])) - $this->request->set_filter($this->config->text[0]["db_name"],$_GET["mask"]."%","LIKE"); - - LogMaster::log($this->request); - } - - - /*! renders self as xml, starting part - */ - public function xml_start(){ - if ($this->request->get_start()) - return "<complete add='true'>"; - else - return "<complete>"; - } - - /*! renders self as xml, ending part - */ - public function xml_end(){ - return "</complete>"; - } -} -?>
\ No newline at end of file diff --git a/codebase/connector.js b/codebase/connector.js deleted file mode 100644 index 0ee9648..0000000 --- a/codebase/connector.js +++ /dev/null @@ -1,155 +0,0 @@ -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -if (window.dhtmlXGridObject && !dhtmlXGridObject.prototype._init_point_connector){ - dhtmlXGridObject.prototype._init_point_connector=dhtmlXGridObject.prototype._init_point; - dhtmlXGridObject.prototype._init_point=function(){ - //make separate config array for each grid - this._con_f_used = [].concat(this._con_f_used); - dhtmlXGridObject.prototype._con_f_used=[]; - - var clear_url=function(url){ - url=url.replace(/(\?|\&)connector[^\f]*/g,""); - return url+(url.indexOf("?")!=-1?"&":"?")+"connector=true"+(this.hdr.rows.length > 0 ? "&dhx_no_header=1":""); - }; - var combine_urls=function(url){ - return clear_url.call(this,url)+(this._connector_sorting||"")+(this._connector_filter||""); - }; - var sorting_url=function(url,ind,dir){ - this._connector_sorting="&dhx_sort["+ind+"]="+dir; - return combine_urls.call(this,url); - }; - var filtering_url=function(url,inds,vals){ - var chunks = []; - for (var i=0; i<inds.length; i++) - chunks[i]="dhx_filter["+inds[i]+"]="+encodeURIComponent(vals[i]); - this._connector_filter="&"+chunks.join("&"); - return combine_urls.call(this,url); - }; - this.attachEvent("onCollectValues",function(ind){ - if (this._con_f_used[ind]){ - if (typeof(this._con_f_used[ind]) == "object") - return this._con_f_used[ind]; - else - return false; - } - return true; - }); - this.attachEvent("onDynXLS",function(){ - this.xmlFileUrl=combine_urls.call(this,this.xmlFileUrl); - return true; - }); - this.attachEvent("onBeforeSorting",function(ind,type,dir){ - if (type=="connector"){ - var self=this; - this.clearAndLoad(sorting_url.call(this,this.xmlFileUrl,ind,dir),function(){ - self.setSortImgState(true,ind,dir); - }); - return false; - } - return true; - }); - this.attachEvent("onFilterStart",function(a,b){ - var ss = this.getSortingState(); - if (this._con_f_used.length){ - var self=this; - this.clearAndLoad(filtering_url.call(this,this.xmlFileUrl,a,b)); - if (ss.length) - self.setSortImgState(true,ss[0],ss[1]); - return false; - } - return true; - }); - this.attachEvent("onXLE",function(a,b,c,xml){ - if (!xml) return; - }); - - if (this._init_point_connector) this._init_point_connector(); - }; - dhtmlXGridObject.prototype._con_f_used=[]; - dhtmlXGridObject.prototype._in_header_connector_text_filter=function(t,i){ - if (!this._con_f_used[i]) - this._con_f_used[i]=1; - return this._in_header_text_filter(t,i); - }; - dhtmlXGridObject.prototype._in_header_connector_select_filter=function(t,i){ - if (!this._con_f_used[i]) - this._con_f_used[i]=2; - return this._in_header_select_filter(t,i); - }; - dhtmlXGridObject.prototype.load_connector=dhtmlXGridObject.prototype.load; - dhtmlXGridObject.prototype.load=function(url, call, type){ - if (!this._colls_loaded && this.cellType){ - var ar=[]; - for (var i=0; i < this.cellType.length; i++) - if (this.cellType[i].indexOf("co")==0 || this.cellType[i].indexOf("clist")==0 || this._con_f_used[i]==2) ar.push(i); - if (ar.length) - arguments[0]+=(arguments[0].indexOf("?")!=-1?"&":"?")+"connector=true&dhx_colls="+ar.join(","); - } - return this.load_connector.apply(this,arguments); - }; - dhtmlXGridObject.prototype._parseHead_connector=dhtmlXGridObject.prototype._parseHead; - dhtmlXGridObject.prototype._parseHead=function(url, call, type){ - this._parseHead_connector.apply(this,arguments); - if (!this._colls_loaded){ - var cols = this.xmlLoader.doXPath("./coll_options", arguments[0]); - for (var i=0; i < cols.length; i++){ - var f = cols[i].getAttribute("for"); - var v = []; - var combo=null; - if (this.cellType[f] == "combo") - combo = this.getColumnCombo(f); - else if (this.cellType[f].indexOf("co")==0) - combo=this.getCombo(f); - - var os = this.xmlLoader.doXPath("./item",cols[i]); - var opts = []; - for (var j=0; j<os.length; j++){ - var val=os[j].getAttribute("value"); - - if (combo){ - var lab=os[j].getAttribute("label")||val; - - if (combo.addOption) - opts.push([val, lab]); - else - combo.put(val,lab); - - v[v.length]=lab; - } else - v[v.length]=val; - } - if (opts.length){ - if (combo) - combo.addOption(opts); - } else if (v.length && !combo) - if (this.registerCList) - this.registerCList(f*1, v); - - - if (this._con_f_used[f*1]) - this._con_f_used[f*1]=v; - } - this._colls_loaded=true; - } - }; - - - - -} - -if (window.dataProcessor && !dataProcessor.prototype.init_original){ - dataProcessor.prototype.init_original=dataProcessor.prototype.init; - dataProcessor.prototype.init=function(obj){ - this.init_original(obj); - obj._dataprocessor=this; - - this.setTransactionMode("POST",true); - this.serverProcessor+=(this.serverProcessor.indexOf("?")!=-1?"&":"?")+"editing=true"; - }; -} -dhtmlxError.catchError("LoadXML",function(a,b,c){ - alert(c[0].responseText); -}); diff --git a/codebase/crosslink_connector.php b/codebase/crosslink_connector.php deleted file mode 100644 index 7d5c74c..0000000 --- a/codebase/crosslink_connector.php +++ /dev/null @@ -1,141 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("data_connector.php"); - -class DelayedConnector extends Connector{ - protected $init_flag=false;//!< used to prevent rendering while initialization - private $data_mode=false;//!< flag to separate xml and data request modes - private $data_result=false;//<! store results of query - - public function dataMode($name){ - $this->data_mode = $name; - $this->data_result=array(); - } - public function getDataResult(){ - return $this->data_result; - } - - public function render(){ - if (!$this->init_flag){ - $this->init_flag=true; - return ""; - } - return parent::render(); - } - - protected function output_as_xml($res){ - if ($this->data_mode){ - while ($data=$this->sql->get_next($res)){ - $this->data_result[]=$data[$this->data_mode]; - } - } - else - return parent::output_as_xml($res); - } - protected function end_run(){ - if (!$this->data_mode) - parent::end_run(); - } -} - -class CrossOptionsConnector extends Connector{ - public $options, $link; - private $master_name, $link_name, $master_value; - - public function __construct($res,$type=false,$item_type=false,$data_type=false){ - $this->options = new OptionsConnector($res,$type,$item_type,$data_type); - $this->link = new DelayedConnector($res,$type,$item_type,$data_type); - - EventMaster::attach_static("connectorInit",array($this, "handle")); - } - public function handle($conn){ - if ($conn instanceof DelayedConnector) return; - if ($conn instanceof OptionsConnector) return; - - $this->master_name = $this->link->get_config()->id["db_name"]; - $this->link_name = $this->options->get_config()->id["db_name"]; - - $this->link->event->attach("beforeFilter",array($this, "get_only_related")); - - if (isset($_GET["dhx_crosslink_".$this->link_name])){ - $this->get_links($_GET["dhx_crosslink_".$this->link_name]); - die(); - } - - if (!$this->dload){ - $conn->event->attach("beforeRender", array($this, "getOptions")); - $conn->event->attach("beforeRenderSet", array($this, "prepareConfig")); - } - - - $conn->event->attach("afterProcessing", array($this, "afterProcessing")); - } - public function prepareConfig($conn, $res, $config){ - $config->add_field($this->link_name); - } - public function getOptions($data){ - $this->link->dataMode($this->link_name); - - $this->get_links($data->get_value($this->master_name)); - - $data->set_value($this->link_name, implode(",",$this->link->getDataResult())); - } - public function get_links($id){ - $this->master_value = $id; - $this->link->render(); - } - public function get_only_related($filters){ - $index = $filters->index($this->master_name); - if ($index!==false){ - $filters->rules[$index]["value"]=$this->master_value; - } else - $filters->add($this->master_name, $this->master_value, "="); - } - public function afterProcessing($action){ - $status = $action->get_status(); - - $master_key = $action->get_id();//value($this->master_name); - $link_key = $action->get_value($this->link_name); - $link_key = explode(',', $link_key); - - if ($status == "inserted") - $master_key = $action->get_new_id(); - - switch ($status){ - case "deleted": - $this->link->delete($master_key); - break; - case "updated": - //cross link options not loaded yet, so we can skip update - if (!array_key_exists($this->link_name, $action->get_data())) - break; - //else, delete old options and continue in insert section to add new values - $this->link->delete($master_key); - case "inserted": - for ($i=0; $i < sizeof($link_key); $i++) - if ($link_key[$i]!="") - $this->link->insert(array( - $this->link_name => $link_key[$i], - $this->master_name => $master_key - )); - break; - } - } -} - - -class JSONCrossOptionsConnector extends CrossOptionsConnector{ - public $options, $link; - private $master_name, $link_name, $master_value; - - public function __construct($res,$type=false,$item_type=false,$data_type=false){ - $this->options = new JSONOptionsConnector($res,$type,$item_type,$data_type); - $this->link = new DelayedConnector($res,$type,$item_type,$data_type); - - EventMaster::attach_static("connectorInit",array($this, "handle")); - } -} -?>
\ No newline at end of file diff --git a/codebase/data_connector.php b/codebase/data_connector.php deleted file mode 100644 index 165cc0f..0000000 --- a/codebase/data_connector.php +++ /dev/null @@ -1,528 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("base_connector.php"); - -class CommonDataProcessor extends DataProcessor{ - protected function get_post_values($ids){ - if (isset($_GET['action'])){ - $data = array(); - if (isset($_POST["id"])){ - $dataset = array(); - foreach($_POST as $key=>$value) - $dataset[$key] = ConnectorSecurity::filter($value); - - $data[$_POST["id"]] = $dataset; - } - else - $data["dummy_id"] = $_POST; - return $data; - } - return parent::get_post_values($ids); - } - - protected function get_ids(){ - if (isset($_GET['action'])){ - if (isset($_POST["id"])) - return array($_POST['id']); - else - return array("dummy_id"); - } - return parent::get_ids(); - } - - protected function get_operation($rid){ - if (isset($_GET['action'])) - return $_GET['action']; - return parent::get_operation($rid); - } - - public function output_as_xml($results){ - if (isset($_GET['action'])){ - LogMaster::log("Edit operation finished",$results); - ob_clean(); - $type = $results[0]->get_status(); - if ($type == "error" || $type == "invalid"){ - echo "false"; - } else if ($type=="insert"){ - echo "true\n".$results[0]->get_new_id(); - } else - echo "true"; - } else - return parent::output_as_xml($results); - } -}; - -/*! DataItem class for DataView component -**/ -class CommonDataItem extends DataItem{ - /*! return self as XML string - */ - function to_xml(){ - if ($this->skip) return ""; - return $this->to_xml_start().$this->to_xml_end(); - } - - function to_xml_start(){ - $str="<item id='".$this->get_id()."' "; - for ($i=0; $i < sizeof($this->config->text); $i++){ - $name=$this->config->text[$i]["name"]; - $str.=" ".$name."='".$this->xmlentities($this->data[$name])."'"; - } - - if ($this->userdata !== false) - foreach ($this->userdata as $key => $value) - $str.=" ".$key."='".$this->xmlentities($value)."'"; - - return $str.">"; - } -} - - -/*! Connector class for DataView -**/ -class DataConnector extends Connector{ - - /*! constructor - - Here initilization of all Masters occurs, execution timer initialized - @param res - db connection resource - @param type - string , which hold type of database ( MySQL or Postgre ), optional, instead of short DB name, full name of DataWrapper-based class can be provided - @param item_type - name of class, which will be used for item rendering, optional, DataItem will be used by default - @param data_type - name of class which will be used for dataprocessor calls handling, optional, DataProcessor class will be used by default. - */ - public function __construct($res,$type=false,$item_type=false,$data_type=false,$render_type=false){ - if (!$item_type) $item_type="CommonDataItem"; - if (!$data_type) $data_type="CommonDataProcessor"; - - $this->sections = array(); - - if (!$render_type) $render_type="RenderStrategy"; - parent::__construct($res,$type,$item_type,$data_type,$render_type); - - } - - protected $sections; - public function add_section($name, $string){ - $this->sections[$name] = $string; - } - - protected function parse_request_mode(){ - if (isset($_GET['action']) && $_GET["action"] != "get") - $this->editing = true; - else - parent::parse_request_mode(); - } - - //parse GET scoope, all operations with incoming request must be done here - protected function parse_request(){ - if (isset($_GET['action'])){ - $action = $_GET['action']; - //simple request mode - if ($action == "get"){ - //data request - if (isset($_GET['id'])){ - //single entity data request - $this->request->set_filter($this->config->id["name"],$_GET['id'],"="); - } else { - //loading collection of items - } - } else { - //data saving - $this->editing = true; - } - parent::check_csrf(); - } else { - if (isset($_GET['editing']) && isset($_POST['ids'])) - $this->editing = true; - parent::parse_request(); - } - - if (isset($_GET["start"]) && isset($_GET["count"])) - $this->request->set_limit($_GET["start"],$_GET["count"]); - - } - - /*! renders self as xml, starting part - */ - protected function xml_start(){ - $start = "<data"; - foreach($this->attributes as $k=>$v) - $start .= " ".$k."='".$v."'"; - $start.= ">"; - - foreach($this->sections as $k=>$v) - $start .= "<".$k.">".$v."</".$k.">\n"; - return $start; - } -}; - -class JSONDataConnector extends DataConnector{ - - public function __construct($res,$type=false,$item_type=false,$data_type=false,$render_type=false){ - if (!$item_type) $item_type="JSONCommonDataItem"; - if (!$data_type) $data_type="CommonDataProcessor"; - if (!$render_type) $render_type="JSONRenderStrategy"; - $this->data_separator = ",\n"; - parent::__construct($res,$type,$item_type,$data_type,$render_type); - } - - /*! assign options collection to the column - - @param name - name of the column - @param options - array or connector object - */ - public function set_options($name,$options){ - if (is_array($options)){ - $str=array(); - foreach($options as $k => $v) - $str[]='{"id":"'.$this->xmlentities($k).'", "value":"'.$this->xmlentities($v).'"}'; - $options=implode(",",$str); - } - $this->options[$name]=$options; - } - - /*! generates xml description for options collections - - @param list - comma separated list of column names, for which options need to be generated - */ - protected function fill_collections($list=""){ - $options = array(); - foreach ($this->options as $k=>$v) { - $name = $k; - $option="\"{$name}\":["; - if (!is_string($this->options[$name])) - $option.=substr(json_encode($this->options[$name]->render()),1,-1); - else - $option.=$this->options[$name]; - $option.="]"; - $options[] = $option; - } - $this->extra_output .= implode($this->data_separator, $options); - } - - protected function resolve_parameter($name){ - if (intval($name).""==$name) - return $this->config->text[intval($name)]["db_name"]; - return $name; - } - - protected function output_as_xml($res){ - $json = $this->render_set($res); - if ($this->simple) return $json; - $result = json_encode($json); - - $this->fill_collections(); - $is_sections = sizeof($this->sections) && $this->is_first_call(); - if ($this->dload || $is_sections || sizeof($this->attributes) || !empty($this->extra_data)){ - - $attributes = ""; - foreach($this->attributes as $k=>$v) - $attributes .= ", \"".$k."\":\"".$v."\""; - - $extra = ""; - if (!empty($this->extra_output)) - $extra .= ', "collections": {'.$this->extra_output.'}'; - - $sections = ""; - if ($is_sections){ - //extra sections - foreach($this->sections as $k=>$v) - $sections .= ", \"".$k."\":".$v; - } - - $dyn = ""; - if ($this->dload){ - //info for dyn. loadin - if ($pos=$this->request->get_start()) - $dyn .= ", \"pos\":".$pos; - else - $dyn .= ", \"pos\":0, \"total_count\":".$this->sql->get_size($this->request); - } - if ($attributes || $sections || $this->extra_output || $dyn) { - $result = "{ \"data\":".$result.$attributes.$extra.$sections.$dyn."}"; - } - } - - // return as string - if ($this->as_string) return $result; - - // output direct to response - $out = new OutputWriter($result, ""); - $out->set_type("json"); - $this->event->trigger("beforeOutput", $this, $out); - $out->output("", true, $this->encoding); - return null; - } -} - -class JSONCommonDataItem extends DataItem{ - /*! return self as XML string - */ - function to_xml(){ - if ($this->skip) return false; - - $data = array( - 'id' => $this->get_id() - ); - for ($i=0; $i<sizeof($this->config->text); $i++){ - $extra = $this->config->text[$i]["name"]; - $data[$extra]=$this->data[$extra]; - if (is_null($data[$extra])) - $data[$extra] = ""; - } - - if ($this->userdata !== false) - foreach ($this->userdata as $key => $value){ - if ($value === null) - $data[$key]=""; - $data[$key]=$value; - } - - return $data; - } -} - - -/*! wrapper around options collection, used for comboboxes and filters -**/ -class JSONOptionsConnector extends JSONDataConnector{ - protected $init_flag=false;//!< used to prevent rendering while initialization - public function __construct($res,$type=false,$item_type=false,$data_type=false){ - if (!$item_type) $item_type="JSONCommonDataItem"; - if (!$data_type) $data_type=""; //has not sense, options not editable - parent::__construct($res,$type,$item_type,$data_type); - } - /*! render self - process commands, return data as XML, not output data to stdout, ignore parameters in incoming request - @return - data as XML string - */ - public function render(){ - if (!$this->init_flag){ - $this->init_flag=true; - return ""; - } - $res = $this->sql->select($this->request); - return $this->render_set($res); - } -} - - -class JSONDistinctOptionsConnector extends JSONOptionsConnector{ - /*! render self - process commands, return data as XML, not output data to stdout, ignore parameters in incoming request - @return - data as XML string - */ - public function render(){ - if (!$this->init_flag){ - $this->init_flag=true; - return ""; - } - $res = $this->sql->get_variants($this->config->text[0]["db_name"],$this->request); - return $this->render_set($res); - } -} - - - -class TreeCommonDataItem extends CommonDataItem{ - protected $kids=-1; - - function to_xml_start(){ - $str="<item id='".$this->get_id()."' "; - for ($i=0; $i < sizeof($this->config->text); $i++){ - $name=$this->config->text[$i]["name"]; - $str.=" ".$name."='".$this->xmlentities($this->data[$name])."'"; - } - - if ($this->userdata !== false) - foreach ($this->userdata as $key => $value) - $str.=" ".$key."='".$this->xmlentities($value)."'"; - - if ($this->kids === true) - $str .=" ".Connector::$kids_var."='1'"; - - return $str.">"; - } - - function has_kids(){ - return $this->kids; - } - - function set_kids($value){ - $this->kids=$value; - } -} - - -class TreeDataConnector extends DataConnector{ - protected $parent_name = 'parent'; - public $rootId = "0"; - - /*! constructor - - Here initilization of all Masters occurs, execution timer initialized - @param res - db connection resource - @param type - string , which hold type of database ( MySQL or Postgre ), optional, instead of short DB name, full name of DataWrapper-based class can be provided - @param item_type - name of class, which will be used for item rendering, optional, DataItem will be used by default - @param data_type - name of class which will be used for dataprocessor calls handling, optional, DataProcessor class will be used by default. - * @param render_type - * name of class which will provides data rendering - */ - public function __construct($res,$type=false,$item_type=false,$data_type=false,$render_type=false){ - if (!$item_type) $item_type="TreeCommonDataItem"; - if (!$data_type) $data_type="CommonDataProcessor"; - if (!$render_type) $render_type="TreeRenderStrategy"; - parent::__construct($res,$type,$item_type,$data_type,$render_type); - } - - //parse GET scoope, all operations with incoming request must be done here - protected function parse_request(){ - parent::parse_request(); - - if (isset($_GET[$this->parent_name])) - $this->request->set_relation($_GET[$this->parent_name]); - else - $this->request->set_relation($this->rootId); - - $this->request->set_limit(0,0); //netralize default reaction on dyn. loading mode - } - - /*! renders self as xml, starting part - */ - protected function xml_start(){ - $attributes = " "; - if (!$this->rootId || $this->rootId != $this->request->get_relation()) - $attributes = " parent='".$this->request->get_relation()."' "; - - foreach($this->attributes as $k=>$v) - $attributes .= " ".$k."='".$v."'"; - - return "<data".$attributes.">"; - } -} - - -class JSONTreeDataConnector extends TreeDataConnector{ - - public function __construct($res,$type=false,$item_type=false,$data_type=false,$render_type=false){ - if (!$item_type) $item_type="JSONTreeCommonDataItem"; - if (!$data_type) $data_type="CommonDataProcessor"; - if (!$render_type) $render_type="JSONTreeRenderStrategy"; - parent::__construct($res,$type,$item_type,$data_type,$render_type); - } - - protected function output_as_xml($res){ - $result = $this->render_set($res); - if ($this->simple) return $result; - - $data = array(); - if (!$this->rootId || $this->rootId != $this->request->get_relation()) - $data["parent"] = $this->request->get_relation(); - - $data["data"] = $result; - - $this->fill_collections(); - if (!empty($this->options)) - $data["collections"] = $this->options; - - - foreach($this->attributes as $k=>$v) - $data[$k] = $v; - - $data = json_encode($data); - - // return as string - if ($this->as_string) return $data; - - // output direct to response - $out = new OutputWriter($data, ""); - $out->set_type("json"); - $this->event->trigger("beforeOutput", $this, $out); - $out->output("", true, $this->encoding); - } - - /*! assign options collection to the column - - @param name - name of the column - @param options - array or connector object - */ - public function set_options($name,$options){ - if (is_array($options)){ - $str=array(); - foreach($options as $k => $v) - $str[]=Array("id"=>$this->xmlentities($k), "value"=>$this->xmlentities($v));//'{"id":"'.$this->xmlentities($k).'", "value":"'.$this->xmlentities($v).'"}'; - $options=$str; - } - $this->options[$name]=$options; - } - - /*! generates xml description for options collections - - @param list - comma separated list of column names, for which options need to be generated - */ - protected function fill_collections($list=""){ - $options = array(); - foreach ($this->options as $k=>$v) { - $name = $k; - if (!is_array($this->options[$name])) - $option=$this->options[$name]->render(); - else - $option=$this->options[$name]; - $options[$name] = $option; - } - $this->options = $options; - $this->extra_output .= "'collections':".json_encode($options); - } - -} - - -class JSONTreeCommonDataItem extends TreeCommonDataItem{ - /*! return self as XML string - */ - function to_xml_start(){ - if ($this->skip) return false; - - $data = array( "id" => $this->get_id() ); - for ($i=0; $i<sizeof($this->config->text); $i++){ - $extra = $this->config->text[$i]["name"]; - if (isset($this->data[$extra])) - $data[$extra]=$this->data[$extra]; - } - - if ($this->userdata !== false) - foreach ($this->userdata as $key => $value) - $data[$key]=$value; - - if ($this->kids === true) - $data[Connector::$kids_var] = 1; - - return $data; - } - - function to_xml_end(){ - return ""; - } -} - - -?> diff --git a/codebase/dataprocessor.php b/codebase/dataprocessor.php deleted file mode 100644 index 89a4460..0000000 --- a/codebase/dataprocessor.php +++ /dev/null @@ -1,521 +0,0 @@ -<?php
-/*
- @author dhtmlx.com
- @license GPL, see license.txt
-*/
-/*! Base DataProcessor handling
-**/
-
-require_once("xss_filter.php");
-
-class DataProcessor{
- protected $connector;//!< Connector instance
- protected $config;//!< DataConfig instance
- protected $request;//!< DataRequestConfig instance
- static public $action_param ="!nativeeditor_status";
-
- /*! constructor
-
- @param connector
- Connector object
- @param config
- DataConfig object
- @param request
- DataRequestConfig object
- */
- function __construct($connector,$config,$request){
- $this->connector= $connector;
- $this->config=$config;
- $this->request=$request;
- }
-
- /*! convert incoming data name to valid db name
- redirect to Connector->name_data by default
- @param data
- data name from incoming request
- @return
- related db_name
- */
- function name_data($data){
- return $data;
- }
- /*! retrieve data from incoming request and normalize it
-
- @param ids
- array of extected IDs
- @return
- hash of data
- */
- protected function get_post_values($ids){
- $data=array();
- for ($i=0; $i < sizeof($ids); $i++)
- $data[$ids[$i]]=array();
-
- foreach ($_POST as $key => $value) {
- $details=explode("_",$key,2);
- if (sizeof($details)==1) continue;
-
- $name=$this->name_data($details[1]);
- $data[$details[0]][$name]=ConnectorSecurity::filter($value);
- }
-
- return $data;
- }
- protected function get_ids(){
- if (!isset($_POST["ids"]))
- throw new Exception("Incorrect incoming data, ID of incoming records not recognized");
- return explode(",",$_POST["ids"]);
- }
-
- protected function get_operation($rid){
- if (!isset($_POST[$rid."_".DataProcessor::$action_param]))
- throw new Exception("Status of record [{$rid}] not found in incoming request");
- return $_POST[$rid."_".DataProcessor::$action_param];
- }
- /*! process incoming request ( save|update|delete )
- */
- function process(){
- LogMaster::log("DataProcessor object initialized",$_POST);
-
- $results=array();
-
- $ids=$this->get_ids();
- $rows_data=$this->get_post_values($ids);
- $failed=false;
-
- try{
- if ($this->connector->sql->is_global_transaction())
- $this->connector->sql->begin_transaction();
-
- for ($i=0; $i < sizeof($ids); $i++) {
- $rid = $ids[$i];
- LogMaster::log("Row data [{$rid}]",$rows_data[$rid]);
- $status = $this->get_operation($rid);
-
- $action=new DataAction($status,$rid,$rows_data[$rid]);
- $results[]=$action;
- $this->inner_process($action);
- }
-
- } catch(Exception $e){
- LogMaster::log($e);
- $failed=true;
- }
-
- if ($this->connector->sql->is_global_transaction()){
- if (!$failed)
- for ($i=0; $i < sizeof($results); $i++)
- if ($results[$i]->get_status()=="error" || $results[$i]->get_status()=="invalid"){
- $failed=true;
- break;
- }
- if ($failed){
- for ($i=0; $i < sizeof($results); $i++)
- $results[$i]->error();
- $this->connector->sql->rollback_transaction();
- }
- else
- $this->connector->sql->commit_transaction();
- }
-
- $this->output_as_xml($results);
- }
-
- /*! converts status string to the inner mode name
-
- @param status
- external status string
- @return
- inner mode name
- */
- protected function status_to_mode($status){
- switch($status){
- case "updated":
- return "update";
- break;
- case "inserted":
- return "insert";
- break;
- case "deleted":
- return "delete";
- break;
- default:
- return $status;
- break;
- }
- }
- /*! process data updated request received
-
- @param action
- DataAction object
- @return
- DataAction object with details of processing
- */
- protected function inner_process($action){
-
- if ($this->connector->sql->is_record_transaction())
- $this->connector->sql->begin_transaction();
-
- try{
-
- $mode = $this->status_to_mode($action->get_status());
- if (!$this->connector->access->check($mode)){
- LogMaster::log("Access control: {$mode} operation blocked");
- $action->error();
- } else {
- $check = $this->connector->event->trigger("beforeProcessing",$action);
- if (!$action->is_ready())
- $this->check_exts($action,$mode);
- if ($mode == "insert" && $action->get_status() != "error" && $action->get_status() != "invalid")
- $this->connector->sql->new_record_order($action, $this->request);
-
- $check = $this->connector->event->trigger("afterProcessing",$action);
- }
-
- } catch (Exception $e){
- LogMaster::log($e);
- $action->set_status("error");
- if ($action)
- $this->connector->event->trigger("onDBError", $action, $e);
- }
-
- if ($this->connector->sql->is_record_transaction()){
- if ($action->get_status()=="error" || $action->get_status()=="invalid")
- $this->connector->sql->rollback_transaction();
- else
- $this->connector->sql->commit_transaction();
- }
-
- return $action;
- }
-
- /*! check if some event intercepts processing, send data to DataWrapper in other case
-
- @param action
- DataAction object
- @param mode
- name of inner mode ( will be used to generate event names )
- */
- function check_exts($action,$mode){
- $old_config = new DataConfig($this->config);
-
- $this->connector->event->trigger("before".$mode,$action);
- if ($action->is_ready())
- LogMaster::log("Event code for ".$mode." processed");
- else {
- //check if custom sql defined
- $sql = $this->connector->sql->get_sql($mode,$action);
- if ($sql){
- $this->connector->sql->query($sql);
- }
- else{
- $action->sync_config($this->config);
- if ($this->connector->model && method_exists($this->connector->model, $mode)){
- call_user_func(array($this->connector->model, $mode), $action);
- LogMaster::log("Model object process action: ".$mode);
- }
- if (!$action->is_ready()){
- $method=array($this->connector->sql,$mode);
- if (!is_callable($method))
- throw new Exception("Unknown dataprocessing action: ".$mode);
- call_user_func($method,$action,$this->request);
- }
- }
- }
- $this->connector->event->trigger("after".$mode,$action);
-
- $this->config->copy($old_config);
- }
-
- /*! output xml response for dataprocessor
-
- @param results
- array of DataAction objects
- */
- function output_as_xml($results){
- LogMaster::log("Edit operation finished",$results);
- ob_clean();
- header("Content-type:text/xml");
- echo "<?xml version='1.0' ?>";
- echo "<data>";
- for ($i=0; $i < sizeof($results); $i++)
- echo $results[$i]->to_xml();
- echo "</data>";
- }
-
-}
-
-/*! contain all info related to action and controls customizaton
-**/
-class DataAction{
- private $status; //!< cuurent status of record
- private $id;//!< id of record
- private $data;//!< data hash of record
- private $userdata;//!< hash of extra data , attached to record
- private $nid;//!< new id value , after operation executed
- private $output;//!< custom output to client side code
- private $attrs;//!< hash of custtom attributes
- private $ready;//!< flag of operation's execution
- private $addf;//!< array of added fields
- private $delf;//!< array of deleted fields
-
-
- /*! constructor
-
- @param status
- current operation status
- @param id
- record id
- @param data
- hash of data
- */
- function __construct($status,$id,$data){
- $this->status=$status;
- $this->id=$id;
- $this->data=$data;
- $this->nid=$id;
-
- $this->output="";
- $this->attrs=array();
- $this->ready=false;
-
- $this->addf=array();
- $this->delf=array();
- }
-
-
- /*! add custom field and value to DB operation
-
- @param name
- name of field which will be added to DB operation
- @param value
- value which will be used for related field in DB operation
- */
- function add_field($name,$value){
- LogMaster::log("adding field: ".$name.", with value: ".$value);
- $this->data[$name]=$value;
- $this->addf[]=$name;
- }
- /*! remove field from DB operation
-
- @param name
- name of field which will be removed from DB operation
- */
- function remove_field($name){
- LogMaster::log("removing field: ".$name);
- $this->delf[]=$name;
- }
-
- /*! sync field configuration with external object
-
- @param slave
- SQLMaster object
- @todo
- check , if all fields removed then cancel action
- */
- function sync_config($slave){
- foreach ($this->addf as $k => $v)
- $slave->add_field($v);
- foreach ($this->delf as $k => $v)
- $slave->remove_field($v);
- }
- /*! get value of some record's propery
-
- @param name
- name of record's property ( name of db field or alias )
- @return
- value of related property
- */
- function get_value($name){
- if (!array_key_exists($name,$this->data)){
- LogMaster::log("Incorrect field name used: ".$name);
- LogMaster::log("data",$this->data);
- return "";
- }
- return $this->data[$name];
- }
- /*! set value of some record's propery
-
- @param name
- name of record's property ( name of db field or alias )
- @param value
- value of related property
- */
- function set_value($name,$value){
- LogMaster::log("change value of: ".$name." as: ".$value);
- $this->data[$name]=$value;
- }
- /*! get hash of data properties
-
- @return
- hash of data properties
- */
- function get_data(){
- return $this->data;
- }
- /*! get some extra info attached to record
- deprecated, exists just for backward compatibility, you can use set_value instead of it
- @param name
- name of userdata property
- @return
- value of related userdata property
- */
- function get_userdata_value($name){
- return $this->get_value($name);
- }
- /*! set some extra info attached to record
- deprecated, exists just for backward compatibility, you can use get_value instead of it
- @param name
- name of userdata property
- @param value
- value of userdata property
- */
- function set_userdata_value($name,$value){
- return $this->set_value($name,$value);
- }
- /*! get current status of record
-
- @return
- string with status value
- */
- function get_status(){
- return $this->status;
- }
- /*! assign new status to the record
-
- @param status
- new status value
- */
- function set_status($status){
- $this->status=$status;
- }
- /*! set id
- @param id
- id value
- */
- function set_id($id) {
- $this->id = $id;
- LogMaster::log("Change id: ".$id);
- }
- /*! set id
- @param id
- id value
- */
- function set_new_id($id) {
- $this->nid = $id;
- LogMaster::log("Change new id: ".$id);
- }
- /*! get id of current record
-
- @return
- id of record
- */
- function get_id(){
- return $this->id;
- }
- /*! sets custom response text
-
- can be accessed through defineAction on client side. Text wrapped in CDATA, so no extra escaping necessary
- @param text
- custom response text
- */
- function set_response_text($text){
- $this->set_response_xml("<![CDATA[".$text."]]>");
- }
- /*! sets custom response xml
-
- can be accessed through defineAction on client side
- @param text
- string with XML data
- */
- function set_response_xml($text){
- $this->output=$text;
- }
- /*! sets custom response attributes
-
- can be accessed through defineAction on client side
- @param name
- name of custom attribute
- @param value
- value of custom attribute
- */
- function set_response_attribute($name,$value){
- $this->attrs[$name]=$value;
- }
- /*! check if action finished
-
- @return
- true if action finished, false otherwise
- */
- function is_ready(){
- return $this->ready;
- }
- /*! return new id value
-
- equal to original ID normally, after insert operation - value assigned for new DB record
- @return
- new id value
- */
- function get_new_id(){
- return $this->nid;
- }
-
- /*! set result of operation as error
- */
- function error(){
- $this->status="error";
- $this->ready=true;
- }
- /*! set result of operation as invalid
- */
- function invalid(){
- $this->status="invalid";
- $this->ready=true;
- }
- /*! confirm successful opeation execution
- @param id
- new id value, optional
- */
- function success($id=false){
- if ($id!==false)
- $this->nid = $id;
- $this->ready=true;
- }
- /*! convert DataAction to xml format compatible with client side dataProcessor
- @return
- DataAction operation report as XML string
- */
- function to_xml(){
- $str="<action type='{$this->status}' sid='{$this->id}' tid='{$this->nid}' ";
- foreach ($this->attrs as $k => $v) {
- $str.=$k."='".$this->xmlentities($v)."' ";
- }
- $str.=">{$this->output}</action>";
- return $str;
- }
-
- /*! replace xml unsafe characters
-
- @param string
- string to be escaped
- @return
- escaped string
- */
- public function xmlentities($string) {
- return str_replace( array( '&', '"', "'", '<', '>', '’' ), array( '&' , '"', ''' , '<' , '>', ''' ), $string);
- }
-
- /*! convert self to string ( for logs )
-
- @return
- DataAction operation report as plain string
- */
- function __toString(){
- return "action:{$this->status}; sid:{$this->id}; tid:{$this->nid};";
- }
-
-
-}
-
-
-?>
\ No newline at end of file diff --git a/codebase/dataview_connector.php b/codebase/dataview_connector.php deleted file mode 100644 index fe2c9fd..0000000 --- a/codebase/dataview_connector.php +++ /dev/null @@ -1,73 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("base_connector.php"); - -/*! DataItem class for DataView component -**/ -class DataViewDataItem extends DataItem{ - /*! return self as XML string - */ - function to_xml(){ - if ($this->skip) return ""; - - $str="<item id='".$this->get_id()."' >"; - for ($i=0; $i<sizeof($this->config->text); $i++){ - $extra = $this->config->text[$i]["name"]; - $str.="<".$extra."><![CDATA[".$this->data[$extra]."]]></".$extra.">"; - } - return $str."</item>"; - } -} - - -/*! Connector class for DataView -**/ -class DataViewConnector extends Connector{ - - /*! constructor - - Here initilization of all Masters occurs, execution timer initialized - @param res - db connection resource - @param type - string , which hold type of database ( MySQL or Postgre ), optional, instead of short DB name, full name of DataWrapper-based class can be provided - @param item_type - name of class, which will be used for item rendering, optional, DataItem will be used by default - @param data_type - name of class which will be used for dataprocessor calls handling, optional, DataProcessor class will be used by default. - */ - public function __construct($res,$type=false,$item_type=false,$data_type=false){ - if (!$item_type) $item_type="DataViewDataItem"; - if (!$data_type) $data_type="DataProcessor"; - parent::__construct($res,$type,$item_type,$data_type); - } - - //parse GET scoope, all operations with incoming request must be done here - function parse_request(){ - parent::parse_request(); - - if (isset($_GET["posStart"]) && isset($_GET["count"])) - $this->request->set_limit($_GET["posStart"],$_GET["count"]); - } - - /*! renders self as xml, starting part - */ - protected function xml_start(){ - $attributes = ""; - foreach($this->attributes as $k=>$v) - $attributes .= " ".$k."='".$v."'"; - - if ($this->dload){ - if ($pos=$this->request->get_start()) - return "<data pos='".$pos."'".$attributes.">"; - else - return "<data total_count='".$this->sql->get_size($this->request)."'".$attributes.">"; - } - else - return "<data".$attributes.">"; - } -} -?>
\ No newline at end of file diff --git a/codebase/db_adodb.php b/codebase/db_adodb.php deleted file mode 100644 index 5250c21..0000000 --- a/codebase/db_adodb.php +++ /dev/null @@ -1,72 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("db_common.php"); -/*! Implementation of DataWrapper for PostgreSQL -**/ -class AdoDBDataWrapper extends DBDataWrapper{ - protected $last_result; - public function query($sql){ - LogMaster::log($sql); - if (is_array($sql)) { - $res = $this->connection->SelectLimit($sql['sql'], $sql['numrows'], $sql['offset']); - } else { - $res = $this->connection->Execute($sql); - } - - if ($res===false) throw new Exception("ADODB operation failed\n".$this->connection->ErrorMsg()); - $this->last_result = $res; - return $res; - } - - public function get_next($res){ - if (!$res) - $res = $this->last_result; - - if ($res->EOF) - return false; - - $row = $res->GetRowAssoc(false); - $res->MoveNext(); - return $row; - } - - protected function get_new_id(){ - return $this->connection->Insert_ID(); - } - - public function escape($data){ - return $this->connection->addq($data); - } - - /*! escape field name to prevent sql reserved words conflict - @param data - unescaped data - @return - escaped data - */ - public function escape_name($data){ - if ((strpos($data,"`")!==false || is_int($data)) || (strpos($data,".")!==false)) - return $data; - return '`'.$data.'`'; - } - - - protected function select_query($select,$from,$where,$sort,$start,$count){ - if (!$from) - return $select; - - $sql="SELECT ".$select." FROM ".$from; - if ($where) $sql.=" WHERE ".$where; - if ($sort) $sql.=" ORDER BY ".$sort; - - if ($start || $count) { - $sql=array("sql"=>$sql,'numrows'=>$count, 'offset'=>$start); - } - return $sql; - } - -} -?>
\ No newline at end of file diff --git a/codebase/db_common.php b/codebase/db_common.php deleted file mode 100644 index f6391d2..0000000 --- a/codebase/db_common.php +++ /dev/null @@ -1,1157 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("tools.php"); - -/*! manager of data request -**/ -class DataRequestConfig{ - private $filters; //!< array of filtering rules - private $relation=false; //!< ID or other element used for linking hierarchy - private $sort_by; //!< sorting field - private $start; //!< start of requested data - private $count; //!< length of requested data - - private $order = false; - private $user; - private $version; - - //for render_sql - private $source; //!< souce table or another source destination - private $fieldset; //!< set of data, which need to be retrieved from source - - /*! constructor - - @param proto - DataRequestConfig object, optional, if provided then new request object will copy all properties from provided one - */ - public function __construct($proto=false){ - if ($proto) - $this->copy($proto); - else{ - $start=0; - $this->filters=array(); - $this->sort_by=array(); - } - } - - /*! copy parameters of source object into self - - @param proto - source object - */ - public function copy($proto){ - $this->filters =$proto->get_filters(); - $this->sort_by =$proto->get_sort_by(); - $this->count =$proto->get_count(); - $this->start =$proto->get_start(); - $this->source =$proto->get_source(); - $this->fieldset =$proto->get_fieldset(); - $this->relation =$proto->get_relation(); - $this->user = $proto->user; - $this->version = $proto->version; - } - - /*! convert self to string ( for logs ) - @return - self as plain string, - */ - public function __toString(){ - $str="Source:{$this->source}\nFieldset:{$this->fieldset}\nWhere:"; - for ($i=0; $i < sizeof($this->filters); $i++) - $str.=$this->filters[$i]["name"]." ".$this->filters[$i]["operation"]." ".$this->filters[$i]["value"].";"; - $str.="\nStart:{$this->start}\nCount:{$this->count}\n"; - for ($i=0; $i < sizeof($this->sort_by); $i++) - $str.=$this->sort_by[$i]["name"]."=".$this->sort_by[$i]["direction"].";"; - $str.="\nRelation:{$this->relation}"; - return $str; - } - - /*! returns set of filtering rules - @return - set of filtering rules - */ - public function get_filters(){ - return $this->filters; - } - public function &get_filters_ref(){ - return $this->filters; - } - public function set_filters($data){ - $this->filters=$data; - } - - - public function get_order(){ - return $this->order; - } - public function set_order($order){ - $this->order = $order; - } - public function get_user(){ - return $this->user; - } - public function set_user($user){ - $this->user = $user; - } - public function get_version(){ - return $this->version; - } - public function set_version($version){ - $this->version = $version; - } - - /*! returns list of used fields - @return - list of used fields - */ - public function get_fieldset(){ - return $this->fieldset; - } - /*! returns name of source table - @return - name of source table - */ - public function get_source(){ - return $this->source; - } - /*! returns set of sorting rules - @return - set of sorting rules - */ - public function get_sort_by(){ - return $this->sort_by; - } - public function &get_sort_by_ref(){ - return $this->sort_by; - } - public function set_sort_by($data){ - $this->sort_by=$data; - } - - /*! returns start index - @return - start index - */ - public function get_start(){ - return $this->start; - } - /*! returns count of requested records - @return - count of requested records - */ - public function get_count(){ - return $this->count; - } - /*! returns name of relation id - @return - relation id name - */ - public function get_relation(){ - return $this->relation; - } - - /*! sets sorting rule - - @param field - name of column - @param order - direction of sorting - */ - public function set_sort($field,$order=false){ - if (!$field && !$order) - $this->sort_by=array(); - else{ - if ($order===false) - $this->sort_by[] = $field; - else { - $order=strtolower($order)=="asc"?"ASC":"DESC"; - $this->sort_by[]=array("name"=>$field,"direction" => $order); - } - } - } - /*! sets filtering rule - - @param field - name of column - @param value - value for filtering - @param operation - operation for filtering, optional , LIKE by default - */ - public function set_filter($field,$value=false,$operation=false){ - if ($value === false) - array_push($this->filters,$field); - else - array_push($this->filters,array("name"=>$field,"value"=>$value,"operation"=>$operation)); - } - - /*! sets list of used fields - - @param value - list of used fields - */ - public function set_fieldset($value){ - $this->fieldset=$value; - } - /*! sets name of source table - - @param value - name of source table - */ - public function set_source($value){ - if (is_string($value)) - $value = trim($value); - $this->source = $value; - if (!$this->source) throw new Exception("Source of data can't be empty"); - } - /*! sets data limits - - @param start - start index - @param count - requested count of data - */ - public function set_limit($start,$count){ - $this->start=$start; - $this->count=$count; - } - /*! sets name of relation id - - @param value - name of relation id field - */ - public function set_relation($value){ - $this->relation=$value; - } - /*! parse incoming sql, to fill other properties - - @param sql - incoming sql string - */ - public function parse_sql($sql, $as_is = false){ - if ($as_is){ - $this->fieldset = $sql; - return; - } - - $sql= preg_replace("/[ \n\t]+limit[\n\t ,0-9]*$/i","",$sql); - - $data = preg_split("/[ \n\t]+\\_from\\_/i",$sql,2); - if (count($data)!=2) - $data = preg_split("/[ \n\t]+from/i",$sql,2); - $this->fieldset = preg_replace("/^[\s]*select/i","",$data[0],1); - - //Ignore next type of calls - //direct call to stored procedure without FROM - if ((count($data) == 1) || - //UNION select - preg_match("#[ \n\r\t]union[ \n\t\r]#i", $sql)){ - $this->fieldset = $sql; - return; - } - - $table_data = preg_split("/[ \n\t]+where/i",$data[1],2); - /* - if sql code contains group_by we will place all sql query in the FROM - it will not allow to use any filtering against the query - still it is better than just generate incorrect sql commands for any group by query - */ - if (sizeof($table_data)>1 && !preg_match("#.*group by.*#i",$table_data[1])){ //where construction exists - $this->set_source($table_data[0]); - $where_data = preg_split("/[ \n\t]+order[ ]+by/i",$table_data[1],2); - $this->filters[]=$where_data[0]; - if (sizeof($where_data)==1) return; //end of line detected - $data=$where_data[1]; - } else { - $table_data = preg_split("/[ \n\t]+order[ ]+by/i",$data[1],2); - $this->set_source($table_data[0]); - if (sizeof($table_data)==1) return; //end of line detected - $data=$table_data[1]; - } - - if (trim($data)){ //order by construction exists - $s_data = preg_split("/\\,/",trim($data)); - for ($i=0; $i < count($s_data); $i++) { - $data=preg_split("/[ ]+/",trim($s_data[$i]),2); - if (sizeof($data)>1) - $this->set_sort($data[0],$data[1]); - else - $this->set_sort($data[0]); - } - - } - } -} - -/*! manager of data configuration -**/ -class DataConfig{ - public $id;////!< name of ID field - public $relation_id;//!< name or relation ID field - public $text;//!< array of text fields - public $data;//!< array of all known fields , fields which exists only in this collection will not be included in dataprocessor's operations - - - /*! converts self to the string, for logging purposes - **/ - public function __toString(){ - $str="ID:{$this->id['db_name']}(ID:{$this->id['name']})\n"; - $str.="Relation ID:{$this->relation_id['db_name']}({$this->relation_id['name']})\n"; - $str.="Data:"; - for ($i=0; $i<sizeof($this->text); $i++) - $str.="{$this->text[$i]['db_name']}({$this->text[$i]['name']}),"; - - $str.="\nExtra:"; - for ($i=0; $i<sizeof($this->data); $i++) - $str.="{$this->data[$i]['db_name']}({$this->data[$i]['name']}),"; - - return $str; - } - - /*! removes un-used fields from configuration - @param name - name of field , which need to be preserved - */ - public function minimize($name){ - for ($i=0; $i < sizeof($this->text); $i++){ - if ($this->text[$i]["db_name"]==$name || $this->text[$i]["name"]==$name){ - $this->text[$i]["name"]="value"; - $this->data=array($this->text[$i]); - $this->text=array($this->text[$i]); - return; - } - } - throw new Exception("Incorrect dataset minimization, master field not found."); - } - - public function limit_fields($data){ - if (isset($this->full_field_list)) - $this->restore_fields(); - $this->full_field_list = $this->text; - $this->text = array(); - - for ($i=0; $i < sizeof($this->full_field_list); $i++) { - if (array_key_exists($this->full_field_list[$i]["name"],$data)) - $this->text[] = $this->full_field_list[$i]; - } - } - - public function restore_fields(){ - if (isset($this->full_field_list)) - $this->text = $this->full_field_list; - } - - /*! initialize inner state by parsing configuration parameters - - @param id - name of id field - @param fields - name of data field(s) - @param extra - name of extra field(s) - @param relation - name of relation field - - */ - public function init($id,$fields,$extra,$relation){ - $this->id = $this->parse($id,false); - $this->text = $this->parse($fields,true); - $this->data = array_merge($this->text,$this->parse($extra,true)); - $this->relation_id = $this->parse($relation,false); - } - - /*! parse configuration string - - @param key - key string from configuration - @param mode - multi names flag - @return - parsed field name object - */ - private function parse($key,$mode){ - if ($mode){ - if (!$key) return array(); - $key=explode(",",$key); - for ($i=0; $i < sizeof($key); $i++) - $key[$i]=$this->parse($key[$i],false); - return $key; - } - $key=explode("(",$key); - $data=array("db_name"=>trim($key[0]), "name"=>trim($key[0])); - if (sizeof($key)>1) - $data["name"]=substr(trim($key[1]),0,-1); - return $data; - } - - /*! constructor - init public collectons - @param proto - DataConfig object used as prototype for new one, optional - */ - public function __construct($proto=false){ - if ($proto!==false) - $this->copy($proto); - else { - $this->text=array(); - $this->data=array(); - $this->id=array("name"=>"dhx_auto_id", "db_name"=>"dhx_auto_id"); - $this->relation_id=array("name"=>"", "db_name"=>""); - } - } - - /*! copy properties from source object - - @param proto - source object - */ - public function copy($proto){ - $this->id = $proto->id; - $this->relation_id = $proto->relation_id; - $this->text = $proto->text; - $this->data = $proto->data; - } - - /*! returns list of data fields (db_names) - @return - list of data fields ( ready to be used in SQL query ) - */ - public function db_names_list($db){ - $out=array(); - if ($this->id["db_name"]) - array_push($out,$db->escape_name($this->id["db_name"])); - if ($this->relation_id["db_name"]) - array_push($out,$db->escape_name($this->relation_id["db_name"])); - - for ($i=0; $i < sizeof($this->data); $i++){ - if ($this->data[$i]["db_name"]!=$this->data[$i]["name"]) - $out[]=$db->escape_name($this->data[$i]["db_name"])." as ".$this->data[$i]["name"]; - else - $out[]=$db->escape_name($this->data[$i]["db_name"]); - } - - return $out; - } - - /*! add field to dataset config ($text collection) - - added field will be used in all auto-generated queries - @param name - name of field - @param aliase - aliase of field, optional - */ - public function add_field($name,$aliase=false){ - if ($aliase===false) $aliase=$name; - - //adding to list of data-active fields - if ($this->id["db_name"]==$name || $this->relation_id["db_name"] == $name){ - LogMaster::log("Field name already used as ID, be sure that it is really necessary."); - } - if ($this->is_field($name,$this->text)!=-1) - throw new Exception('Data field already registered: '.$name); - array_push($this->text,array("db_name"=>$name,"name"=>$aliase)); - - //adding to list of all fields as well - if ($this->is_field($name,$this->data)==-1) - array_push($this->data,array("db_name"=>$name,"name"=>$aliase)); - - } - - /*! remove field from dataset config ($text collection) - - removed field will be excluded from all auto-generated queries - @param name - name of field, or aliase of field - */ - public function remove_field($name){ - $ind = $this->is_field($name); - if ($ind==-1) throw new Exception('There was no such data field registered as: '.$name); - array_splice($this->text,$ind,1); - //we not deleting field from $data collection, so it will not be included in data operation, but its data still available - } - - /*! remove field from dataset config ($text and $data collections) - - removed field will be excluded from all auto-generated queries - @param name - name of field, or aliase of field - */ - public function remove_field_full($name){ - $ind = $this->is_field($name); - if ($ind==-1) throw new Exception('There was no such data field registered as: '.$name); - array_splice($this->text,$ind,1); - - $ind = $this->is_field($name, $this->data); - if ($ind==-1) throw new Exception('There was no such data field registered as: '.$name); - array_splice($this->data,$ind,1); - } - - /*! check if field is a part of dataset - - @param name - name of field - @param collection - collection, against which check will be done, $text collection by default - @return - returns true if field already a part of dataset, otherwise returns true - */ - public function is_field($name,$collection = false){ - if (!$collection) - $collection=$this->text; - - for ($i=0; $i<sizeof($collection); $i++) - if ($collection[$i]["name"] == $name || $collection[$i]["db_name"] == $name) return $i; - return -1; - } - - -} - -/*! Base abstraction class, used for data operations - Class abstract access to data, it is a base class to all DB wrappers -**/ -abstract class DataWrapper{ - protected $connection; - protected $config;//!< DataConfig instance - /*! constructor - @param connection - DB connection - @param config - DataConfig instance - */ - public function __construct($connection = false,$config = false){ - $this->config=$config; - $this->connection=$connection; - } - - /*! insert record in storage - - @param data - DataAction object - @param source - DataRequestConfig object - */ - abstract function insert($data,$source); - - /*! delete record from storage - - @param data - DataAction object - @param source - DataRequestConfig object - */ - abstract function delete($data,$source); - - /*! update record in storage - - @param data - DataAction object - @param source - DataRequestConfig object - */ - abstract function update($data,$source); - - /*! select record from storage - - @param source - DataRequestConfig object - */ - abstract function select($source); - - /*! get size of storage - - @param source - DataRequestConfig object - */ - abstract function get_size($source); - - /*! get all variations of field in storage - - @param name - name of field - @param source - DataRequestConfig object - */ - abstract function get_variants($name,$source); - - /*! checks if there is a custom sql string for specified db operation - - @param name - name of DB operation - @param data - hash of data - @return - sql string - */ - public function get_sql($name,$data){ - return ""; //custom sql not supported by default - } - - /*! begins DB transaction - */ - public function begin_transaction(){ - throw new Exception("Data wrapper not supports transactions."); - } - /*! commits DB transaction - */ - public function commit_transaction(){ - throw new Exception("Data wrapper not supports transactions."); - } - /*! rollbacks DB transaction - */ - public function rollback_transaction(){ - throw new Exception("Data wrapper not supports transactions."); - } -} - -/*! Common database abstraction class - Class provides base set of methods to access and change data in DB, class used as a base for DB-specific wrappers -**/ -abstract class DBDataWrapper extends DataWrapper{ - private $transaction = false; //!< type of transaction - private $sequence=false;//!< sequence name - private $sqls = array();//!< predefined sql actions - - - /*! assign named sql query - @param name - name of sql query - @param data - sql query text - */ - public function attach($name,$data){ - $name=strtolower($name); - $this->sqls[$name]=$data; - } - /*! replace vars in sql string with actual values - - @param matches - array of field name matches - @return - value for the var name - */ - public function get_sql_callback($matches){ - return $this->escape($this->temp->get_value($matches[1])); - } - public function get_sql($name,$data){ - $name=strtolower($name); - if (!array_key_exists($name,$this->sqls)) return ""; - - - $str = $this->sqls[$name]; - $this->temp = $data; //dirty - $str = preg_replace_callback('|\{([^}]+)\}|',array($this,"get_sql_callback"),$str); - unset ($this->temp); //dirty - return $str; - } - - public function new_record_order($action, $source){ - $order = $source->get_order(); - if ($order){ - $table = $source->get_source(); - $id = $this->config->id["db_name"]; - $idvalue = $action->get_new_id(); - - $max = $this->queryOne("SELECT MAX($order) as dhx_maxvalue FROM $table"); - $dhx_maxvalue = $max["dhx_maxvalue"] + 1; - - $this->query("UPDATE $table SET $order = $dhx_maxvalue WHERE $id = $idvalue"); - } - } - - public function order($data, $source){ - //id of moved item - $id1 = $this->escape($data->get_value("id")); - //id of target item - $target = $data->get_value("target"); - if (strpos($target, "next:") !== false){ - $dropnext = true; - $id2 = str_replace("next:", "", $target); - } else { - $id2 = $target; - } - $id2 = $this->escape($id2); - - - //for tree like components we need to limit out queries to the affected branch only - $relation_select = $relation_update = $relation_sql_out = $relation_sql = ""; - if ($this->config->relation_id["name"]){ - $relation = $data->get_value($this->config->relation_id["name"]); - if ($relation !== false && $relation !== ""){ - $relation_sql = " ".$this->config->relation_id["db_name"]." = '".$this->escape($relation)."' AND "; - $relation_select = $this->config->relation_id["db_name"]." as dhx_parent, "; - $relation_update = " ".$this->config->relation_id["db_name"]." = '".$this->escape($relation)."', "; - } - } - - - $name = $source->get_order(); - $table = $source->get_source(); - $idkey = $this->config->id["db_name"]; - - $source = $this->queryOne("select $relation_select $name as dhx_index from $table where $idkey = '$id1'"); - $source_index = $source["dhx_index"] ? $source["dhx_index"] : 0; - if ($relation_sql) - $relation_sql_out = " ".$this->config->relation_id["db_name"]." = '".$this->escape($source["dhx_parent"])."' AND "; - - $this->query("update $table set $name = $name - 1 where $relation_sql_out $name >= $source_index"); - - if ($id2 !== ""){ - $target = $this->queryOne("select $name as dhx_index from $table where $idkey = '$id2'"); - $target_index = $target["dhx_index"]; - if (!$target_index) - $target_index = 0; - if ($dropnext) - $target_index += 1; - $this->query("update $table set $name = $name + 1 where $relation_sql $name >= $target_index"); - } else { - $target = $this->queryOne("select max($name) as dhx_index from $table"); - $target_index = ($target["dhx_index"] ? $target["dhx_index"] : 0)+1; - } - - $this->query("update $table set $relation_update $name = $target_index where $idkey = '$id1'"); - } - - public function insert($data,$source){ - $sql=$this->insert_query($data,$source); - $this->query($sql); - $data->success($this->get_new_id()); - } - public function delete($data,$source){ - $sql=$this->delete_query($data,$source); - $this->query($sql); - $data->success(); - } - public function update($data,$source){ - $sql=$this->update_query($data,$source); - $this->query($sql); - $data->success(); - } - public function select($source){ - $select=$source->get_fieldset(); - if (!$select){ - $select=$this->config->db_names_list($this); - $select = implode(",",$select); - } - - $where=$this->build_where($source->get_filters(),$source->get_relation()); - $sort=$this->build_order($source->get_sort_by()); - - return $this->query($this->select_query($select,$source->get_source(),$where,$sort,$source->get_start(),$source->get_count())); - } - public function queryOne($sql){ - $res = $this->query($sql); - if ($res) - return $this->get_next($res); - return false; - } - public function get_size($source){ - $count = new DataRequestConfig($source); - - $count->set_fieldset("COUNT(*) as DHX_COUNT "); - $count->set_sort(null); - $count->set_limit(0,0); - - $res=$this->select($count); - $data=$this->get_next($res); - if (array_key_exists("DHX_COUNT",$data)) return $data["DHX_COUNT"]; - else return $data["dhx_count"]; //postgresql - } - public function get_variants($name,$source){ - $count = new DataRequestConfig($source); - $count->set_fieldset("DISTINCT ".$this->escape_name($name)." as value"); - $sort = new SortInterface($source); - $count->set_sort(null); - for ($i = 0; $i < count($sort->rules); $i++) { - if ($sort->rules[$i]['name'] == $name) - $count->set_sort($sort->rules[$i]['name'], $sort->rules[$i]['direction']); - } - $count->set_limit(0,0); - return $this->select($count); - } - - public function sequence($sec){ - $this->sequence=$sec; - } - - - /*! create an sql string for filtering rules - - @param rules - set of filtering rules - @param relation - name of relation id field - @return - sql string with filtering rules - */ - protected function build_where($rules,$relation=false){ - $sql=array(); - for ($i=0; $i < sizeof($rules); $i++) - if (is_string($rules[$i])) - array_push($sql,"(".$rules[$i].")"); - else { - $filtervalue = $rules[$i]["value"]; - $filteroperation = $rules[$i]["operation"]; - if ($filtervalue!=""){ - if (!$filteroperation) - array_push($sql,$this->escape_name($rules[$i]["name"])." LIKE '%".$this->escape($filtervalue)."%'"); - else { - if ($filteroperation != "IN") - $filtervalue = "'".$this->escape($filtervalue)."'"; - - array_push($sql,$this->escape_name($rules[$i]["name"])." ".$filteroperation." ".$filtervalue); - } - } - } - - if ($relation !== false && $relation !== ""){ - $relsql = $this->escape_name($this->config->relation_id["db_name"])." = '".$this->escape($relation)."'"; - if ($relation == "0") - $relsql = "( ".$relsql." OR ".$this->escape_name($this->config->relation_id["db_name"])." IS NULL )"; - - array_push($sql,$relsql); - } - return implode(" AND ",$sql); - } - /*! convert sorting rules to sql string - - @param by - set of sorting rules - @return - sql string for set of sorting rules - */ - protected function build_order($by){ - if (!sizeof($by)) return ""; - $out = array(); - for ($i=0; $i < sizeof($by); $i++) - if (is_string($by[$i])) - $out[] = $by[$i]; - else if ($by[$i]["name"]) - $out[]=$this->escape_name($by[$i]["name"])." ".$by[$i]["direction"]; - return implode(",",$out); - } - - /*! generates sql code for select operation - - @param select - list of fields in select - @param from - table name - @param where - list of filtering rules - @param sort - list of sorting rules - @param start - start index of fetching - @param count - count of records to fetch - @return - sql string for select operation - */ - protected function select_query($select,$from,$where,$sort,$start,$count){ - if (!$from) - return $select; - - $sql="SELECT ".$select." FROM ".$from; - if ($where) $sql.=" WHERE ".$where; - if ($sort) $sql.=" ORDER BY ".$sort; - if ($start || $count) $sql.=" LIMIT ".$start.",".$count; - return $sql; - } - /*! generates update sql - - @param data - DataAction object - @param request - DataRequestConfig object - @return - sql string, which updates record with provided data - */ - protected function update_query($data,$request){ - $sql="UPDATE ".$request->get_source()." SET "; - $temp=array(); - for ($i=0; $i < sizeof($this->config->text); $i++) { - $step=$this->config->text[$i]; - - if ($data->get_value($step["name"])===Null) - $step_value ="Null"; - else - $step_value = "'".$this->escape($data->get_value($step["name"]))."'"; - $temp[$i]= $this->escape_name($step["db_name"])."=". $step_value; - } - if ($relation = $this->config->relation_id["db_name"]){ - $temp[]= $this->escape_name($relation)."='".$this->escape($data->get_value($relation))."'"; - } - $sql.=implode(",",$temp)." WHERE ".$this->escape_name($this->config->id["db_name"])."='".$this->escape($data->get_id())."'"; - - //if we have limited set - set constraints - $where=$this->build_where($request->get_filters()); - if ($where) $sql.=" AND (".$where.")"; - - return $sql; - } - - /*! generates delete sql - - @param data - DataAction object - @param request - DataRequestConfig object - @return - sql string, which delete record - */ - protected function delete_query($data,$request){ - $sql="DELETE FROM ".$request->get_source(); - $sql.=" WHERE ".$this->escape_name($this->config->id["db_name"])."='".$this->escape($data->get_id())."'"; - - //if we have limited set - set constraints - $where=$this->build_where($request->get_filters()); - if ($where) $sql.=" AND (".$where.")"; - - return $sql; - } - - /*! generates insert sql - - @param data - DataAction object - @param request - DataRequestConfig object - @return - sql string, which inserts new record with provided data - */ - protected function insert_query($data,$request){ - $temp_n=array(); - $temp_v=array(); - foreach($this->config->text as $k => $v){ - $temp_n[$k]=$this->escape_name($v["db_name"]); - if ($data->get_value($v["name"])===Null) - $temp_v[$k]="Null"; - else - $temp_v[$k]="'".$this->escape($data->get_value($v["name"]))."'"; - } - if ($relation = $this->config->relation_id["db_name"]){ - $temp_n[]=$this->escape_name($relation); - $temp_v[]="'".$this->escape($data->get_value($relation))."'"; - } - if ($this->sequence){ - $temp_n[]=$this->escape_name($this->config->id["db_name"]); - $temp_v[]=$this->sequence; - } - - $sql="INSERT INTO ".$request->get_source()."(".implode(",",$temp_n).") VALUES (".implode(",",$temp_v).")"; - - return $sql; - } - - /*! sets the transaction mode, used by dataprocessor - - @param mode - mode name - */ - public function set_transaction_mode($mode){ - if ($mode!="none" && $mode!="global" && $mode!="record") - throw new Exception("Unknown transaction mode"); - $this->transaction=$mode; - } - /*! returns true if global transaction mode was specified - @return - true if global transaction mode was specified - */ - public function is_global_transaction(){ - return $this->transaction == "global"; - } - /*! returns true if record transaction mode was specified - @return - true if record transaction mode was specified - */ - public function is_record_transaction(){ - return $this->transaction == "record"; - } - - - public function begin_transaction(){ - $this->query("BEGIN"); - } - public function commit_transaction(){ - $this->query("COMMIT"); - } - public function rollback_transaction(){ - $this->query("ROLLBACK"); - } - - /*! exec sql string - - @param sql - sql string - @return - sql result set - */ - abstract public function query($sql); - /*! returns next record from result set - - @param res - sql result set - @return - hash of data - */ - abstract public function get_next($res); - /*! returns new id value, for newly inserted row - @return - new id value, for newly inserted row - */ - abstract public function get_new_id(); - /*! escape data to prevent sql injections - @param data - unescaped data - @return - escaped data - */ - abstract public function escape($data); - - /*! escape field name to prevent sql reserved words conflict - @param data - unescaped data - @return - escaped data - */ - public function escape_name($data){ - return $data; - } - - /*! get list of tables in the database - - @return - array of table names - */ - public function tables_list() { - throw new Exception("Not implemented"); - } - - /*! returns list of fields for the table in question - - @param table - name of table in question - @return - array of field names - */ - public function fields_list($table) { - throw new Exception("Not implemented"); - } - -} - -class ArrayDBDataWrapper extends DBDataWrapper{ - public function get_next($res){ - if ($res->index < sizeof($res->data)) - return $res->data[$res->index++]; - } - public function select($sql){ - if ($this->config->relation_id["db_name"] == "") { - if ($sql->get_relation() == "0" || $sql->get_relation() == "") { - return new ArrayQueryWrapper($this->connection); - } else { - return new ArrayQueryWrapper(array()); - } - } - - $relation_id = $this->config->relation_id["db_name"]; - $result = array(); - - for ($i = 0; $i < count($this->connection); $i++) { - $item = $this->connection[$i]; - if (!isset($item[$relation_id])) continue; - if ($item[$relation_id] == $sql->get_relation()) - $result[] = $item; - - } - - return new ArrayQueryWrapper($result); - } - public function query($sql){ - throw new Exception("Not implemented"); - } - public function escape($value){ - throw new Exception("Not implemented"); - } - public function get_new_id(){ - throw new Exception("Not implemented"); - } -} - -class ArrayQueryWrapper{ - public function __construct($data){ - $this->data = $data; - $this->index = 0; - } -} -/*! Implementation of DataWrapper for MySQL -**/ -class MySQLDBDataWrapper extends DBDataWrapper{ - protected $last_result; - public function query($sql){ - LogMaster::log($sql); - $res=mysql_query($sql,$this->connection); - if ($res===false) throw new Exception("MySQL operation failed\n".mysql_error($this->connection)); - $this->last_result = $res; - return $res; - } - - public function get_next($res){ - if (!$res) - $res = $this->last_result; - - return mysql_fetch_assoc($res); - } - - public function get_new_id(){ - return mysql_insert_id($this->connection); - } - - public function escape($data){ - return mysql_real_escape_string($data, $this->connection); - } - - public function tables_list() { - $result = mysql_query("SHOW TABLES"); - if ($result===false) throw new Exception("MySQL operation failed\n".mysql_error($this->connection)); - - $tables = array(); - while ($table = mysql_fetch_array($result)) { - $tables[] = $table[0]; - } - return $tables; - } - - public function fields_list($table) { - $result = mysql_query("SHOW COLUMNS FROM `".$table."`"); - if ($result===false) throw new Exception("MySQL operation failed\n".mysql_error($this->connection)); - - $fields = array(); - $id = ""; - while ($field = mysql_fetch_assoc($result)) { - if ($field['Key'] == "PRI") - $id = $field["Field"]; - else - $fields[] = $field["Field"]; - } - return array("fields" => $fields, "key" => $id ); - } - - /*! escape field name to prevent sql reserved words conflict - @param data - unescaped data - @return - escaped data - */ - public function escape_name($data){ - if ((strpos($data,"`")!==false || is_int($data)) || (strpos($data,".")!==false)) - return $data; - return '`'.$data.'`'; - } -} -?>
\ No newline at end of file diff --git a/codebase/db_excel.php b/codebase/db_excel.php deleted file mode 100644 index 6c0e347..0000000 --- a/codebase/db_excel.php +++ /dev/null @@ -1,190 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once('db_common.php'); - -if (!defined('DHX_IGNORE_EMPTY_ROWS')) { - define('DHX_IGNORE_EMPTY_ROWS', true); -} - -class ExcelDBDataWrapper extends DBDataWrapper { - - public $emptyLimit = 10; - public function excel_data($points){ - $path = $this->connection; - $excel = PHPExcel_IOFactory::createReaderForFile($path); - $excel = $excel->load($path); - $result = array(); - $excelWS = $excel->getActiveSheet(); - - for ($i=0; $i < sizeof($points); $i++) { - $c = array(); - preg_match("/^([a-zA-Z]+)(\d+)/", $points[$i], $c); - if (count($c) > 0) { - $col = PHPExcel_Cell::columnIndexFromString($c[1]) - 1; - $cell = $excelWS->getCellByColumnAndRow($col, (int)$c[2]); - $result[] = $cell->getValue(); - } - } - - return $result; - } - public function select($source) { - $path = $this->connection; - $excel = PHPExcel_IOFactory::createReaderForFile($path); - $excel->setReadDataOnly(false); - $excel = $excel->load($path); - $excRes = new ExcelResult(); - $excelWS = $excel->getActiveSheet(); - $addFields = true; - - $coords = array(); - if ($source->get_source() == '*') { - $coords['start_row'] = 0; - $coords['end_row'] = false; - } else { - $c = array(); - preg_match("/^([a-zA-Z]+)(\d+)/", $source->get_source(), $c); - if (count($c) > 0) { - $coords['start_row'] = (int) $c[2]; - } else { - $coords['start_row'] = 0; - } - $c = array(); - preg_match("/:(.+)(\d+)$/U", $source->get_source(), $c); - if (count($c) > 0) { - $coords['end_row'] = (int) $c[2]; - } else { - $coords['end_row'] = false; - } - } - - $i = $coords['start_row']; - $end = 0; - while ((($coords['end_row'] == false)&&($end < $this->emptyLimit))||(($coords['end_row'] !== false)&&($i < $coords['end_row']))) { - $r = Array(); - $emptyNum = 0; - for ($j = 0; $j < count($this->config->text); $j++) { - $col = PHPExcel_Cell::columnIndexFromString($this->config->text[$j]['name']) - 1; - $cell = $excelWS->getCellByColumnAndRow($col, $i); - if (PHPExcel_Shared_Date::isDateTime($cell)) { - $r[PHPExcel_Cell::stringFromColumnIndex($col)] = PHPExcel_Shared_Date::ExcelToPHP($cell->getValue()); - } else if ($cell->getDataType() == 'f') { - $r[PHPExcel_Cell::stringFromColumnIndex($col)] = $cell->getCalculatedValue(); - } else { - $r[PHPExcel_Cell::stringFromColumnIndex($col)] = $cell->getValue(); - } - if ($r[PHPExcel_Cell::stringFromColumnIndex($col)] == '') { - $emptyNum++; - } - } - if ($emptyNum < count($this->config->text)) { - $r['id'] = $i; - $excRes->addRecord($r); - $end = 0; - } else { - if (DHX_IGNORE_EMPTY_ROWS == false) { - $r['id'] = $i; - $excRes->addRecord($r); - } - $end++; - } - $i++; - } - return $excRes; - } - - public function query($sql) { - } - - public function get_new_id() { - } - - public function escape($data) { - } - - public function get_next($res) { - return $res->next(); - } - -} - - -class ExcelResult { - private $rows; - private $currentRecord = 0; - - - // add record to output list - public function addRecord($file) { - $this->rows[] = $file; - } - - - // return next record - public function next() { - if ($this->currentRecord < count($this->rows)) { - $row = $this->rows[$this->currentRecord]; - $this->currentRecord++; - return $row; - } else { - return false; - } - } - - - // sorts records under $sort array - public function sort($sort, $data) { - if (count($this->files) == 0) { - return $this; - } - // defines fields list if it's need - for ($i = 0; $i < count($sort); $i++) { - $fieldname = $sort[$i]['name']; - if (!isset($this->files[0][$fieldname])) { - if (isset($data[$fieldname])) { - $fieldname = $data[$fieldname]['db_name']; - $sort[$i]['name'] = $fieldname; - } else { - $fieldname = false; - } - } - } - - // for every sorting field will sort - for ($i = 0; $i < count($sort); $i++) { - // if field, setted in sort parameter doesn't exist, continue - if ($sort[$i]['name'] == false) { - continue; - } - // sorting by current field - $flag = true; - while ($flag == true) { - $flag = false; - // checks if previous sorting fields are equal - for ($j = 0; $j < count($this->files) - 1; $j++) { - $equal = true; - for ($k = 0; $k < $i; $k++) { - if ($this->files[$j][$sort[$k]['name']] != $this->files[$j + 1][$sort[$k]['name']]) { - $equal = false; - } - } - // compares two records in list under current sorting field and sorting direction - if (((($this->files[$j][$sort[$i]['name']] > $this->files[$j + 1][$sort[$i]['name']])&&($sort[$i]['direction'] == 'ASC'))||(($this->files[$j][$sort[$i]['name']] < $this->files[$j + 1][$sort[$i]['name']])&&($sort[$i]['direction'] == 'DESC')))&&($equal == true)) { - $c = $this->files[$j]; - $this->files[$j] = $this->files[$j+1]; - $this->files[$j+1] = $c; - $flag = true; - } - } - } - } - return $this; - } - -} - - -?>
\ No newline at end of file diff --git a/codebase/db_filesystem.php b/codebase/db_filesystem.php deleted file mode 100644 index b3d16d2..0000000 --- a/codebase/db_filesystem.php +++ /dev/null @@ -1,345 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once('db_common.php'); -require_once('tree_connector.php'); - -/* -Most execution time is a standart functions for workin with FileSystem: is_dir(), dir(), readdir(), stat() -*/ - -class FileSystemDBDataWrapper extends DBDataWrapper { - - - // returns list of files and directories - public function select($source) { - $relation = $this->getFileName($source->get_relation()); - // for tree checks relation id and forms absolute path - if ($relation == '0') { - $relation = ''; - } else { - $path = $source->get_source(); - } - $path = $source->get_source(); - $path = $this->getFileName($path); - $path = realpath($path); - if ($path == false) { - return new FileSystemResult(); - } - - if (strpos(realpath($path.'/'.$relation), $path) !== 0) { - return new FileSystemResult(); - } - // gets files and directories list - $res = $this->getFilesList($path, $relation); - // sorts list - $res = $res->sort($source->get_sort_by(), $this->config->data); - return $res; - } - - - // gets files and directory list - private function getFilesList($path, $relation) { - $fileSystemTypes = FileSystemTypes::getInstance(); - LogMaster::log("Query filesystem: ".$path); - $dir = opendir($path.'/'.$relation); - $result = new FileSystemResult(); - // forms fields list - for ($i = 0; $i < count($this->config->data); $i++) { - $fields[] = $this->config->data[$i]['db_name']; - } - // for every file and directory of folder - while ($file = readdir($dir)) { - // . and .. should not be in output list - if (($file == '.')||($file == '..')) { - continue; - } - $newFile = array(); - // parse file name as Array('name', 'ext', 'is_dir') - $fileNameExt = $this->parseFileName($path.'/'.$relation, $file); - // checks if file should be in output array - if (!$fileSystemTypes->checkFile($file, $fileNameExt)) { - continue; - } - // takes file stat if it's need - if ((in_array('size', $fields))||(in_array('date', $fields))) { - $fileInfo = stat($path.'/'.$file); - } - - // for every field forms list of fields - for ($i = 0; $i < count($fields); $i++) { - $field = $fields[$i]; - switch ($field) { - case 'filename': - $newFile['filename'] = $file; - break; - case 'full_filename': - $newFile['full_filename'] = $path."/".$file; - break; - case 'size': - $newFile['size'] = $fileInfo['size']; - break; - case 'extention': - $newFile['extention'] = $fileNameExt['ext']; - break; - case 'name': - $newFile['name'] = $fileNameExt['name']; - break; - case 'date': - $newFile['date'] = date("Y-m-d H:i:s", $fileInfo['ctime']); - break; - } - $newFile['relation_id'] = $relation.'/'.$file; - $newFile['safe_name'] = $this->setFileName($relation.'/'.$file); - $newFile['is_folder'] = $fileNameExt['is_dir']; - } - // add file in output list - $result->addFile($newFile); - } - return $result; - } - - - // replaces '.' and '_' in id - private function setFileName($filename) { - $filename = str_replace(".", "{-dot-}", $filename); - $filename = str_replace("_", "{-nizh-}", $filename); - return $filename; - } - - - // replaces '{-dot-}' and '{-nizh-}' in id - private function getFileName($filename) { - $filename = str_replace("{-dot-}", ".", $filename); - $filename = str_replace("{-nizh-}", "_", $filename); - return $filename; - } - - - // parses file name and checks if is directory - private function parseFileName($path, $file) { - $result = Array(); - if (is_dir($path.'/'.$file)) { - $result['name'] = $file; - $result['ext'] = 'dir'; - $result['is_dir'] = 1; - } else { - $pos = strrpos($file, '.'); - $result['name'] = substr($file, 0, $pos); - $result['ext'] = substr($file, $pos + 1); - $result['is_dir'] = 0; - } - return $result; - } - - public function query($sql) { - } - - public function get_new_id() { - } - - public function escape($data) { - } - - public function get_next($res) { - return $res->next(); - } - -} - - -class FileSystemResult { - private $files; - private $currentRecord = 0; - - - // add record to output list - public function addFile($file) { - $this->files[] = $file; - } - - - // return next record - public function next() { - if ($this->currentRecord < count($this->files)) { - $file = $this->files[$this->currentRecord]; - $this->currentRecord++; - return $file; - } else { - return false; - } - } - - - // sorts records under $sort array - public function sort($sort, $data) { - if (count($this->files) == 0) { - return $this; - } - // defines fields list if it's need - for ($i = 0; $i < count($sort); $i++) { - $fieldname = $sort[$i]['name']; - if (!isset($this->files[0][$fieldname])) { - if (isset($data[$fieldname])) { - $fieldname = $data[$fieldname]['db_name']; - $sort[$i]['name'] = $fieldname; - } else { - $fieldname = false; - } - } - } - - // for every sorting field will sort - for ($i = 0; $i < count($sort); $i++) { - // if field, setted in sort parameter doesn't exist, continue - if ($sort[$i]['name'] == false) { - continue; - } - // sorting by current field - $flag = true; - while ($flag == true) { - $flag = false; - // checks if previous sorting fields are equal - for ($j = 0; $j < count($this->files) - 1; $j++) { - $equal = true; - for ($k = 0; $k < $i; $k++) { - if ($this->files[$j][$sort[$k]['name']] != $this->files[$j + 1][$sort[$k]['name']]) { - $equal = false; - } - } - // compares two records in list under current sorting field and sorting direction - if (((($this->files[$j][$sort[$i]['name']] > $this->files[$j + 1][$sort[$i]['name']])&&($sort[$i]['direction'] == 'ASC'))||(($this->files[$j][$sort[$i]['name']] < $this->files[$j + 1][$sort[$i]['name']])&&($sort[$i]['direction'] == 'DESC')))&&($equal == true)) { - $c = $this->files[$j]; - $this->files[$j] = $this->files[$j+1]; - $this->files[$j+1] = $c; - $flag = true; - } - } - } - } - return $this; - } - -} - - -// singleton class for setting file types filter -class FileSystemTypes { - - static private $instance = NULL; - private $extentions = Array(); - private $extentions_not = Array(); - private $all = true; - private $patterns = Array(); - // predefined types - private $types = Array( - 'image' => Array('jpg', 'jpeg', 'gif', 'png', 'tiff', 'bmp', 'psd', 'dir'), - 'document' => Array('txt', 'doc', 'docx', 'xls', 'xlsx', 'rtf', 'dir'), - 'web' => Array('php', 'html', 'htm', 'js', 'css', 'dir'), - 'audio' => Array('mp3', 'wav', 'ogg', 'dir'), - 'video' => Array('avi', 'mpg', 'mpeg', 'mp4', 'dir'), - 'only_dir' => Array('dir') - ); - - - static function getInstance() { - if (self::$instance == NULL) { - self::$instance = new FileSystemTypes(); - } - return self::$instance; - } - - // sets array of extentions - public function setExtentions($ext) { - $this->all = false; - $this->extentions = $ext; - } - - // adds one extention in array - public function addExtention($ext) { - $this->all = false; - $this->extentions[] = $ext; - } - - - // adds one extention which will not ouputed in array - public function addExtentionNot($ext) { - $this->extentions_not[] = $ext; - } - - - // returns array of extentions - public function getExtentions() { - return $this->extentions; - } - - // adds regexp pattern - public function addPattern($pattern) { - $this->all = false; - $this->patterns[] = $pattern; - } - - // clear extentions array - public function clearExtentions() { - $this->all = true; - $this->extentions = Array(); - } - - // clear regexp patterns array - public function clearPatterns() { - $this->all = true; - $this->patterns = Array(); - } - - // clear all filters - public function clearAll() { - $this->clearExtentions(); - $this->clearPatterns(); - } - - // sets predefined type - public function setType($type, $clear = false) { - $this->all = false; - if ($type == 'all') { - $this->all = true; - return true; - } - if (isset($this->types[$type])) { - if ($clear) { - $this->clearExtentions(); - } - for ($i = 0; $i < count($this->types[$type]); $i++) { - $this->extentions[] = $this->types[$type][$i]; - } - return true; - } else { - return false; - } - } - - - // check file under setted filter - public function checkFile($filename, $fileNameExt) { - if (in_array($fileNameExt['ext'], $this->extentions_not)) { - return false; - } - if ($this->all) { - return true; - } - - if ((count($this->extentions) > 0)&&(!in_array($fileNameExt['ext'], $this->extentions))) { - return false; - } - - for ($i = 0; $i < count($this->patterns); $i++) { - if (!preg_match($this->patterns[$i], $filename)) { - return false; - } - } - return true; - } -} - -?>
\ No newline at end of file diff --git a/codebase/db_mssql.php b/codebase/db_mssql.php deleted file mode 100644 index 0acab93..0000000 --- a/codebase/db_mssql.php +++ /dev/null @@ -1,73 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("db_common.php"); -/*! MSSQL implementation of DataWrapper -**/ -class MsSQLDBDataWrapper extends DBDataWrapper{ - private $last_id=""; //!< ID of previously inserted record - private $insert_operation=false; //!< flag of insert operation - private $start_from=false; //!< index of start position - - public function query($sql){ - LogMaster::log($sql); - $res = mssql_query($sql,$this->connection); - if ($this->insert_operation){ - $last = mssql_fetch_assoc($res); - $this->last_id = $last["dhx_id"]; - mssql_free_result($res); - } - if ($this->start_from) - mssql_data_seek($res,$this->start_from); - return $res; - } - - public function get_next($res){ - return mssql_fetch_assoc($res); - } - - public function get_new_id(){ - /* - MSSQL doesn't support identity or auto-increment fields - Insert SQL returns new ID value, which stored in last_id field - */ - return $this->last_id; - } - - protected function insert_query($data,$request){ - $sql = parent::insert_query($data,$request); - $this->insert_operation=true; - return $sql.";SELECT @@IDENTITY AS dhx_id"; - } - - protected function select_query($select,$from,$where,$sort,$start,$count){ - if (!$from) - return $select; - - $sql="SELECT " ; - if ($count) - $sql.=" TOP ".($count+$start); - $sql.=" ".$select." FROM ".$from; - if ($where) $sql.=" WHERE ".$where; - if ($sort) $sql.=" ORDER BY ".$sort; - if ($start && $count) - $this->start_from=$start; - else - $this->start_from=false; - return $sql; - } - - public function escape($data){ - /* - there is no special escaping method for mssql - use common logic - */ - return str_replace("'","''",$data); - } - - public function begin_transaction(){ - $this->query("BEGIN TRAN"); - } -} -?>
\ No newline at end of file diff --git a/codebase/db_mysqli.php b/codebase/db_mysqli.php deleted file mode 100644 index 6740a3b..0000000 --- a/codebase/db_mysqli.php +++ /dev/null @@ -1,56 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("db_common.php"); - -class MySQLiDBDataWrapper extends MySQLDBDataWrapper{ - - public function query($sql){ - LogMaster::log($sql); - $res = $this->connection->query($sql); - if ($res===false) throw new Exception("MySQL operation failed\n".$this->connection->error); - return $res; - } - - public function get_next($res){ - return $res->fetch_assoc(); - } - - public function get_new_id(){ - return $this->connection->insert_id; - } - - public function escape($data){ - return $this->connection->real_escape_string($data); - } - - public function tables_list() { - $result = $this->connection->query("SHOW TABLES"); - if ($result===false) throw new Exception("MySQL operation failed\n".$this->connection->error); - - $tables = array(); - while ($table = $result->fetch_array()) { - $tables[] = $table[0]; - } - return $tables; - } - - public function fields_list($table) { - $result = $this->connection->query("SHOW COLUMNS FROM `".$table."`"); - if ($result===false) throw new Exception("MySQL operation failed\n".$this->connection->error); - $fields = array(); - while ($field = $result->fetch_array()) { - if ($field['Key'] == "PRI") { - $fields[$field[0]] = 1; - } else { - $fields[$field[0]] = 0; - } - } - return $fields; - } - -} - -?>
\ No newline at end of file diff --git a/codebase/db_oracle.php b/codebase/db_oracle.php deleted file mode 100644 index 703d3a4..0000000 --- a/codebase/db_oracle.php +++ /dev/null @@ -1,88 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("db_common.php"); -/*! Implementation of DataWrapper for Oracle -**/ -class OracleDBDataWrapper extends DBDataWrapper{ - private $last_id=""; //id of previously inserted record - private $insert_operation=false; //flag of insert operation - - public function query($sql){ - LogMaster::log($sql); - $stm = oci_parse($this->connection,$sql); - if ($stm===false) throw new Exception("Oracle - sql parsing failed\n".oci_error($this->connection)); - - $out = array(0=>null); - if($this->insert_operation){ - oci_bind_by_name($stm,":outID",$out[0],999); - $this->insert_operation=false; - } - - - $mode = ($this->is_record_transaction() || $this->is_global_transaction())?OCI_DEFAULT:OCI_COMMIT_ON_SUCCESS; - $res = @oci_execute($stm,$mode); - if ($res===false) throw new Exception(oci_error($this->connection)); - - $this->last_id=$out[0]; - - return $stm; - } - - public function get_next($res){ - $data = oci_fetch_assoc($res); - if ($data){ - foreach ($data as $k => $v) - $data[strtolower($k)] = $v; - } - return $data; - } - - public function get_new_id(){ - /* - Oracle doesn't support identity or auto-increment fields - Insert SQL returns new ID value, which stored in last_id field - */ - return $this->last_id; - } - - protected function insert_query($data,$request){ - $sql = parent::insert_query($data,$request); - $this->insert_operation=true; - return $sql." returning ".$this->config->id["db_name"]." into :outID"; - } - - protected function select_query($select,$from,$where,$sort,$start,$count){ - if (!$from) - return $select; - - $sql="SELECT ".$select." FROM ".$from; - if ($where) $sql.=" WHERE ".$where; - if ($sort) $sql.=" ORDER BY ".$sort; - if ($start || $count) - $sql="SELECT * FROM ( select /*+ FIRST_ROWS(".$count.")*/dhx_table.*, ROWNUM rnum FROM (".$sql.") dhx_table where ROWNUM <= ".($count+$start)." ) where rnum >".$start; - return $sql; - } - - public function escape($data){ - /* - as far as I can see the only way to escape data is by using oci_bind_by_name - while it is neat solution in common case, it conflicts with existing SQL building logic - fallback to simple escaping - */ - return str_replace("'","''",$data); - } - - public function begin_transaction(){ - //auto-start of transaction - } - public function commit_transaction(){ - oci_commit($this->connection); - } - public function rollback_transaction(){ - oci_rollback($this->connection); - } -} -?>
\ No newline at end of file diff --git a/codebase/db_phpcake.php b/codebase/db_phpcake.php deleted file mode 100644 index 4df0289..0000000 --- a/codebase/db_phpcake.php +++ /dev/null @@ -1,85 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("db_common.php"); - -//DataProcessor::$action_param ="dhx_editor_status"; - -/*! Implementation of DataWrapper for PDO - -if you plan to use it for Oracle - use Oracle connection type instead -**/ -class PHPCakeDBDataWrapper extends ArrayDBDataWrapper{ - public function select($sql){ - $source = $sql->get_source(); - if (is_array($source)) //result of find - $res = $source; - else - $res = $this->connection->find("all"); - - $temp = array(); - if (sizeof($res)){ - $name = get_class($this->connection); - for ($i=sizeof($res)-1; $i>=0; $i--) - $temp[]=&$res[$i][$name]; - } - return new ArrayQueryWrapper($temp); - } - - protected function getErrorMessage(){ - $errors = $this->connection->invalidFields(); - $text = array(); - foreach ($errors as $key => $value){ - $text[] = $key." - ".$value[0]; - } - return implode("\n", $text); - } - - public function insert($data,$source){ - $name = get_class($this->connection); - $save = array(); - $temp_data = $data->get_data(); - unset($temp_data[$this->config->id['db_name']]); - unset($temp_data["!nativeeditor_status"]); - $save[$name] = $temp_data; - - if ($this->connection->save($save)){ - $data->success($this->connection->getLastInsertID()); - } else { - $data->set_response_attribute("details", $this->getErrorMessage()); - $data->invalid(); - } - } - public function delete($data,$source){ - $id = $data->get_id(); - $this->connection->delete($id); - $data->success(); - } - public function update($data,$source){ - $name = get_class($this->connection); - $save = array(); - $save[$name] = &$data->get_data(); - - if ($this->connection->save($save)){ - $data->success(); - } else { - $data->set_response_attribute("details", $this->getErrorMessage()); - $data->invalid(); - } - } - - - public function escape($str){ - throw new Exception("Not implemented"); - } - public function query($str){ - throw new Exception("Not implemented"); - } - public function get_new_id(){ - throw new Exception("Not implemented"); - } -} - -?>
\ No newline at end of file diff --git a/codebase/db_phpci.php b/codebase/db_phpci.php deleted file mode 100644 index 9d10d99..0000000 --- a/codebase/db_phpci.php +++ /dev/null @@ -1,65 +0,0 @@ -<?php
-/*
- @author dhtmlx.com
- @license GPL, see license.txt
-*/
-require_once("db_common.php");
-
-/*! Implementation of DataWrapper for PDO
-
-if you plan to use it for Oracle - use Oracle connection type instead
-**/
-class PHPCIDBDataWrapper extends DBDataWrapper{
- private $last_result;//!< store result or last operation
-
- public function query($sql){
- LogMaster::log($sql);
-
- $res=$this->connection->query($sql);
- if ($res===false) {
- throw new Exception("CI - sql execution failed");
- }
-
- if (is_object($res))
- return new PHPCIResultSet($res);
- return new ArrayQueryWrapper(array());
- }
-
- public function get_next($res){
- $data = $res->next();
- return $data;
- }
-
- public function get_new_id(){
- return $this->connection->insert_id();
- }
-
- public function escape($str){
- return $this->connection->escape_str($str);
- }
-
- public function escape_name($data){
- return $this->connection->protect_identifiers($data);
- }
-}
-
-class PHPCIResultSet{
- private $res;
- private $start;
- private $count;
-
- public function __construct($res){
- $this->res = $res;
- $this->start = $res->current_row;
- $this->count = $res->num_rows;
- }
- public function next(){
- if ($this->start != $this->count){
- return $this->res->row($this->start++,'array');
- } else {
- $this->res->free_result();
- return null;
- }
- }
-}
-?>
\ No newline at end of file diff --git a/codebase/db_postgre.php b/codebase/db_postgre.php deleted file mode 100644 index a7d1598..0000000 --- a/codebase/db_postgre.php +++ /dev/null @@ -1,73 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("db_common.php"); -/*! Implementation of DataWrapper for PostgreSQL -**/ -class PostgreDBDataWrapper extends DBDataWrapper{ - public function query($sql){ - LogMaster::log($sql); - - $res=pg_query($this->connection,$sql); - if ($res===false) throw new Exception("Postgre - sql execution failed\n".pg_last_error($this->connection)); - - return $res; - } - - protected function select_query($select,$from,$where,$sort,$start,$count){ - if (!$from) - return $select; - - $sql="SELECT ".$select." FROM ".$from; - if ($where) $sql.=" WHERE ".$where; - if ($sort) $sql.=" ORDER BY ".$sort; - if ($start || $count) - $sql.=" OFFSET ".$start." LIMIT ".$count; - return $sql; - } - - public function get_next($res){ - return pg_fetch_assoc($res); - } - - public function get_new_id(){ - $res = pg_query( $this->connection, "SELECT LASTVAL() AS seq"); - $data = pg_fetch_assoc($res); - pg_free_result($res); - return $data['seq']; - } - - public function escape($data){ - //need to use oci_bind_by_name - return pg_escape_string($this->connection,$data); - } - - public function tables_list() { - $sql = "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'"; - $res = pg_query($this->connection, $sql); - $tables = array(); - while ($table = pg_fetch_assoc($res)) { - $tables[] = $table['table_name']; - } - return $tables; - } - - public function fields_list($table) { - $sql = "SELECT * FROM information_schema.constraint_column_usage"; - $result = pg_query($this->connection, $sql); - $field = pg_fetch_assoc($result); - $id = $field['column_name']; - - $sql = "SELECT * FROM information_schema.columns WHERE table_name ='".$table."';"; - $result = pg_query($this->connection, $sql); - $fields = array(); - $id = ""; - while ($field = pg_fetch_assoc($result)) { - $fields[] = $field["column_name"]; - } - return array('fields' => $fields, 'key' => $id ); - } -} -?>
\ No newline at end of file diff --git a/codebase/db_sasql.php b/codebase/db_sasql.php deleted file mode 100644 index 025f5ef..0000000 --- a/codebase/db_sasql.php +++ /dev/null @@ -1,54 +0,0 @@ -<?php -require_once("db_common.php"); -/*! SaSQL implementation of DataWrapper -**/ -class SaSQLDBDataWrapper extends DBDataWrapper{ - private $last_id=""; //!< ID of previously inserted record - - public function query($sql){ - LogMaster::log($sql); - $res=sasql_query($this->connection, $sql); - if ($res===false) throw new Exception("SaSQL operation failed\n".sasql_error($this->connection)); - $this->last_result = $res; - return $res; - } - - public function get_next($res){ - if (!$res) - $res = $this->last_result; - - return sasql_fetch_assoc($res); - } - - public function get_new_id(){ - return sasql_insert_id($this->connection); - } - - protected function insert_query($data,$request){ - $sql = parent::insert_query($data,$request); - $this->insert_operation=true; - return $sql; - } - - protected function select_query($select,$from,$where,$sort,$start,$count){ - if (!$from) - return $select; - - $sql="SELECT " ; - if ($count) - $sql.=" TOP ".($count+$start); - $sql.=" ".$select." FROM ".$from; - if ($where) $sql.=" WHERE ".$where; - if ($sort) $sql.=" ORDER BY ".$sort; - return $sql; - } - - public function escape($data){ - return sasql_escape_string($this->connection, $data); - } - - public function begin_transaction(){ - $this->query("BEGIN TRAN"); - } -} -?>
\ No newline at end of file diff --git a/codebase/db_sqlite.php b/codebase/db_sqlite.php deleted file mode 100644 index 04df7e5..0000000 --- a/codebase/db_sqlite.php +++ /dev/null @@ -1,34 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("db_common.php"); -/*! SQLite implementation of DataWrapper -**/ -class SQLiteDBDataWrapper extends DBDataWrapper{ - - public function query($sql){ - LogMaster::log($sql); - - $res = sqlite_query($this->connection,$sql); - if ($res === false) - throw new Exception("SQLLite - sql execution failed\n".sqlite_error_string(sqlite_last_error($this->connection))); - - return $res; - } - - public function get_next($res){ - $data = sqlite_fetch_array($res, SQLITE_ASSOC); - return $data; - } - - public function get_new_id(){ - return sqlite_last_insert_rowid($this->connection); - } - - public function escape($data){ - return sqlite_escape_string($data); - } -} -?>
\ No newline at end of file diff --git a/codebase/db_sqlite3.php b/codebase/db_sqlite3.php deleted file mode 100644 index 349490b..0000000 --- a/codebase/db_sqlite3.php +++ /dev/null @@ -1,33 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("db_common.php"); -/*! SQLite implementation of DataWrapper -**/ -class SQLite3DBDataWrapper extends DBDataWrapper{ - - public function query($sql){ - LogMaster::log($sql); - - $res = $this->connection->query($sql); - if ($res === false) - throw new Exception("SQLLite - sql execution failed\n".$this->connection->lastErrorMsg()); - - return $res; - } - - public function get_next($res){ - return $res->fetchArray(); - } - - public function get_new_id(){ - return $this->connection->lastInsertRowID(); - } - - public function escape($data){ - return $this->connection->escapeString($data); - } -} -?>
\ No newline at end of file diff --git a/codebase/db_sqlsrv.php b/codebase/db_sqlsrv.php deleted file mode 100644 index 1b27020..0000000 --- a/codebase/db_sqlsrv.php +++ /dev/null @@ -1,102 +0,0 @@ -<?php -/* -This software is allowed to use under GPL or you need to obtain Commercial or Enterise License -to use it in non-GPL project. Please contact sales@dhtmlx.com for details -*/ -?><?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("db_common.php"); -/*! MSSQL implementation of DataWrapper -**/ -class SQLSrvDBDataWrapper extends DBDataWrapper{ - private $last_id=""; //!< ID of previously inserted record - private $insert_operation=false; //!< flag of insert operation - private $start_from=false; //!< index of start position - - public function query($sql){ - LogMaster::log($sql); - if ($this->start_from) - $res = sqlsrv_query($this->connection,$sql, array(), array("Scrollable" => SQLSRV_CURSOR_STATIC)); - else - $res = sqlsrv_query($this->connection,$sql); - - if ($res === false){ - $errors = sqlsrv_errors(); - $message = Array(); - foreach($errors as $error) - $message[]=$error["SQLSTATE"].$error["code"].$error["message"]; - throw new Exception("SQLSrv operation failed\n".implode("\n\n", $message)); - } - - if ($this->insert_operation){ - sqlsrv_next_result($res); - $last = sqlsrv_fetch_array($res); - $this->last_id = $last["dhx_id"]; - sqlsrv_free_stmt($res); - } - if ($this->start_from) - $data = sqlsrv_fetch($res, SQLSRV_SCROLL_ABSOLUTE, $this->start_from-1); - return $res; - } - - public function get_next($res){ - $data = sqlsrv_fetch_array($res, SQLSRV_FETCH_ASSOC); - if ($data) - foreach ($data as $key => $value) - if (is_a($value, "DateTime")) - $data[$key] = $value->format("Y-m-d H:i"); - return $data; - } - - public function get_new_id(){ - /* - MSSQL doesn't support identity or auto-increment fields - Insert SQL returns new ID value, which stored in last_id field - */ - return $this->last_id; - } - - protected function insert_query($data,$request){ - $sql = parent::insert_query($data,$request); - $this->insert_operation=true; - return $sql.";SELECT SCOPE_IDENTITY() as dhx_id"; - } - - protected function select_query($select,$from,$where,$sort,$start,$count){ - if (!$from) - return $select; - - $sql="SELECT " ; - if ($count) - $sql.=" TOP ".($count+$start); - $sql.=" ".$select." FROM ".$from; - if ($where) $sql.=" WHERE ".$where; - if ($sort) $sql.=" ORDER BY ".$sort; - if ($start && $count) - $this->start_from=$start; - else - $this->start_from=false; - return $sql; - } - - public function escape($data){ - /* - there is no special escaping method for mssql - use common logic - */ - return str_replace("'","''",$data); - } - - public function begin_transaction(){ - sqlsrv_begin_transaction($this->connection); - } - public function commit_transaction(){ - sqlsrv_commit($this->connection); - } - public function rollback_transaction(){ - sqlsrv_rollback($this->connection); - } -} -?>
\ No newline at end of file diff --git a/codebase/filesystem_item.php b/codebase/filesystem_item.php deleted file mode 100644 index 046ad98..0000000 --- a/codebase/filesystem_item.php +++ /dev/null @@ -1,19 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ - -class FileTreeDataItem extends TreeDataItem { - - function has_kids(){ - if ($this->data['is_folder'] == '1') { - return true; - } else { - return false; - } - } - -} - -?>
\ No newline at end of file diff --git a/codebase/form_connector.php b/codebase/form_connector.php deleted file mode 100644 index 5eeea38..0000000 --- a/codebase/form_connector.php +++ /dev/null @@ -1,62 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("base_connector.php"); - -/*! DataItem class for dhxForm component -**/ -class FormDataItem extends DataItem{ - /*! return self as XML string - */ - function to_xml(){ - if ($this->skip) return ""; - $str=""; - for ($i = 0; $i < count($this->config->data); $i++) { - $str .= "<".$this->config->data[$i]['name']."><![CDATA[".$this->data[$this->config->data[$i]['name']]."]]></".$this->config->data[$i]['name'].">"; - } - return $str; - } -} - - -/*! Connector class for dhtmlxForm -**/ -class FormConnector extends Connector{ - - /*! constructor - - Here initilization of all Masters occurs, execution timer initialized - @param res - db connection resource - @param type - string , which hold type of database ( MySQL or Postgre ), optional, instead of short DB name, full name of DataWrapper-based class can be provided - @param item_type - name of class, which will be used for item rendering, optional, DataItem will be used by default - @param data_type - name of class which will be used for dataprocessor calls handling, optional, DataProcessor class will be used by default. - */ - public function __construct($res,$type=false,$item_type=false,$data_type=false){ - if (!$item_type) $item_type="FormDataItem"; - if (!$data_type) $data_type="FormDataProcessor"; - parent::__construct($res,$type,$item_type,$data_type); - } - - //parse GET scoope, all operations with incoming request must be done here - function parse_request(){ - parent::parse_request(); - if (isset($_GET["id"])) - $this->request->set_filter($this->config->id["name"],$_GET["id"],"="); - else if (!$_POST["ids"]) - throw new Exception("ID parameter is missed"); - } - -} - -/*! DataProcessor class for dhxForm component -**/ -class FormDataProcessor extends DataProcessor{ - -} -?>
\ No newline at end of file diff --git a/codebase/gantt_connector.php b/codebase/gantt_connector.php deleted file mode 100644 index 3577835..0000000 --- a/codebase/gantt_connector.php +++ /dev/null @@ -1,364 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("base_connector.php"); -require_once("data_connector.php"); - -/*! DataItem class for Gantt component -**/ -class GanttDataItem extends DataItem{ - - /*! return self as XML string - */ - function to_xml(){ - if ($this->skip) return ""; - - $str="<task id='".$this->get_id()."' >"; - $str.="<start_date><![CDATA[".$this->data[$this->config->text[0]["name"]]."]]></start_date>"; - $str.="<".$this->config->text[1]["name"]."><![CDATA[".$this->data[$this->config->text[1]["name"]]."]]></".$this->config->text[1]["name"].">"; - $str.="<text><![CDATA[".$this->data[$this->config->text[2]["name"]]."]]></text>"; - for ($i=3; $i<sizeof($this->config->text); $i++){ - $extra = $this->config->text[$i]["name"]; - $str.="<".$extra."><![CDATA[".$this->data[$extra]."]]></".$extra.">"; - } - if ($this->userdata !== false) - foreach ($this->userdata as $key => $value) - $str.="<".$key."><![CDATA[".$value."]]></".$key.">"; - - return $str."</task>"; - } -} - - -/*! Connector class for dhtmlxGantt -**/ -class GanttConnector extends Connector{ - - protected $extra_output="";//!< extra info which need to be sent to client side - protected $options=array();//!< hash of OptionsConnector - protected $links_mode = false; - - - /*! assign options collection to the column - - @param name - name of the column - @param options - array or connector object - */ - public function set_options($name,$options){ - if (is_array($options)){ - $str=""; - foreach($options as $k => $v) - $str.="<item value='".$this->xmlentities($k)."' label='".$this->xmlentities($v)."' />"; - $options=$str; - } - $this->options[$name]=$options; - } - - - /*! constructor - - Here initilization of all Masters occurs, execution timer initialized - @param res - db connection resource - @param type - string , which hold type of database ( MySQL or Postgre ), optional, instead of short DB name, full name of DataWrapper-based class can be provided - @param item_type - name of class, which will be used for item rendering, optional, DataItem will be used by default - @param data_type - name of class which will be used for dataprocessor calls handling, optional, DataProcessor class will be used by default. - * @param render_type - name of class which will be used for rendering. - */ - public function __construct($res,$type=false,$item_type=false,$data_type=false,$render_type=false){ - if (!$item_type) $item_type="GanttDataItem"; - if (!$data_type) $data_type="GanttDataProcessor"; - if (!$render_type) $render_type="RenderStrategy"; - parent::__construct($res,$type,$item_type,$data_type,$render_type); - - $this->event->attach("afterDelete", array($this, "delete_related_links")); - $this->event->attach("afterOrder", array($this, "order_set_parent")); - } - - //parse GET scoope, all operations with incoming request must be done here - function parse_request(){ - parent::parse_request(); - - if (isset($_GET["gantt_mode"]) && $_GET["gantt_mode"] == "links") - $this->links_mode = true; - - if (count($this->config->text)){ - if (isset($_GET["to"])) - $this->request->set_filter($this->config->text[0]["name"],$_GET["to"],"<"); - if (isset($_GET["from"])) - $this->request->set_filter($this->config->text[1]["name"],$_GET["from"],">"); - } - } - - function order_set_parent($action){ - $value = $action->get_id(); - $parent = $action->get_value("parent"); - - $table = $this->request->get_source(); - $id = $this->config->id["db_name"]; - - $this->sql->query("UPDATE $table SET parent = $parent WHERE $id = $value"); - } - - function delete_related_links($action){ - if (isset($this->options["links"])){ - $links = $this->options["links"]; - $value = $this->sql->escape($action->get_new_id()); - $table = $links->get_request()->get_source(); - - $this->sql->query("DELETE FROM $table WHERE source = '$value'"); - $this->sql->query("DELETE FROM $table WHERE target = '$value'"); - } - } - - public function render_links($table,$id="",$fields=false,$extra=false,$relation_id=false) { - $links = new GanttLinksConnector($this->get_connection(),$this->names["db_class"]); - $links->render_table($table,$id,$fields,$extra); - $this->set_options("links", $links); - } -} - -/*! DataProcessor class for Gantt component -**/ -class GanttDataProcessor extends DataProcessor{ - function name_data($data){ - if ($data=="start_date") - return $this->config->text[0]["name"]; - if ($data=="id") - return $this->config->id["name"]; - if ($data=="duration" && $this->config->text[1]["name"] == "duration") - return $this->config->text[1]["name"]; - if ($data=="end_date" && $this->config->text[1]["name"] == "end_date") - return $this->config->text[1]["name"]; - if ($data=="text") - return $this->config->text[2]["name"]; - - return $data; - } -} - - -class JSONGanttDataItem extends GanttDataItem{ - /*! return self as XML string - */ - function to_xml(){ - if ($this->skip) return ""; - - $obj = array(); - $obj['id'] = $this->get_id(); - $obj['start_date'] = $this->data[$this->config->text[0]["name"]]; - $obj[$this->config->text[1]["name"]] = $this->data[$this->config->text[1]["name"]]; - $obj['text'] = $this->data[$this->config->text[2]["name"]]; - for ($i=3; $i<sizeof($this->config->text); $i++){ - $extra = $this->config->text[$i]["name"]; - $obj[$extra]=$this->data[$extra]; - } - - if ($this->userdata !== false) - foreach ($this->userdata as $key => $value) - $obj[$key]=$value; - - return $obj; - } -} - - -class JSONGanttConnector extends GanttConnector { - - protected $data_separator = ","; - - /*! constructor - - Here initilization of all Masters occurs, execution timer initialized - @param res - db connection resource - @param type - string , which hold type of database ( MySQL or Postgre ), optional, instead of short DB name, full name of DataWrapper-based class can be provided - @param item_type - name of class, which will be used for item rendering, optional, DataItem will be used by default - @param data_type - name of class which will be used for dataprocessor calls handling, optional, DataProcessor class will be used by default. - */ - public function __construct($res,$type=false,$item_type=false,$data_type=false,$render_type=false){ - if (!$item_type) $item_type="JSONGanttDataItem"; - if (!$data_type) $data_type="GanttDataProcessor"; - if (!$render_type) $render_type="JSONRenderStrategy"; - parent::__construct($res,$type,$item_type,$data_type,$render_type); - } - - protected function xml_start() { - return '{ "data":'; - } - - protected function xml_end() { - $this->fill_collections(); - $end = (!empty($this->extra_output)) ? ', "collections": {'.$this->extra_output.'}' : ''; - foreach ($this->attributes as $k => $v) - $end.=", \"".$k."\":\"".$v."\""; - $end .= '}'; - return $end; - } - - /*! assign options collection to the column - - @param name - name of the column - @param options - array or connector object - */ - public function set_options($name,$options){ - if (is_array($options)){ - $str=array(); - foreach($options as $k => $v) - $str[]='{"id":"'.$this->xmlentities($k).'", "value":"'.$this->xmlentities($v).'"}'; - $options=implode(",",$str); - } - $this->options[$name]=$options; - } - - - /*! generates xml description for options collections - - @param list - comma separated list of column names, for which options need to be generated - */ - protected function fill_collections($list=""){ - $options = array(); - foreach ($this->options as $k=>$v) { - $name = $k; - $option="\"{$name}\":["; - if (!is_string($this->options[$name])){ - $data = json_encode($this->options[$name]->render()); - $option.=substr($data,1,-1); - } else - $option.=$this->options[$name]; - $option.="]"; - $options[] = $option; - } - $this->extra_output .= implode($this->data_separator, $options); - } - - - /*! output fetched data as XML - @param res - DB resultset - */ - protected function output_as_xml($res){ - $result = $this->render_set($res); - if ($this->simple) return $result; - - $data=$this->xml_start().json_encode($result).$this->xml_end(); - - if ($this->as_string) return $data; - - $out = new OutputWriter($data, ""); - $out->set_type("json"); - $this->event->trigger("beforeOutput", $this, $out); - $out->output("", true, $this->encoding); - } - - public function render_links($table,$id="",$fields=false,$extra=false,$relation_id=false) { - $links = new JSONGanttLinksConnector($this->get_connection(),$this->names["db_class"]); - $links->render_table($table,$id,$fields,$extra); - $this->set_options("links", $links); - } - - - /*! render self - process commands, output requested data as XML - */ - public function render(){ - $this->event->trigger("onInit", $this); - EventMaster::trigger_static("connectorInit",$this); - - if (!$this->as_string) - $this->parse_request(); - $this->set_relation(); - - if ($this->live_update !== false && $this->updating!==false) { - $this->live_update->get_updates(); - } else { - if ($this->editing){ - if ($this->links_mode && isset($this->options["links"])) { - $this->options["links"]->save(); - } else { - $dp = new $this->names["data_class"]($this,$this->config,$this->request); - $dp->process($this->config,$this->request); - } - } else { - if (!$this->access->check("read")){ - LogMaster::log("Access control: read operation blocked"); - echo "Access denied"; - die(); - } - $wrap = new SortInterface($this->request); - $this->apply_sorts($wrap); - $this->event->trigger("beforeSort",$wrap); - $wrap->store(); - - $wrap = new FilterInterface($this->request); - $this->apply_filters($wrap); - $this->event->trigger("beforeFilter",$wrap); - $wrap->store(); - - if ($this->model && method_exists($this->model, "get")){ - $this->sql = new ArrayDBDataWrapper(); - $result = new ArrayQueryWrapper(call_user_func(array($this->model, "get"), $this->request)); - $out = $this->output_as_xml($result); - } else { - $out = $this->output_as_xml($this->get_resource()); - - if ($out !== null) return $out; - } - - } - } - $this->end_run(); - } -} - - -class GanttLinksConnector extends OptionsConnector { - public function render(){ - if (!$this->init_flag){ - $this->init_flag=true; - return ""; - } - - $res = $this->sql->select($this->request); - return $this->render_set($res); - } - - public function save() { - $dp = new $this->names["data_class"]($this,$this->config,$this->request); - $dp->process($this->config,$this->request); - } -} - - -class JSONGanttLinksConnector extends JSONOptionsConnector { - public function render(){ - if (!$this->init_flag){ - $this->init_flag=true; - return ""; - } - - $res = $this->sql->select($this->request); - return $this->render_set($res); - } - - public function save() { - $dp = new $this->names["data_class"]($this,$this->config,$this->request); - $dp->process($this->config,$this->request); - } -} - -?>
\ No newline at end of file diff --git a/codebase/grid_config.php b/codebase/grid_config.php deleted file mode 100644 index 24297b2..0000000 --- a/codebase/grid_config.php +++ /dev/null @@ -1,423 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ - -class GridConfiguration{ - - /*! attaching header functionality - */ - protected $headerDelimiter = ','; - protected $headerNames = false; - protected $headerAttaches = array(); - protected $footerAttaches = array(); - protected $headerWidthsUnits = 'px'; - - protected $headerIds = false; - protected $headerWidths = false; - protected $headerTypes = false; - protected $headerAlign = false; - protected $headerVAlign = false; - protected $headerSorts = false; - protected $headerColors = false; - protected $headerHidden = false; - protected $headerFormat = false; - - protected $convert_mode = false; - - function __construct($headers = false){ - if ($headers === false || $headers === true ) - $this->headerNames = $headers; - else - $this->setHeader($headers); - } - - /*! brief convert list of parameters to an array - @param param - list of values or array of values - @return array of parameters - */ - private function parse_param_array($param, $check=false, $default = ""){ - if (gettype($param) == 'string') - $param = explode($this->headerDelimiter, $param); - - if ($check){ - for ($i=0; $i < sizeof($param); $i++) { - if (!array_key_exists($param[$i],$check)) - $param[$i] = $default; - } - } - return $param; - } - - /*! sets delimiter for string arguments in attach header functions (default is ,) - @param headerDelimiter - string delimiter - */ - public function setHeaderDelimiter($headerDelimiter) { - $this->headerDelimiter = $headerDelimiter; - } - - /*! sets header - @param names - array of names or string of names, delimited by headerDelimiter (default is ,) - */ - public function setHeader($names) { - if ($names instanceof DataConfig){ - $out = array(); - for ($i=0; $i < sizeof($names->text); $i++) - $out[]=$names->text[$i]["name"]; - $names = $out; - } - - $this->headerNames = $this->parse_param_array($names); - } - - /*! sets init columns width in pixels - @param wp - array of widths or string of widths, delimited by headerDelimiter (default is ,) - */ - public function setInitWidths($wp) { - $this->headerWidths = $this->parse_param_array($wp); - $this->headerWidthsUnits = 'px'; - } - - /*! sets init columns width in persents - @param wp - array of widths or string of widths, delimited by headerDelimiter (default is ,) - */ - public function setInitWidthsP($wp) { - $this->setInitWidths($wp); - $this->headerWidthsUnits = '%'; - } - - /*! sets columns align - @param alStr - array of aligns or string of aligns, delimited by headerDelimiter (default is ,) - */ - public function setColAlign($alStr) { - $this->headerAlign = $this->parse_param_array($alStr, - array("right"=>1, "left"=>1, "center"=>1, "justify"=>1), - "left"); - } - - /*! sets columns vertical align - @param alStr - array of vertical aligns or string of vertical aligns, delimited by headerDelimiter (default is ,) - */ - public function setColVAlign($alStr) { - $this->headerVAlign = $this->parse_param_array($alStr, - array("baseline"=>1, "sub"=>1, "super"=>1, "top"=>1, "text-top"=>1, "middle"=>1, "bottom"=>1, "text-bottom"=>1), - "top"); - } - - /*! sets column types - @param typeStr - array of types or string of types, delimited by headerDelimiter (default is ,) - */ - public function setColTypes($typeStr) { - $this->headerTypes = $this->parse_param_array($typeStr); - } - - /*! sets columns sorting - @param sortStr - array if sortings or string of sortings, delimited by headerDelimiter (default is ,) - */ - public function setColSorting($sortStr) { - $this->headerSorts = $this->parse_param_array($sortStr); - } - - /*! sets columns colors - @param colorStr - array of colors or string of colors, delimited by headerDelimiter (default is ,) - if (color should not be applied it's value should be null) - */ - public function setColColor($colorStr) { - $this->headerColors = $this->parse_param_array($colorStr); - } - - /*! sets hidden columns - @param hidStr - array of bool values or string of bool values, delimited by headerDelimiter (default is ,) - */ - public function setColHidden($hidStr) { - $this->headerHidden = $this->parse_param_array($hidStr); - } - - /*! sets columns id - @param idsStr - array of ids or string of ids, delimited by headerDelimiter (default is ,) - */ - public function setColIds($idsStr) { - $this->headerIds = $this->parse_param_array($idsStr); - } - - /*! sets number/date format - @param formatArr - array of mask formats for number/dates , delimited by headerDelimiter (default is ,) - */ - public function setColFormat($formatArr) { - $this->headerFormat = $this->parse_param_array($formatArr); - } - - /*! attaches header - @param values - array of header names or string of header names, delimited by headerDelimiter (default is ,) - @param styles - array of header styles or string of header styles, delimited by headerDelimiter (default is ,) - */ - public function attachHeader($values, $styles = null, $footer = false) { - $header = array(); - $header['values'] = $this->parse_param_array($values); - if ($styles != null) { - $header['styles'] = $this->parse_param_array($styles); - } else { - $header['styles'] = null; - } - if ($footer) - $this->footerAttaches[] = $header; - else - $this->headerAttaches[] = $header; - } - - /*! attaches footer - @param values - array of footer names or string of footer names, delimited by headerDelimiter (default is ,) - @param styles - array of footer styles or string of footer styles, delimited by headerDelimiter (default is ,) - */ - public function attachFooter($values, $styles = null) { - $this->attachHeader($values, $styles, true); - } - - private function auto_fill($mode){ - $headerWidths = array(); - $headerTypes = array(); - $headerSorts = array(); - $headerAttaches = array(); - - for ($i=0; $i < sizeof($this->headerNames); $i++) { - $headerWidths[] = 100; - $headerTypes[] = "ro"; - $headerSorts[] = "connector"; - $headerAttaches[] = "#connector_text_filter"; - } - if ($this->headerWidths == false) - $this->setInitWidths($headerWidths); - if ($this->headerTypes == false) - $this->setColTypes($headerTypes); - - if ($mode){ - if ($this->headerSorts == false) - $this->setColSorting($headerSorts); - $this->attachHeader($headerAttaches); - } - } - - public function defineOptions($conn){ - if (!$conn->is_first_call()) return; //render head only for first call - - $config = $conn->get_config(); - $full_header = ($this->headerNames === true); - - if (gettype($this->headerNames) == 'boolean') //auto-config - $this->setHeader($config); - $this->auto_fill($full_header); - - if (isset($_GET["dhx_colls"])) return; - - $fillList = array(); - for ($i = 0; $i < count($this->headerNames); $i++) - if ($this->headerTypes[$i] == "co" || $this->headerTypes[$i] == "coro") - $fillList[$i] = true; - - for ($i = 0; $i < count($this->headerAttaches); $i++) { - for ($j = 0; $j < count($this->headerAttaches[$i]['values']); $j++) { - if ($this->headerAttaches[$i]['values'][$j] == "#connector_select_filter" - || $this->headerAttaches[$i]['values'][$j] == "#select_filter") { - $fillList[$j] = true;; - } - } - } - - $temp = array(); - foreach($fillList as $k => $v) - $temp[] = $k; - if (count($temp)) - $_GET["dhx_colls"] = implode(",",$temp); - } - - - /*! gets header as array - */ - private function getHeaderArray() { - $head = Array(); - $head[0] = $this->headerNames; - $head = $this->getAttaches($head, $this->headerAttaches); - return $head; - } - - - /*! get footer as array - */ - private function getFooterArray() { - $foot = Array(); - $foot = $this->getAttaches($foot, $this->footerAttaches); - return $foot; - } - - - /*! gets array of data with attaches - */ - private function getAttaches($to, $from) { - for ($i = 0; $i < count($from); $i++) { - $line = $from[$i]['values']; - $to[] = $line; - } - return $to; - } - - - /*! calculates rowspan array according #cspan markers - */ - private function processCspan($data) { - $rspan = Array(); - for ($i = 0; $i < count($data); $i++) { - $last = 0; - $rspan[$i] = Array(); - for ($j = 0; $j < count($data[$i]); $j++) { - $rspan[$i][$j] = 0; - if ($data[$i][$j] === '#cspan') { - $rspan[$i][$last]++; - } else { - $last = $j; - } - } - } - return $rspan; - } - - - /*! calculates colspan array according #rspan markers - */ - private function processRspan($data) { - $last = Array(); - $cspan = Array(); - for ($i = 0; $i < count($data); $i++) { - $cspan[$i] = Array(); - for ($j = 0; $j < count($data[$i]); $j++) { - $cspan[$i][$j] = 0; - if (!isset($last[$j])) $last[$j] = 0; - if ($data[$i][$j] === '#rspan') { - $cspan[$last[$j]][$j]++; - } else { - $last[$j] = $i; - } - } - } - return $cspan; - } - - - /*! sets mode of output format: usual mode or convert mode. - * @param mode - * true - convert mode, false - otherwise - */ - public function set_convert_mode($mode) { - $this->convert_mode = $mode; - } - - - /*! adds header configuration in output XML - */ - public function attachHeaderToXML($conn, $out) { - if (!$conn->is_first_call()) return; //render head only for first call - - $head = $this->getHeaderArray(); - $foot = $this->getFooterArray(); - $rspan = $this->processRspan($head); - $cspan = $this->processCspan($head); - - $str = '<head>'; - - if ($this->convert_mode) $str .= "<columns>"; - - for ($i = 0; $i < count($this->headerNames); $i++) { - $str .= '<column'; - $str .= ' type="'. $this->headerTypes[$i].'"'; - $str .= ' width="'.$this->headerWidths[$i].'"'; - $str .= $this->headerIds ? ' id="'.$this->headerIds[$i].'"' : ''; - $str .= $this->headerAlign[$i] ? ' align="'.$this->headerAlign[$i].'"' : ''; - $str .= $this->headerVAlign[$i] ? ' valign="'.$this->headerVAlign[$i].'"' : ''; - $str .= $this->headerSorts[$i] ? ' sort="'.$this->headerSorts[$i].'"' : ''; - $str .= $this->headerColors[$i] ? ' color="'.$this->headerColors[$i].'"' : ''; - $str .= $this->headerHidden[$i] ? ' hidden="'.$this->headerHidden[$i].'"' : ''; - $str .= $this->headerFormat[$i] ? ' format="'.$this->headerFormat[$i].'"' : ''; - $str .= $cspan[0][$i] ? ' colspan="'.($cspan[0][$i] + 1).'"' : ''; - $str .= $rspan[0][$i] ? ' rowspan="'.($rspan[0][$i] + 1).'"' : ''; - $str .= '>'.$this->headerNames[$i].'</column>'; - } - - if (!$this->convert_mode) { - $str .= '<settings><colwidth>'.$this->headerWidthsUnits.'</colwidth></settings>'; - if ((count($this->headerAttaches) > 0)||(count($this->footerAttaches) > 0)) { - $str .= '<afterInit>'; - } - for ($i = 0; $i < count($this->headerAttaches); $i++) { - $str .= '<call command="attachHeader">'; - $str .= '<param>'.implode(",",$this->headerAttaches[$i]['values']).'</param>'; - if ($this->headerAttaches[$i]['styles'] != null) { - $str .= '<param>'.implode(",",$this->headerAttaches[$i]['styles']).'</param>'; - } - $str .= '</call>'; - } - for ($i = 0; $i < count($this->footerAttaches); $i++) { - $str .= '<call command="attachFooter">'; - $str .= '<param>'.implode(",",$this->footerAttaches[$i]['values']).'</param>'; - if ($this->footerAttaches[$i]['styles'] != null) { - $str .= '<param>'.implode(",",$this->footerAttaches[$i]['styles']).'</param>'; - } - $str .= '</call>'; - } - if ((count($this->headerAttaches) > 0)||(count($this->footerAttaches) > 0)) { - $str .= '</afterInit>'; - } - } else { - $str .= "</columns>"; - for ($i = 1; $i < count($head); $i++) { - $str .= "<columns>"; - for ($j = 0; $j < count($head[$i]); $j++) { - $str .= '<column'; - $str .= $cspan[$i][$j] ? ' colspan="'.($cspan[$i][$j] + 1).'"' : ''; - $str .= $rspan[$i][$j] ? ' rowspan="'.($rspan[$i][$j] + 1).'"' : ''; - $str .= '>'.$head[$i][$j].'</column>'; - } - $str .= "</columns>\n"; - } - } - $str .= '</head>'; - - - if ($this->convert_mode && count($foot) > 0) { - $rspan = $this->processRspan($foot); - $cspan = $this->processCspan($foot); - $str .= "<foot>"; - for ($i = 0; $i < count($foot); $i++) { - $str .= "<columns>"; - for ($j = 0; $j < count($foot[$i]); $j++) { - $str .= '<column'; - $str .= $cspan[$i][$j] ? ' colspan="'.($cspan[$i][$j] + 1).'"' : ''; - $str .= $rspan[$i][$j] ? ' rowspan="'.($rspan[$i][$j] + 1).'"' : ''; - $str .= '>'.$foot[$i][$j].'</column>'; - } - $str .= "</columns>\n"; - } - $str .= "</foot>"; - } - - $out->add($str); - } -} - -?>
\ No newline at end of file diff --git a/codebase/grid_connector.php b/codebase/grid_connector.php deleted file mode 100644 index d9be16a..0000000 --- a/codebase/grid_connector.php +++ /dev/null @@ -1,269 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("base_connector.php"); -require_once("grid_config.php"); - -//require_once("grid_dataprocessor.php"); - -/*! DataItem class for Grid component -**/ - -class GridDataItem extends DataItem{ - protected $row_attrs;//!< hash of row attributes - protected $cell_attrs;//!< hash of cell attributes - - function __construct($data,$name,$index=0){ - parent::__construct($data,$name,$index); - - $this->row_attrs=array(); - $this->cell_attrs=array(); - } - /*! set color of row - - @param color - color of row - */ - function set_row_color($color){ - $this->row_attrs["bgColor"]=$color; - } - /*! set style of row - - @param color - color of row - */ - function set_row_style($color){ - $this->row_attrs["style"]=$color; - } - /*! assign custom style to the cell - - @param name - name of column - @param value - css style string - */ - function set_cell_style($name,$value){ - $this->set_cell_attribute($name,"style",$value); - } - /*! assign custom class to specific cell - - @param name - name of column - @param value - css class name - */ - function set_cell_class($name,$value){ - $this->set_cell_attribute($name,"class",$value); - } - /*! set custom cell attribute - - @param name - name of column - @param attr - name of attribute - @param value - value of attribute - */ - function set_cell_attribute($name,$attr,$value){ - if (!array_key_exists($name, $this->cell_attrs)) $this->cell_attrs[$name]=array(); - $this->cell_attrs[$name][$attr]=$value; - } - - /*! set custom row attribute - - @param attr - name of attribute - @param value - value of attribute - */ - function set_row_attribute($attr,$value){ - $this->row_attrs[$attr]=$value; - } - - /*! return self as XML string, starting part - */ - public function to_xml_start(){ - if ($this->skip) return ""; - - $str="<row id='".$this->xmlentities($this->get_id())."'"; - foreach ($this->row_attrs as $k=>$v) - $str.=" ".$k."='".$v."'"; - $str.=">"; - for ($i=0; $i < sizeof($this->config->text); $i++){ - $str.="<cell"; - $name=$this->config->text[$i]["name"]; - $xmlcontent = false; - if (isset($this->cell_attrs[$name])){ - $cattrs=$this->cell_attrs[$name]; - foreach ($cattrs as $k => $v){ - $str.=" ".$k."='".$this->xmlentities($v)."'"; - if ($k == "xmlcontent") - $xmlcontent = true; - } - } - $value = isset($this->data[$name]) ? $this->data[$name] : ''; - if (!$xmlcontent) - $str.="><![CDATA[".$value."]]></cell>"; - else - $str.=">".$value."</cell>"; - } - if ($this->userdata !== false) - foreach ($this->userdata as $key => $value) - $str.="<userdata name='".$key."'><![CDATA[".$value."]]></userdata>"; - - return $str; - } - /*! return self as XML string, ending part - */ - public function to_xml_end(){ - if ($this->skip) return ""; - - return "</row>"; - } -} -/*! Connector for the dhtmlxgrid -**/ -class GridConnector extends Connector{ - - /*! constructor - - Here initilization of all Masters occurs, execution timer initialized - @param res - db connection resource - @param type - string , which hold type of database ( MySQL or Postgre ), optional, instead of short DB name, full name of DataWrapper-based class can be provided - @param item_type - name of class, which will be used for item rendering, optional, DataItem will be used by default - @param data_type - name of class which will be used for dataprocessor calls handling, optional, DataProcessor class will be used by default. - */ - public function __construct($res,$type=false,$item_type=false,$data_type=false,$render_type=false){ - if (!$item_type) $item_type="GridDataItem"; - if (!$data_type) $data_type="GridDataProcessor"; - if (!$render_type) $render_type="RenderStrategy"; - parent::__construct($res,$type,$item_type,$data_type,$render_type); - } - - - protected function parse_request(){ - parent::parse_request(); - - if (isset($_GET["dhx_colls"])) - $this->fill_collections($_GET["dhx_colls"]); - } - protected function resolve_parameter($name){ - if (intval($name).""==$name) - return $this->config->text[intval($name)]["db_name"]; - return $name; - } - - /*! replace xml unsafe characters - - @param string - string to be escaped - @return - escaped string - */ - protected function xmlentities($string) { - return str_replace( array( '&', '"', "'", '<', '>', '’' ), array( '&' , '"', ''' , '<' , '>', ''' ), $string); - } - - /*! assign options collection to the column - - @param name - name of the column - @param options - array or connector object - */ - public function set_options($name,$options){ - if (is_array($options)){ - $str=""; - foreach($options as $k => $v) - $str.="<item value='".$this->xmlentities($k)."' label='".$this->xmlentities($v)."' />"; - $options=$str; - } - $this->options[$name]=$options; - } - /*! generates xml description for options collections - - @param list - comma separated list of column names, for which options need to be generated - */ - protected function fill_collections($list=""){ - $names=explode(",",$list); - for ($i=0; $i < sizeof($names); $i++) { - $name = $this->resolve_parameter($names[$i]); - if (!array_key_exists($name,$this->options)){ - $this->options[$name] = new DistinctOptionsConnector($this->get_connection(),$this->names["db_class"]); - $c = new DataConfig($this->config); - $r = new DataRequestConfig($this->request); - $c->minimize($name); - - $this->options[$name]->render_connector($c,$r); - } - - $this->extra_output.="<coll_options for='{$names[$i]}'>"; - if (!is_string($this->options[$name])) - $this->extra_output.=$this->options[$name]->render(); - else - $this->extra_output.=$this->options[$name]; - $this->extra_output.="</coll_options>"; - } - } - - /*! renders self as xml, starting part - */ - protected function xml_start(){ - $attributes = ""; - foreach($this->attributes as $k=>$v) - $attributes .= " ".$k."='".$v."'"; - - if ($this->dload){ - if ($pos=$this->request->get_start()) - return "<rows pos='".$pos."'".$attributes.">"; - else - return "<rows total_count='".$this->sql->get_size($this->request)."'".$attributes.">"; - } - else - return "<rows".$attributes.">"; - } - - - /*! renders self as xml, ending part - */ - protected function xml_end(){ - return $this->extra_output."</rows>"; - } - - public function set_config($config = false){ - if (gettype($config) == 'boolean') - $config = new GridConfiguration($config); - - $this->event->attach("beforeOutput", Array($config, "attachHeaderToXML")); - $this->event->attach("onInit", Array($config, "defineOptions")); - } -} - -/*! DataProcessor class for Grid component -**/ -class GridDataProcessor extends DataProcessor{ - - /*! convert incoming data name to valid db name - converts c0..cN to valid field names - @param data - data name from incoming request - @return - related db_name - */ - function name_data($data){ - if ($data == "gr_id") return $this->config->id["name"]; - $parts=explode("c",$data); - if ($parts[0]=="" && ((string)intval($parts[1]))==$parts[1]) - if (sizeof($this->config->text)>intval($parts[1])) - return $this->config->text[intval($parts[1])]["name"]; - return $data; - } -} -?>
\ No newline at end of file diff --git a/codebase/keygrid_connector.php b/codebase/keygrid_connector.php deleted file mode 100644 index 3942ac2..0000000 --- a/codebase/keygrid_connector.php +++ /dev/null @@ -1,48 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("grid_connector.php"); -class KeyGridConnector extends GridConnector{ - public function __construct($res,$type=false,$item_type=false,$data_type=false){ - if (!$item_type) $item_type="GridDataItem"; - if (!$data_type) $data_type="KeyGridDataProcessor"; - parent::__construct($res,$type,$item_type,$data_type); - - $this->event->attach("beforeProcessing",array($this,"before_check_key")); - $this->event->attach("afterProcessing",array($this,"after_check_key")); - } - - public function before_check_key($action){ - if ($action->get_value($this->config->id["name"])=="") - $action->error(); - } - public function after_check_key($action){ - if ($action->get_status()=="inserted" || $action->get_status()=="updated"){ - $action->success($action->get_value($this->config->id["name"])); - $action->set_status("inserted"); - } - } -}; - -class KeyGridDataProcessor extends DataProcessor{ - - /*! convert incoming data name to valid db name - converts c0..cN to valid field names - @param data - data name from incoming request - @return - related db_name - */ - function name_data($data){ - if ($data == "gr_id") return "__dummy__id__"; //ignore ID - $parts=explode("c",$data); - if ($parts[0]=="" && intval($parts[1])==$parts[1]) - return $this->config->text[intval($parts[1])]["name"]; - return $data; - } -} - - -?>
\ No newline at end of file diff --git a/codebase/mixed_connector.php b/codebase/mixed_connector.php deleted file mode 100644 index 461d6ec..0000000 --- a/codebase/mixed_connector.php +++ /dev/null @@ -1,28 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("base_connector.php"); - -class MixedConnector extends Connector { - - protected $connectors = array(); - - public function add($name, $conn) { - $this->connectors[$name] = $conn; - } - - public function render() { - $result = "{"; - $parts = array(); - foreach($this->connectors as $name => $conn) { - $conn->asString(true); - $parts[] = "\"".$name."\":".($conn->render())."\n"; - } - $result .= implode(",\n", $parts)."}"; - echo $result; - } -} - -?>
\ No newline at end of file diff --git a/codebase/options_connector.php b/codebase/options_connector.php deleted file mode 100644 index dc72eb2..0000000 --- a/codebase/options_connector.php +++ /dev/null @@ -1,45 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("base_connector.php"); - -/*! DataItem class for dhxForm:options -**/ -class OptionsDataItem extends DataItem{ - /*! return self as XML string - */ - function to_xml(){ - if ($this->skip) return ""; - $str =""; - - $str .= "<item value=\"".$this->xmlentities($this->data[$this->config->data[0]['db_name']])."\" label=\"".$this->xmlentities($this->data[$this->config->data[1]['db_name']])."\" />"; - return $str; - } -} - -/*! Connector class for dhtmlxForm:options -**/ -class SelectOptionsConnector extends Connector{ - - /*! constructor - - Here initilization of all Masters occurs, execution timer initialized - @param res - db connection resource - @param type - string , which hold type of database ( MySQL or Postgre ), optional, instead of short DB name, full name of DataWrapper-based class can be provided - @param item_type - name of class, which will be used for item rendering, optional, DataItem will be used by default - @param data_type - name of class which will be used for dataprocessor calls handling, optional, DataProcessor class will be used by default. - */ - public function __construct($res,$type=false,$item_type=false,$data_type=false){ - if (!$item_type) $item_type="OptionsDataItem"; - parent::__construct($res,$type,$item_type,$data_type); - } - -} - -?>
\ No newline at end of file diff --git a/codebase/scheduler_connector.php b/codebase/scheduler_connector.php deleted file mode 100644 index ee0cd20..0000000 --- a/codebase/scheduler_connector.php +++ /dev/null @@ -1,230 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("base_connector.php"); -require_once("data_connector.php"); - -/*! DataItem class for Scheduler component -**/ -class SchedulerDataItem extends DataItem{ - /*! return self as XML string - */ - function to_xml(){ - if ($this->skip) return ""; - - $str="<event id='".$this->get_id()."' >"; - $str.="<start_date><![CDATA[".$this->data[$this->config->text[0]["name"]]."]]></start_date>"; - $str.="<end_date><![CDATA[".$this->data[$this->config->text[1]["name"]]."]]></end_date>"; - $str.="<text><![CDATA[".$this->data[$this->config->text[2]["name"]]."]]></text>"; - for ($i=3; $i<sizeof($this->config->text); $i++){ - $extra = $this->config->text[$i]["name"]; - $str.="<".$extra."><![CDATA[".$this->data[$extra]."]]></".$extra.">"; - } - if ($this->userdata !== false) - foreach ($this->userdata as $key => $value) - $str.="<".$key."><![CDATA[".$value."]]></".$key.">"; - - return $str."</event>"; - } -} - - -/*! Connector class for dhtmlxScheduler -**/ -class SchedulerConnector extends Connector{ - - protected $extra_output="";//!< extra info which need to be sent to client side - protected $options=array();//!< hash of OptionsConnector - - - /*! assign options collection to the column - - @param name - name of the column - @param options - array or connector object - */ - public function set_options($name,$options){ - if (is_array($options)){ - $str=""; - foreach($options as $k => $v) - $str.="<item value='".$this->xmlentities($k)."' label='".$this->xmlentities($v)."' />"; - $options=$str; - } - $this->options[$name]=$options; - } - - - /*! constructor - - Here initilization of all Masters occurs, execution timer initialized - @param res - db connection resource - @param type - string , which hold type of database ( MySQL or Postgre ), optional, instead of short DB name, full name of DataWrapper-based class can be provided - @param item_type - name of class, which will be used for item rendering, optional, DataItem will be used by default - @param data_type - name of class which will be used for dataprocessor calls handling, optional, DataProcessor class will be used by default. - * @param render_type - name of class which will be used for rendering. - */ - public function __construct($res,$type=false,$item_type=false,$data_type=false,$render_type=false){ - if (!$item_type) $item_type="SchedulerDataItem"; - if (!$data_type) $data_type="SchedulerDataProcessor"; - if (!$render_type) $render_type="RenderStrategy"; - parent::__construct($res,$type,$item_type,$data_type,$render_type); - } - - //parse GET scoope, all operations with incoming request must be done here - function parse_request(){ - parent::parse_request(); - if (count($this->config->text)){ - if (isset($_GET["to"])) - $this->request->set_filter($this->config->text[0]["name"],$_GET["to"],"<"); - if (isset($_GET["from"])) - $this->request->set_filter($this->config->text[1]["name"],$_GET["from"],">"); - } - } -} - -/*! DataProcessor class for Scheduler component -**/ -class SchedulerDataProcessor extends DataProcessor{ - function name_data($data){ - if ($data=="start_date") - return $this->config->text[0]["db_name"]; - if ($data=="id") - return $this->config->id["db_name"]; - if ($data=="end_date") - return $this->config->text[1]["db_name"]; - if ($data=="text") - return $this->config->text[2]["db_name"]; - - return $data; - } -} - - -class JSONSchedulerDataItem extends SchedulerDataItem{ - /*! return self as XML string - */ - function to_xml(){ - if ($this->skip) return ""; - - $obj = array(); - $obj['id'] = $this->get_id(); - $obj['start_date'] = $this->data[$this->config->text[0]["name"]]; - $obj['end_date'] = $this->data[$this->config->text[1]["name"]]; - $obj['text'] = $this->data[$this->config->text[2]["name"]]; - for ($i=3; $i<sizeof($this->config->text); $i++){ - $extra = $this->config->text[$i]["name"]; - $obj[$extra]=$this->data[$extra]; - } - - if ($this->userdata !== false) - foreach ($this->userdata as $key => $value) - $obj[$key]=$value; - - return $obj; - } -} - - -class JSONSchedulerConnector extends SchedulerConnector { - - protected $data_separator = ","; - - /*! constructor - - Here initilization of all Masters occurs, execution timer initialized - @param res - db connection resource - @param type - string , which hold type of database ( MySQL or Postgre ), optional, instead of short DB name, full name of DataWrapper-based class can be provided - @param item_type - name of class, which will be used for item rendering, optional, DataItem will be used by default - @param data_type - name of class which will be used for dataprocessor calls handling, optional, DataProcessor class will be used by default. - */ - public function __construct($res,$type=false,$item_type=false,$data_type=false,$render_type=false){ - if (!$item_type) $item_type="JSONSchedulerDataItem"; - if (!$data_type) $data_type="SchedulerDataProcessor"; - if (!$render_type) $render_type="JSONRenderStrategy"; - parent::__construct($res,$type,$item_type,$data_type,$render_type); - } - - protected function xml_start() { - return '{ "data":'; - } - - protected function xml_end() { - $this->fill_collections(); - $end = (!empty($this->extra_output)) ? ', "collections": {'.$this->extra_output.'}' : ''; - foreach ($this->attributes as $k => $v) - $end.=", \"".$k."\":\"".$v."\""; - $end .= '}'; - return $end; - } - - /*! assign options collection to the column - - @param name - name of the column - @param options - array or connector object - */ - public function set_options($name,$options){ - if (is_array($options)){ - $str=array(); - foreach($options as $k => $v) - $str[]='{"id":"'.$this->xmlentities($k).'", "value":"'.$this->xmlentities($v).'"}'; - $options=implode(",",$str); - } - $this->options[$name]=$options; - } - - - /*! generates xml description for options collections - - @param list - comma separated list of column names, for which options need to be generated - */ - protected function fill_collections($list=""){ - $options = array(); - foreach ($this->options as $k=>$v) { - $name = $k; - $option="\"{$name}\":["; - if (!is_string($this->options[$name])){ - $data = json_encode($this->options[$name]->render()); - $option.=substr($data,1,-1); - } else - $option.=$this->options[$name]; - $option.="]"; - $options[] = $option; - } - $this->extra_output .= implode($this->data_separator, $options); - } - - - /*! output fetched data as XML - @param res - DB resultset - */ - protected function output_as_xml($res){ - $result = $this->render_set($res); - if ($this->simple) return $result; - - $data=$this->xml_start().json_encode($result).$this->xml_end(); - - if ($this->as_string) return $data; - - $out = new OutputWriter($data, ""); - $out->set_type("json"); - $this->event->trigger("beforeOutput", $this, $out); - $out->output("", true, $this->encoding); - } -} -?>
\ No newline at end of file diff --git a/codebase/strategy.php b/codebase/strategy.php deleted file mode 100644 index 344dcf2..0000000 --- a/codebase/strategy.php +++ /dev/null @@ -1,508 +0,0 @@ -<?php - -class RenderStrategy { - - protected $conn = null; - - public function __construct($conn) { - $this->conn = $conn; - } - - /*! adds mix fields into DataConfig - * @param config - * DataConfig object - * @param mix - * mix structure - */ - protected function mix($config, $mix) { - for ($i = 0; $i < count($mix); $i++) { - if ($config->is_field($mix[$i]['name'])===-1) { - $config->add_field($mix[$i]['name']); - } - } - } - - /*! remove mix fields from DataConfig - * @param config - * DataConfig object - * @param mix - * mix structure - */ - protected function unmix($config, $mix) { - for ($i = 0; $i < count($mix); $i++) { - if ($config->is_field($mix[$i]['name'])!==-1) { - $config->remove_field_full($mix[$i]['name']); - } - } - } - - /*! adds mix fields in item - * simple mix adds only strings specified by user - * @param mix - * mix structure - * @param data - * array of selected data - */ - protected function simple_mix($mix, $data) { - // get mix details - for ($i = 0; $i < count($mix); $i++) - $data[$mix[$i]["name"]] = is_object($mix[$i]["value"]) ? "" : $mix[$i]["value"]; - return $data; - } - - /*! adds mix fields in item - * complex mix adds strings specified by user and results of subrequests - * @param mix - * mix structure - * @param data - * array of selected data - */ - protected function complex_mix($mix, $data) { - // get mix details - for ($i = 0; $i < count($mix); $i++) { - $mixname = $mix[$i]["name"]; - if ($mix[$i]['filter'] !== false) { - $subconn = $mix[$i]["value"]; - $filter = $mix[$i]["filter"]; - - // setting relationships - $subconn->clear_filter(); - foreach ($filter as $k => $v) - if (isset($data[$v])) - $subconn->filter($k, $data[$v], "="); - else - throw new Exception('There was no such data field registered as: '.$k); - - $subconn->asString(true); - $data[$mixname]=$subconn->simple_render(); - if (is_array($data[$mixname]) && count($data[$mixname]) == 1) - $data[$mixname] = $data[$mixname][0]; - } else { - $data[$mixname] = $mix[$i]["value"]; - } - } - return $data; - } - - /*! render from DB resultset - @param res - DB resultset - process commands, output requested data as XML - */ - public function render_set($res, $name, $dload, $sep, $config, $mix){ - $output=""; - $index=0; - $conn = $this->conn; - $this->mix($config, $mix); - $conn->event->trigger("beforeRenderSet",$conn,$res,$config); - while ($data=$conn->sql->get_next($res)){ - $data = $this->simple_mix($mix, $data); - - $data = new $name($data,$config,$index); - if ($data->get_id()===false) - $data->set_id($conn->uuid()); - $conn->event->trigger("beforeRender",$data); - $output.=$data->to_xml().$sep; - $index++; - } - $this->unmix($config, $mix); - return $output; - } - -} - -class JSONRenderStrategy extends RenderStrategy { - - /*! render from DB resultset - @param res - DB resultset - process commands, output requested data as json - */ - public function render_set($res, $name, $dload, $sep, $config, $mix){ - $output=array(); - $index=0; - $conn = $this->conn; - $this->mix($config, $mix); - $conn->event->trigger("beforeRenderSet",$conn,$res,$config); - while ($data=$conn->sql->get_next($res)){ - $data = $this->complex_mix($mix, $data); - $data = new $name($data,$config,$index); - if ($data->get_id()===false) - $data->set_id($conn->uuid()); - $conn->event->trigger("beforeRender",$data); - $item = $data->to_xml(); - if ($item !== false) - $output[]=$item; - $index++; - } - $this->unmix($config, $mix); - return $output; - } - -} - -class TreeRenderStrategy extends RenderStrategy { - - protected $id_swap = array(); - - public function __construct($conn) { - parent::__construct($conn); - $conn->event->attach("afterInsert",array($this,"parent_id_correction_a")); - $conn->event->attach("beforeProcessing",array($this,"parent_id_correction_b")); - } - - public function render_set($res, $name, $dload, $sep, $config, $mix){ - $output=""; - $index=0; - $conn = $this->conn; - $config_copy = new DataConfig($config); - $this->mix($config, $mix); - while ($data=$conn->sql->get_next($res)){ - $data = $this->simple_mix($mix, $data); - $data = new $name($data,$config,$index); - $conn->event->trigger("beforeRender",$data); - //there is no info about child elements, - //if we are using dyn. loading - assume that it has, - //in normal mode juse exec sub-render routine - if ($data->has_kids()===-1 && $dload) - $data->set_kids(true); - $output.=$data->to_xml_start(); - if ($data->has_kids()===-1 || ( $data->has_kids()==true && !$dload)){ - $sub_request = new DataRequestConfig($conn->get_request()); - //$sub_request->set_fieldset(implode(",",$config_copy->db_names_list($conn->sql))); - $sub_request->set_relation($data->get_id()); - $output.=$this->render_set($conn->sql->select($sub_request), $name, $dload, $sep, $config_copy, $mix); - } - $output.=$data->to_xml_end(); - $index++; - } - $this->unmix($config, $mix); - return $output; - } - - /*! store info about ID changes during insert operation - @param dataAction - data action object during insert operation - */ - public function parent_id_correction_a($dataAction){ - $this->id_swap[$dataAction->get_id()]=$dataAction->get_new_id(); - } - - /*! update ID if it was affected by previous operation - @param dataAction - data action object, before any processing operation - */ - public function parent_id_correction_b($dataAction){ - $relation = $this->conn->get_config()->relation_id["db_name"]; - $value = $dataAction->get_value($relation); - - if (array_key_exists($value,$this->id_swap)) - $dataAction->set_value($relation,$this->id_swap[$value]); - } -} - - - -class JSONTreeRenderStrategy extends TreeRenderStrategy { - - public function render_set($res, $name, $dload, $sep, $config,$mix){ - $output=array(); - $index=0; - $conn = $this->conn; - $config_copy = new DataConfig($config); - $this->mix($config, $mix); - while ($data=$conn->sql->get_next($res)){ - $data = $this->complex_mix($mix, $data); - $data = new $name($data,$config,$index); - $conn->event->trigger("beforeRender",$data); - //there is no info about child elements, - //if we are using dyn. loading - assume that it has, - //in normal mode just exec sub-render routine - if ($data->has_kids()===-1 && $dload) - $data->set_kids(true); - $record = $data->to_xml_start(); - if ($data->has_kids()===-1 || ( $data->has_kids()==true && !$dload)){ - $sub_request = new DataRequestConfig($conn->get_request()); - //$sub_request->set_fieldset(implode(",",$config_copy->db_names_list($conn->sql))); - $sub_request->set_relation($data->get_id()); - //$sub_request->set_filters(array()); - $temp = $this->render_set($conn->sql->select($sub_request), $name, $dload, $sep, $config_copy, $mix); - if (sizeof($temp)) - $record["data"] = $temp; - } - if ($record !== false) - $output[] = $record; - $index++; - } - $this->unmix($config, $mix); - return $output; - } - -} - - -class MultitableTreeRenderStrategy extends TreeRenderStrategy { - - private $level = 0; - private $max_level = null; - protected $sep = "-@level@-"; - - public function __construct($conn) { - parent::__construct($conn); - $conn->event->attach("beforeProcessing", Array($this, 'id_translate_before')); - $conn->event->attach("afterProcessing", Array($this, 'id_translate_after')); - } - - public function set_separator($sep) { - $this->sep = $sep; - } - - public function render_set($res, $name, $dload, $sep, $config, $mix){ - $output=""; - $index=0; - $conn = $this->conn; - $this->mix($config, $mix); - while ($data=$conn->sql->get_next($res)){ - $data = $this->simple_mix($mix, $data); - $data[$config->id['name']] = $this->level_id($data[$config->id['name']]); - $data = new $name($data,$config,$index); - $conn->event->trigger("beforeRender",$data); - if (($this->max_level !== null)&&($conn->get_level() == $this->max_level)) { - $data->set_kids(false); - } else { - if ($data->has_kids()===-1) - $data->set_kids(true); - } - $output.=$data->to_xml_start(); - $output.=$data->to_xml_end(); - $index++; - } - $this->unmix($config, $mix); - return $output; - } - - - public function level_id($id, $level = null) { - return ($level === null ? $this->level : $level).$this->sep.$id; - } - - - /*! remove level prefix from id, parent id and set new id before processing - @param action - DataAction object - */ - public function id_translate_before($action) { - $id = $action->get_id(); - $id = $this->parse_id($id, false); - $action->set_id($id); - $action->set_value('tr_id', $id); - $action->set_new_id($id); - $pid = $action->get_value($this->conn->get_config()->relation_id['db_name']); - $pid = $this->parse_id($pid, false); - $action->set_value($this->conn->get_config()->relation_id['db_name'], $pid); - } - - - /*! add level prefix in id and new id after processing - @param action - DataAction object - */ - public function id_translate_after($action) { - $id = $action->get_id(); - $action->set_id($this->level_id($id)); - $id = $action->get_new_id(); - $action->success($this->level_id($id)); - } - - - public function get_level($parent_name) { - if ($this->level) return $this->level; - if (!isset($_GET[$parent_name])) { - if (isset($_POST['ids'])) { - $ids = explode(",",$_POST["ids"]); - $id = $this->parse_id($ids[0]); - $this->level--; - } - $this->conn->get_request()->set_relation(false); - } else { - $id = $this->parse_id($_GET[$parent_name]); - $_GET[$parent_name] = $id; - } - return $this->level; - } - - - public function is_max_level() { - if (($this->max_level !== null) && ($this->level >= $this->max_level)) - return true; - return false; - } - public function set_max_level($max_level) { - $this->max_level = $max_level; - } - public function parse_id($id, $set_level = true) { - $parts = explode($this->sep, $id, 2); - if (count($parts) === 2) { - $level = $parts[0] + 1; - $id = $parts[1]; - } else { - $level = 0; - $id = ''; - } - if ($set_level) $this->level = $level; - return $id; - } - -} - - -class JSONMultitableTreeRenderStrategy extends MultitableTreeRenderStrategy { - - public function render_set($res, $name, $dload, $sep, $config, $mix){ - $output=array(); - $index=0; - $conn = $this->conn; - $this->mix($config, $mix); - while ($data=$conn->sql->get_next($res)){ - $data = $this->complex_mix($mix, $data); - $data[$config->id['name']] = $this->level_id($data[$config->id['name']]); - $data = new $name($data,$config,$index); - $conn->event->trigger("beforeRender",$data); - - if ($this->is_max_level()) { - $data->set_kids(false); - } else { - if ($data->has_kids()===-1) - $data->set_kids(true); - } - $record = $data->to_xml_start($output); - $output[] = $record; - $index++; - } - $this->unmix($config, $mix); - return $output; - } - -} - - -class GroupRenderStrategy extends RenderStrategy { - - protected $id_postfix = '__{group_param}'; - - public function __construct($conn) { - parent::__construct($conn); - $conn->event->attach("beforeProcessing", Array($this, 'check_id')); - $conn->event->attach("onInit", Array($this, 'replace_postfix')); - } - - public function render_set($res, $name, $dload, $sep, $config, $mix, $usemix = false){ - $output=""; - $index=0; - $conn = $this->conn; - if ($usemix) $this->mix($config, $mix); - while ($data=$conn->sql->get_next($res)){ - if (isset($data[$config->id['name']])) { - $this->simple_mix($mix, $data); - $has_kids = false; - } else { - $data[$config->id['name']] = $data['value'].$this->id_postfix; - $data[$config->text[0]['name']] = $data['value']; - $has_kids = true; - } - $data = new $name($data,$config,$index); - $conn->event->trigger("beforeRender",$data); - if ($has_kids === false) { - $data->set_kids(false); - } - - if ($data->has_kids()===-1 && $dload) - $data->set_kids(true); - $output.=$data->to_xml_start(); - if (($data->has_kids()===-1 || ( $data->has_kids()==true && !$dload))&&($has_kids == true)){ - $sub_request = new DataRequestConfig($conn->get_request()); - $sub_request->set_relation(str_replace($this->id_postfix, "", $data->get_id())); - $output.=$this->render_set($conn->sql->select($sub_request), $name, $dload, $sep, $config, $mix, true); - } - $output.=$data->to_xml_end(); - $index++; - } - if ($usemix) $this->unmix($config, $mix); - return $output; - } - - public function check_id($action) { - if (isset($_GET['editing'])) { - $config = $this->conn->get_config(); - $id = $action->get_id(); - $pid = $action->get_value($config->relation_id['name']); - $pid = str_replace($this->id_postfix, "", $pid); - $action->set_value($config->relation_id['name'], $pid); - if (!empty($pid)) { - return $action; - } else { - $action->error(); - $action->set_response_text("This record can't be updated!"); - return $action; - } - } else { - return $action; - } - } - - public function replace_postfix() { - if (isset($_GET['id'])) { - $_GET['id'] = str_replace($this->id_postfix, "", $_GET['id']); - } - } - - public function get_postfix() { - return $this->id_postfix; - } - -} - - -class JSONGroupRenderStrategy extends GroupRenderStrategy { - - public function render_set($res, $name, $dload, $sep, $config, $mix, $usemix = false){ - $output=array(); - $index=0; - $conn = $this->conn; - if ($usemix) $this->mix($config, $mix); - while ($data=$conn->sql->get_next($res)){ - if (isset($data[$config->id['name']])) { - $data = $this->complex_mix($mix, $data); - $has_kids = false; - } else { - $data[$config->id['name']] = $data['value'].$this->id_postfix; - $data[$config->text[0]['name']] = $data['value']; - $has_kids = true; - } - $data = new $name($data,$config,$index); - $conn->event->trigger("beforeRender",$data); - if ($has_kids === false) { - $data->set_kids(false); - } - - if ($data->has_kids()===-1 && $dload) - $data->set_kids(true); - $record = $data->to_xml_start(); - if (($data->has_kids()===-1 || ( $data->has_kids()==true && !$dload))&&($has_kids == true)){ - $sub_request = new DataRequestConfig($conn->get_request()); - $sub_request->set_relation(str_replace($this->id_postfix, "", $data->get_id())); - $temp = $this->render_set($conn->sql->select($sub_request), $name, $dload, $sep, $config, $mix, true); - if (sizeof($temp)) - $record["data"] = $temp; - } - $output[] = $record; - $index++; - } - if ($usemix) $this->unmix($config, $mix); - return $output; - } - -} - - -?>
\ No newline at end of file diff --git a/codebase/tools.php b/codebase/tools.php deleted file mode 100644 index 5017a72..0000000 --- a/codebase/tools.php +++ /dev/null @@ -1,267 +0,0 @@ -<?php
-/*
- @author dhtmlx.com
- @license GPL, see license.txt
-*/
-
-/*! Class which allows to assign|fire events.
-*/
-class EventMaster{
- private $events;//!< hash of event handlers
- private $master;
- private static $eventsStatic=array();
-
- /*! constructor
- */
- function __construct(){
- $this->events=array();
- $this->master = false;
- }
- /*! Method check if event with such name already exists.
- @param name
- name of event, case non-sensitive
- @return
- true if event with such name registered, false otherwise
- */
- public function exist($name){
- $name=strtolower($name);
- return (isset($this->events[$name]) && sizeof($this->events[$name]));
- }
- /*! Attach custom code to event.
-
- Only on event handler can be attached in the same time. If new event handler attached - old will be detached.
-
- @param name
- name of event, case non-sensitive
- @param method
- function which will be attached. You can use array(class, method) if you want to attach the method of the class.
- */
- public function attach($name,$method=false){
- //use class for event handling
- if ($method === false){
- $this->master = $name;
- return;
- }
- //use separate functions
- $name=strtolower($name);
- if (!array_key_exists($name,$this->events))
- $this->events[$name]=array();
- $this->events[$name][]=$method;
- }
-
- public static function attach_static($name, $method){
- $name=strtolower($name);
- if (!array_key_exists($name,EventMaster::$eventsStatic))
- EventMaster::$eventsStatic[$name]=array();
- EventMaster::$eventsStatic[$name][]=$method;
- }
-
- public static function trigger_static($name, $method){
- $arg_list = func_get_args();
- $name=strtolower(array_shift($arg_list));
-
- if (isset(EventMaster::$eventsStatic[$name]))
- foreach(EventMaster::$eventsStatic[$name] as $method){
- if (is_array($method) && !method_exists($method[0],$method[1]))
- throw new Exception("Incorrect method assigned to event: ".$method[0].":".$method[1]);
- if (!is_array($method) && !function_exists($method))
- throw new Exception("Incorrect function assigned to event: ".$method);
- call_user_func_array($method, $arg_list);
- }
- return true;
- }
-
- /*! Detach code from event
- @param name
- name of event, case non-sensitive
- */
- public function detach($name){
- $name=strtolower($name);
- unset($this->events[$name]);
- }
- /*! Trigger event.
- @param name
- name of event, case non-sensitive
- @param data
- value which will be provided as argument for event function,
- you can provide multiple data arguments, method accepts variable number of parameters
- @return
- true if event handler was not assigned , result of event hangler otherwise
- */
- public function trigger($name,$data){
- $arg_list = func_get_args();
- $name=strtolower(array_shift($arg_list));
-
- if (isset($this->events[$name]))
- foreach($this->events[$name] as $method){
- if (is_array($method) && !method_exists($method[0],$method[1]))
- throw new Exception("Incorrect method assigned to event: ".$method[0].":".$method[1]);
- if (!is_array($method) && !function_exists($method))
- throw new Exception("Incorrect function assigned to event: ".$method);
- call_user_func_array($method, $arg_list);
- }
-
- if ($this->master !== false)
- if (method_exists($this->master, $name))
- call_user_func_array(array($this->master, $name), $arg_list);
-
- return true;
- }
-}
-
-/*! Class which handles access rules.
-**/
-class AccessMaster{
- private $rules,$local;
- /*! constructor
-
- Set next access right to "allowed" by default : read, insert, update, delete
- Basically - all common data operations allowed by default
- */
- function __construct(){
- $this->rules=array("read" => true, "insert" => true, "update" => true, "delete" => true);
- $this->local=true;
- }
- /*! change access rule to "allow"
- @param name
- name of access right
- */
- public function allow($name){
- $this->rules[$name]=true;
- }
- /*! change access rule to "deny"
-
- @param name
- name of access right
- */
- public function deny($name){
- $this->rules[$name]=false;
- }
-
- /*! change all access rules to "deny"
- */
- public function deny_all(){
- $this->rules=array();
- }
-
- /*! check access rule
-
- @param name
- name of access right
- @return
- true if access rule allowed, false otherwise
- */
- public function check($name){
- if ($this->local){
- /*!
- todo
- add referrer check, to prevent access from remote points
- */
- }
- if (!isset($this->rules[$name]) || !$this->rules[$name]){
- return false;
- }
- return true;
- }
-}
-
-/*! Controls error and debug logging.
- Class designed to be used as static object.
-**/
-class LogMaster{
- private static $_log=false;//!< logging mode flag
- private static $_output=false;//!< output error infor to client flag
- private static $session="";//!< all messages generated for current request
-
- /*! convert array to string representation ( it is a bit more readable than var_dump )
-
- @param data
- data object
- @param pref
- prefix string, used for formating, optional
- @return
- string with array description
- */
- private static function log_details($data,$pref=""){
- if (is_array($data)){
- $str=array("");
- foreach($data as $k=>$v)
- array_push($str,$pref.$k." => ".LogMaster::log_details($v,$pref."\t"));
- return implode("\n",$str);
- }
- return $data;
- }
- /*! put record in log
-
- @param str
- string with log info, optional
- @param data
- data object, which will be added to log, optional
- */
- public static function log($str="",$data=""){
- if (LogMaster::$_log){
- $message = $str.LogMaster::log_details($data)."\n\n";
- LogMaster::$session.=$message;
- error_log($message,3,LogMaster::$_log);
- }
- }
-
- /*! get logs for current request
- @return
- string, which contains all log messages generated for current request
- */
- public static function get_session_log(){
- return LogMaster::$session;
- }
-
- /*! error handler, put normal php errors in log file
-
- @param errn
- error number
- @param errstr
- error description
- @param file
- error file
- @param line
- error line
- @param context
- error cntext
- */
- public static function error_log($errn,$errstr,$file,$line,$context){
- LogMaster::log($errstr." at ".$file." line ".$line);
- }
-
- /*! exception handler, used as default reaction on any error - show execution log and stop processing
-
- @param exception
- instance of Exception
- */
- public static function exception_log($exception){
- LogMaster::log("!!!Uncaught Exception\nCode: " . $exception->getCode() . "\nMessage: " . $exception->getMessage());
- if (LogMaster::$_output){
- echo "<pre><xmp>\n";
- echo LogMaster::get_session_log();
- echo "\n</xmp></pre>";
- }
- die();
- }
-
- /*! enable logging
-
- @param name
- path to the log file, if boolean false provided as value - logging will be disabled
- @param output
- flag of client side output, if enabled - session log will be sent to client side in case of an error.
- */
- public static function enable_log($name,$output=false){
- LogMaster::$_log=$name;
- LogMaster::$_output=$output;
- if ($name){
- set_error_handler(array("LogMaster","error_log"),E_ALL);
- set_exception_handler(array("LogMaster","exception_log"));
- LogMaster::log("\n\n====================================\nLog started, ".date("d/m/Y h:i:s")."\n====================================");
- }
- }
-}
-
-?>
\ No newline at end of file diff --git a/codebase/tree_connector.php b/codebase/tree_connector.php deleted file mode 100644 index 63d4442..0000000 --- a/codebase/tree_connector.php +++ /dev/null @@ -1,231 +0,0 @@ -<?php
-/*
- @author dhtmlx.com
- @license GPL, see license.txt
-*/
-require_once("base_connector.php");
-
-/*! DataItem class for Tree component
-**/
-
-class TreeDataItem extends DataItem{
- private $im0;//!< image of closed folder
- private $im1;//!< image of opened folder
- private $im2;//!< image of leaf item
- private $check;//!< checked state
- private $kids=-1;//!< checked state
- private $attrs;//!< collection of custom attributes
-
- function __construct($data,$config,$index){
- parent::__construct($data,$config,$index);
-
- $this->im0=false;
- $this->im1=false;
- $this->im2=false;
- $this->check=false;
- $this->attrs = array();
- }
- /*! get id of parent record
-
- @return
- id of parent record
- */
- function get_parent_id(){
- return $this->data[$this->config->relation_id["name"]];
- }
- /*! get state of items checkbox
-
- @return
- state of item's checkbox as int value, false if state was not defined
- */
- function get_check_state(){
- return $this->check;
- }
- /*! set state of item's checkbox
-
- @param value
- int value, 1 - checked, 0 - unchecked, -1 - third state
- */
- function set_check_state($value){
- $this->check=$value;
- }
-
- /*! return count of child items
- -1 if there is no info about childs
- @return
- count of child items
- */
- function has_kids(){
- return $this->kids;
- }
- /*! sets count of child items
- @param value
- count of child items
- */
- function set_kids($value){
- $this->kids=$value;
- }
-
- /*! set custom attribute
-
- @param name
- name of the attribute
- @param value
- new value of the attribute
- */
- function set_attribute($name, $value){
- switch($name){
- case "id":
- $this->set_id($value);
- break;
- case "text":
- $this->data[$this->config->text[0]["name"]]=$value;
- break;
- case "checked":
- $this->set_check_state($value);
- break;
- case "im0":
- $this->im0=$value;
- break;
- case "im1":
- $this->im1=$value;
- break;
- case "im2":
- $this->im2=$value;
- break;
- case "child":
- $this->set_kids($value);
- break;
- default:
- $this->attrs[$name]=$value;
- }
- }
-
-
- /*! assign image for tree's item
-
- @param img_folder_closed
- image for item, which represents folder in closed state
- @param img_folder_open
- image for item, which represents folder in opened state, optional
- @param img_leaf
- image for item, which represents leaf item, optional
- */
- function set_image($img_folder_closed,$img_folder_open=false,$img_leaf=false){
- $this->im0=$img_folder_closed;
- $this->im1=$img_folder_open?$img_folder_open:$img_folder_closed;
- $this->im2=$img_leaf?$img_leaf:$img_folder_closed;
- }
- /*! return self as XML string, starting part
- */
- function to_xml_start(){
- if ($this->skip) return "";
-
- $str1="<item id='".$this->xmlentities($this->get_id())."' text='".$this->xmlentities($this->data[$this->config->text[0]["name"]])."' ";
- if ($this->has_kids()==true) $str1.="child='".$this->has_kids()."' ";
- if ($this->im0) $str1.="im0='".$this->im0."' ";
- if ($this->im1) $str1.="im1='".$this->im1."' ";
- if ($this->im2) $str1.="im2='".$this->im2."' ";
- if ($this->check) $str1.="checked='".$this->check."' ";
- foreach ($this->attrs as $key => $value)
- $str1.=$key."='".$this->xmlentities($value)."' ";
- $str1.=">";
- if ($this->userdata !== false)
- foreach ($this->userdata as $key => $value)
- $str1.="<userdata name='".$key."'><![CDATA[".$value."]]></userdata>";
-
- return $str1;
- }
- /*! return self as XML string, ending part
- */
- function to_xml_end(){
- if ($this->skip) return "";
- return "</item>";
- }
-
-}
-
-require_once("filesystem_item.php");
-
-/*! Connector for the dhtmlxtree
-**/
-class TreeConnector extends Connector{
- protected $parent_name = 'id';
- public $rootId = "0";
-
- /*! constructor
-
- Here initilization of all Masters occurs, execution timer initialized
- @param res
- db connection resource
- @param type
- string , which hold type of database ( MySQL or Postgre ), optional, instead of short DB name, full name of DataWrapper-based class can be provided
- @param item_type
- name of class, which will be used for item rendering, optional, DataItem will be used by default
- @param data_type
- name of class which will be used for dataprocessor calls handling, optional, DataProcessor class will be used by default.
- * @param render_type
- * name of class which will provides data rendering
- */
- public function __construct($res,$type=false,$item_type=false,$data_type=false, $render_type=false){
- if (!$item_type) $item_type="TreeDataItem";
- if (!$data_type) $data_type="TreeDataProcessor";
- if (!$render_type) $render_type="TreeRenderStrategy";
- parent::__construct($res,$type,$item_type,$data_type,$render_type);
- }
-
- //parse GET scoope, all operations with incoming request must be done here
- public function parse_request(){
- parent::parse_request();
-
- if (isset($_GET[$this->parent_name]))
- $this->request->set_relation($_GET[$this->parent_name]);
- else
- $this->request->set_relation($this->rootId);
-
- $this->request->set_limit(0,0); //netralize default reaction on dyn. loading mode
- }
-
- /*! renders self as xml, starting part
- */
- public function xml_start(){
- $attributes = "";
- foreach($this->attributes as $k=>$v)
- $attributes .= " ".$k."='".$v."'";
-
- return "<tree id='".$this->request->get_relation()."'".$attributes.">";
- }
-
- /*! renders self as xml, ending part
- */
- public function xml_end(){
- $this->fill_collections();
- return $this->extra_output."</tree>";
- }
-}
-
-
-class TreeDataProcessor extends DataProcessor{
-
- function __construct($connector,$config,$request){
- parent::__construct($connector,$config,$request);
- $request->set_relation(false);
- }
-
- /*! convert incoming data name to valid db name
- converts c0..cN to valid field names
- @param data
- data name from incoming request
- @return
- related db_name
- */
- function name_data($data){
- if ($data=="tr_pid")
- return $this->config->relation_id["db_name"];
- if ($data=="tr_text")
- return $this->config->text[0]["db_name"];
- return $data;
- }
-}
-
-?>
\ No newline at end of file diff --git a/codebase/treedatagroup_connector.php b/codebase/treedatagroup_connector.php deleted file mode 100644 index 336915a..0000000 --- a/codebase/treedatagroup_connector.php +++ /dev/null @@ -1,89 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("data_connector.php"); - -class TreeDataGroupConnector extends TreeDataConnector{ - - public function __construct($res,$type=false,$item_type=false,$data_type=false,$render_type=false){ - if (!$render_type) $render_type="GroupRenderStrategy"; - parent::__construct($res,$type,$item_type,$data_type,$render_type); - } - - /*! if not isset $_GET[id] then it's top level - */ - protected function set_relation() { - if (!isset($_GET[$this->parent_name])) $this->request->set_relation(false); - } - - /*! if it's first level then distinct level - * else select by parent - */ - protected function get_resource() { - $resource = null; - if (isset($_GET[$this->parent_name])) - $resource = $this->sql->select($this->request); - else - $resource = $this->sql->get_variants($this->config->relation_id['name'], $this->request); - return $resource; - } - - - /*! renders self as xml, starting part - */ - public function xml_start(){ - if (isset($_GET[$this->parent_name])) { - return "<data parent='".$_GET[$this->parent_name].$this->render->get_postfix()."'>"; - } else { - return "<data parent='0'>"; - } - } - -} - - - - -class JSONTreeDataGroupConnector extends JSONTreeDataConnector{ - - public function __construct($res,$type=false,$item_type=false,$data_type=false,$render_type=false){ - if (!$render_type) $render_type="JSONGroupRenderStrategy"; - parent::__construct($res,$type,$item_type,$data_type,$render_type); - } - - /*! if not isset $_GET[id] then it's top level - */ - protected function set_relation() { - if (!isset($_GET[$this->parent_name])) $this->request->set_relation(false); - } - - /*! if it's first level then distinct level - * else select by parent - */ - protected function get_resource() { - $resource = null; - if (isset($_GET[$this->parent_name])) - $resource = $this->sql->select($this->request); - else - $resource = $this->sql->get_variants($this->config->relation_id['name'], $this->request); - return $resource; - } - - - /*! renders self as xml, starting part - */ - public function xml_start(){ - if (isset($_GET[$this->parent_name])) { - return "<data parent='".$_GET[$this->parent_name].$this->render->get_postfix()."'>"; - } else { - return "<data parent='0'>"; - } - } - -} - - - -?>
\ No newline at end of file diff --git a/codebase/treedatamultitable_connector.php b/codebase/treedatamultitable_connector.php deleted file mode 100644 index 104770e..0000000 --- a/codebase/treedatamultitable_connector.php +++ /dev/null @@ -1,91 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("data_connector.php"); - -class TreeDataMultitableConnector extends TreeDataConnector{ - - protected $parent_name = 'parent'; - - public function __construct($res,$type=false,$item_type=false,$data_type=false,$render_type=false){ - if (!$data_type) $data_type="TreeDataProcessor"; - if (!$render_type) $render_type="MultitableTreeRenderStrategy"; - parent::__construct($res,$type,$item_type,$data_type,$render_type); - } - - public function render(){ - $this->dload = true; - return parent::render(); - } - - /*! sets relation for rendering */ - protected function set_relation() { - if (!isset($_GET[$this->parent_name])) - $this->request->set_relation(false); - } - - public function xml_start(){ - if (isset($_GET[$this->parent_name])) { - return "<data parent='".$this->xmlentities($this->render->level_id($_GET[$this->parent_name], $this->render->get_level() - 1))."'>"; - } else { - return "<data parent='0'>"; - } - } - - /*! set maximum level of tree - @param max_level - maximum level - */ - public function setMaxLevel($max_level) { - $this->render->set_max_level($max_level); - } - - public function get_level() { - return $this->render->get_level($this->parent_name); - } - -} - - - - - - -class JSONTreeDataMultitableConnector extends TreeDataMultitableConnector{ - - public function __construct($res,$type=false,$item_type=false,$data_type=false,$render_type=false){ - if (!$item_type) $item_type="JSONTreeCommonDataItem"; - if (!$data_type) $data_type="CommonDataProcessor"; - if (!$render_type) $render_type="JSONMultitableTreeRenderStrategy"; - parent::__construct($res,$type,$item_type,$data_type,$render_type); - } - - protected function output_as_xml($res){ - $result = $this->render_set($res); - if ($this->simple) return $result; - - $data = array(); - if (isset($_GET['parent'])) - $data["parent"] = $this->render->level_id($_GET[$this->parent_name], $this->render->get_level() - 1); - else - $data["parent"] = "0"; - $data["data"] = $result; - - $result = json_encode($data); - if ($this->as_string) return $result; - - $out = new OutputWriter($result, ""); - $out->set_type("json"); - $this->event->trigger("beforeOutput", $this, $out); - $out->output("", true, $this->encoding); - } - - public function xml_start(){ - return ''; - } -} - - -?>
\ No newline at end of file diff --git a/codebase/treegrid_connector.php b/codebase/treegrid_connector.php deleted file mode 100644 index 1f89137..0000000 --- a/codebase/treegrid_connector.php +++ /dev/null @@ -1,121 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("grid_connector.php"); - -/*! DataItem class for TreeGrid component -**/ -class TreeGridDataItem extends GridDataItem{ - private $kids=-1;//!< checked state - - function __construct($data,$config,$index){ - parent::__construct($data,$config,$index); - $this->im0=false; - } - /*! return id of parent record - - @return - id of parent record - */ - function get_parent_id(){ - return $this->data[$this->config->relation_id["name"]]; - } - /*! assign image to treegrid's item - longer description - @param img - relative path to the image - */ - function set_image($img){ - $this->set_cell_attribute($this->config->text[0]["name"],"image",$img); - } - - /*! return count of child items - -1 if there is no info about childs - @return - count of child items - */ - function has_kids(){ - return $this->kids; - } - /*! sets count of child items - @param value - count of child items - */ - function set_kids($value){ - $this->kids=$value; - if ($value) - $this->set_row_attribute("xmlkids",$value); - } -} -/*! Connector for dhtmlxTreeGrid -**/ -class TreeGridConnector extends GridConnector{ - protected $parent_name = 'id'; - protected $rootId = "0"; - - /*! constructor - - Here initilization of all Masters occurs, execution timer initialized - @param res - db connection resource - @param type - string , which hold type of database ( MySQL or Postgre ), optional, instead of short DB name, full name of DataWrapper-based class can be provided - @param item_type - name of class, which will be used for item rendering, optional, DataItem will be used by default - @param data_type - name of class which will be used for dataprocessor calls handling, optional, DataProcessor class will be used by default. - * @param render_type - * name of class which will provides data rendering - */ - public function __construct($res,$type=false,$item_type=false,$data_type=false,$render_type=false){ - if (!$item_type) $item_type="TreeGridDataItem"; - if (!$data_type) $data_type="TreeGridDataProcessor"; - if (!$render_type) $render_type="TreeRenderStrategy"; - parent::__construct($res,$type,$item_type,$data_type,$render_type); - } - - /*! process treegrid specific options in incoming request */ - public function parse_request(){ - parent::parse_request(); - - if (isset($_GET[$this->parent_name])) - $this->request->set_relation($_GET[$this->parent_name]); - else - $this->request->set_relation($this->rootId); - - $this->request->set_limit(0,0); //netralize default reaction on dyn. loading mode - } - - /*! renders self as xml, starting part - */ - protected function xml_start(){ - return "<rows parent='".$this->xmlentities( $this->request->get_relation() )."'>"; - } -} - -/*! DataProcessor class for Grid component -**/ -class TreeGridDataProcessor extends GridDataProcessor{ - - function __construct($connector,$config,$request){ - parent::__construct($connector,$config,$request); - $request->set_relation(false); - } - - /*! convert incoming data name to valid db name - converts c0..cN to valid field names - @param data - data name from incoming request - @return - related db_name - */ - function name_data($data){ - - if ($data=="gr_pid") - return $this->config->relation_id["name"]; - else return parent::name_data($data); - } -} -?>
\ No newline at end of file diff --git a/codebase/treegridgroup_connector.php b/codebase/treegridgroup_connector.php deleted file mode 100644 index cd8fdf2..0000000 --- a/codebase/treegridgroup_connector.php +++ /dev/null @@ -1,46 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("treegrid_connector.php"); - -class TreeGridGroupConnector extends TreeGridConnector{ - - public function __construct($res,$type=false,$item_type=false,$data_type=false,$render_type=false){ - if (!$render_type) $render_type="GroupRenderStrategy"; - parent::__construct($res,$type,$item_type,$data_type,$render_type); - } - - /*! if not isset $_GET[id] then it's top level - */ - protected function set_relation() { - if (!isset($_GET[$this->parent_name])) $this->request->set_relation(false); - } - - /*! if it's first level then distinct level - * else select by parent - */ - protected function get_resource() { - $resource = null; - if (isset($_GET[$this->parent_name])) - $resource = $this->sql->select($this->request); - else - $resource = $this->sql->get_variants($this->config->relation_id['name'], $this->request); - return $resource; - } - - - /*! renders self as xml, starting part - */ - protected function xml_start(){ - if (isset($_GET[$this->parent_name])) { - return "<rows parent='".$_GET[$this->parent_name].$this->render->get_postfix()."'>"; - } else { - return "<rows parent='0'>"; - } - } - -} - -?>
\ No newline at end of file diff --git a/codebase/treegridmultitable_connector.php b/codebase/treegridmultitable_connector.php deleted file mode 100644 index 31217f9..0000000 --- a/codebase/treegridmultitable_connector.php +++ /dev/null @@ -1,69 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("treegrid_connector.php"); - -class TreeGridMultitableConnector extends TreeGridConnector{ - - public function __construct($res,$type=false,$item_type=false,$data_type=false,$render_type=false){ - $data_type="TreeGridMultitableDataProcessor"; - if (!$render_type) $render_type="MultitableTreeRenderStrategy"; - parent::__construct($res,$type,$item_type,$data_type,$render_type); - } - - public function render(){ - $this->dload = true; - return parent::render(); - } - - /*! sets relation for rendering */ - protected function set_relation() { - if (!isset($_GET['id'])) - $this->request->set_relation(false); - } - - public function xml_start(){ - if (isset($_GET['id'])) { - return "<rows parent='".$this->xmlentities($this->render->level_id($_GET['id'], $this->get_level() - 1))."'>"; - } else { - return "<rows parent='0'>"; - } - } - - /*! set maximum level of tree - @param max_level - maximum level - */ - public function setMaxLevel($max_level) { - $this->render->set_max_level($max_level); - } - - public function get_level() { - return $this->render->get_level($this->parent_name); - } - - -} - - -class TreeGridMultitableDataProcessor extends DataProcessor { - - function name_data($data){ - if ($data=="gr_pid") - return $this->config->relation_id["name"]; - if ($data=="gr_id") - return $this->config->id["name"]; - preg_match('/^c([%\d]+)$/', $data, $data_num); - if (!isset($data_num[1])) return $data; - $data_num = $data_num[1]; - if (isset($this->config->data[$data_num]["db_name"])) { - return $this->config->data[$data_num]["db_name"]; - } - return $data; - } - -} - -?>
\ No newline at end of file diff --git a/codebase/treegroup_connector.php b/codebase/treegroup_connector.php deleted file mode 100644 index 5266d0b..0000000 --- a/codebase/treegroup_connector.php +++ /dev/null @@ -1,46 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("tree_connector.php"); - -class TreeGroupConnector extends TreeConnector{ - - public function __construct($res,$type=false,$item_type=false,$data_type=false,$render_type=false){ - if (!$render_type) $render_type="GroupRenderStrategy"; - parent::__construct($res,$type,$item_type,$data_type,$render_type); - } - - /*! if not isset $_GET[id] then it's top level - */ - protected function set_relation() { - if (!isset($_GET[$this->parent_name])) $this->request->set_relation(false); - } - - /*! if it's first level then distinct level - * else select by parent - */ - protected function get_resource() { - $resource = null; - if (isset($_GET[$this->parent_name])) - $resource = $this->sql->select($this->request); - else - $resource = $this->sql->get_variants($this->config->relation_id['name'], $this->request); - return $resource; - } - - - /*! renders self as xml, starting part - */ - public function xml_start(){ - if (isset($_GET[$this->parent_name])) { - return "<tree id='".$_GET[$this->parent_name].$this->render->get_postfix()."'>"; - } else { - return "<tree id='0'>"; - } - } - -} - -?>
\ No newline at end of file diff --git a/codebase/treemultitable_connector.php b/codebase/treemultitable_connector.php deleted file mode 100644 index b06164c..0000000 --- a/codebase/treemultitable_connector.php +++ /dev/null @@ -1,51 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ -require_once("tree_connector.php"); - -class TreeMultitableConnector extends TreeConnector{ - - protected $parent_name = 'id'; - - public function __construct($res,$type=false,$item_type=false,$data_type=false,$render_type=false){ - if (!$data_type) $data_type="TreeDataProcessor"; - if (!$render_type) $render_type="MultitableTreeRenderStrategy"; - parent::__construct($res,$type,$item_type,$data_type,$render_type); - } - - public function render(){ - $this->dload = true; - return parent::render(); - } - - /*! sets relation for rendering */ - protected function set_relation() { - if (!isset($_GET[$this->parent_name])) - $this->request->set_relation(false); - } - - public function xml_start(){ - if (isset($_GET[$this->parent_name])) { - return "<tree id='".$this->xmlentities($this->render->level_id($_GET[$this->parent_name], $this->get_level() - 1))."'>"; - } else { - return "<tree id='0'>"; - } - } - - /*! set maximum level of tree - @param max_level - maximum level - */ - public function setMaxLevel($max_level) { - $this->render->set_max_level($max_level); - } - - public function get_level() { - return $this->render->get_level($this->parent_name); - } - -} - -?>
\ No newline at end of file diff --git a/codebase/update.php b/codebase/update.php deleted file mode 100644 index dacc211..0000000 --- a/codebase/update.php +++ /dev/null @@ -1,266 +0,0 @@ -<?php -/* - @author dhtmlx.com - @license GPL, see license.txt -*/ - -/*! DataItemUpdate class for realization Optimistic concurrency control - Wrapper for DataItem object - It's used during outputing updates instead of DataItem object - Create wrapper for every data item with update information. -*/ -class DataItemUpdate extends DataItem { - - - /*! constructor - @param data - hash of data - @param config - DataConfig object - @param index - index of element - */ - public function __construct($data,$config,$index,$type){ - $this->config=$config; - $this->data=$data; - $this->index=$index; - $this->skip=false; - $this->child = new $type($data, $config, $index); - } - - /*! returns parent_id (for Tree and TreeGrid components) - */ - public function get_parent_id(){ - if (method_exists($this->child, 'get_parent_id')) { - return $this->child->get_parent_id(); - } else { - return ''; - } - } - - - /*! generate XML on the data hash base - */ - public function to_xml(){ - $str= "<update "; - $str .= 'status="'.$this->data['type'].'" '; - $str .= 'id="'.$this->data['dataId'].'" '; - $str .= 'parent="'.$this->get_parent_id().'"'; - $str .= '>'; - $str .= $this->child->to_xml(); - $str .= '</update>'; - return $str; - } - - /*! return starting tag for XML string - */ - public function to_xml_start(){ - $str="<update "; - $str .= 'status="'.$this->data['type'].'" '; - $str .= 'id="'.$this->data['dataId'].'" '; - $str .= 'parent="'.$this->get_parent_id().'"'; - $str .= '>'; - $str .= $this->child->to_xml_start(); - return $str; - } - - /*! return ending tag for XML string - */ - public function to_xml_end(){ - $str = $this->child->to_xml_end(); - $str .= '</update>'; - return $str; - } - - /*! returns false for outputing only current item without child items - */ - public function has_kids(){ - return false; - } - - /*! sets count of child items - @param value - count of child items - */ - public function set_kids($value){ - if (method_exists($this->child, 'set_kids')) { - $this->child->set_kids($value); - } - } - - /*! sets attribute for item - */ - public function set_attribute($name, $value){ - if (method_exists($this->child, 'set_attribute')) { - LogMaster::log("setting attribute: \nname = {$name}\nvalue = {$value}"); - $this->child->set_attribute($name, $value); - } else { - LogMaster::log("set_attribute method doesn't exists"); - } - } -} - - -class DataUpdate{ - - protected $table; //!< table , where actions are stored - protected $url; //!< url for notification service, optional - protected $sql; //!< DB wrapper object - protected $config; //!< DBConfig object - protected $request; //!< DBRequestConfig object - protected $event; - protected $item_class; - protected $demu; - - //protected $config;//!< DataConfig instance - //protected $request;//!< DataRequestConfig instance - - /*! constructor - - @param connector - Connector object - @param config - DataConfig object - @param request - DataRequestConfig object - */ - function __construct($sql, $config, $request, $table, $url){ - $this->config= $config; - $this->request= $request; - $this->sql = $sql; - $this->table=$table; - $this->url=$url; - $this->demu = false; - } - - public function set_demultiplexor($path){ - $this->demu = $path; - } - - public function set_event($master, $name){ - $this->event = $master; - $this->item_class = $name; - } - - private function select_update($actions_table, $join_table, $id_field_name, $version, $user) { - $sql = "SELECT * FROM {$actions_table}"; - $sql .= " LEFT OUTER JOIN {$join_table} ON "; - $sql .= "{$actions_table}.DATAID = {$join_table}.{$id_field_name} "; - $sql .= "WHERE {$actions_table}.ID > '{$version}' AND {$actions_table}.USER <> '{$user}'"; - return $sql; - } - - private function get_update_max_version() { - $sql = "SELECT MAX(id) as VERSION FROM {$this->table}"; - $res = $this->sql->query($sql); - $data = $this->sql->get_next($res); - - if ($data == false || $data['VERSION'] == false) - return 1; - else - return $data['VERSION']; - } - - private function log_update_action($actions_table, $dataId, $status, $user) { - $sql = "INSERT INTO {$actions_table} (DATAID, TYPE, USER) VALUES ('{$dataId}', '{$status}', '{$user}')"; - $this->sql->query($sql); - if ($this->demu) - file_get_contents($this->demu); - } - - - - - /*! records operations in actions_table - @param action - DataAction object - */ - public function log_operations($action) { - $type = $this->sql->escape($action->get_status()); - $dataId = $this->sql->escape($action->get_new_id()); - $user = $this->sql->escape($this->request->get_user()); - if ($type!="error" && $type!="invalid" && $type !="collision") { - $this->log_update_action($this->table, $dataId, $type, $user); - } - } - - - /*! return action version in XMl format - */ - public function get_version() { - $version = $this->get_update_max_version(); - return "<userdata name='version'>".$version."</userdata>"; - } - - - /*! adds action version in output XML as userdata - */ - public function version_output($conn, $out) { - $out->add($this->get_version()); - } - - - /*! create update actions in XML-format and sends it to output - */ - public function get_updates() { - $sub_request = new DataRequestConfig($this->request); - $version = $this->request->get_version(); - $user = $this->request->get_user(); - - $sub_request->parse_sql($this->select_update($this->table, $this->request->get_source(), $this->config->id['db_name'], $version, $user)); - $sub_request->set_relation(false); - - $output = $this->render_set($this->sql->select($sub_request), $this->item_class); - - ob_clean(); - header("Content-type:text/xml"); - - echo $this->updates_start(); - echo $this->get_version(); - echo $output; - echo $this->updates_end(); - } - - - protected function render_set($res, $name){ - $output=""; - $index=0; - while ($data=$this->sql->get_next($res)){ - $data = new DataItemUpdate($data,$this->config,$index, $name); - $this->event->trigger("beforeRender",$data); - $output.=$data->to_xml(); - $index++; - } - return $output; - } - - /*! returns update start string - */ - protected function updates_start() { - $start = '<updates>'; - return $start; - } - - /*! returns update end string - */ - protected function updates_end() { - $start = '</updates>'; - return $start; - } - - /*! checks if action version given by client is deprecated - @param action - DataAction object - */ - public function check_collision($action) { - $version = $this->sql->escape($this->request->get_version()); - //$user = $this->sql->escape($this->request->get_user()); - $last_version = $this->get_update_max_version(); - if (($last_version > $version)&&($action->get_status() == 'update')) { - $action->error(); - $action->set_status('collision'); - } - } -} - -?>
\ No newline at end of file diff --git a/codebase/xss_filter.php b/codebase/xss_filter.php deleted file mode 100644 index ed0a309..0000000 --- a/codebase/xss_filter.php +++ /dev/null @@ -1,199 +0,0 @@ -<?php - -// +----------------------------------------------------------------------+ -// | Copyright (c) 2001-2008 Liip AG | -// +----------------------------------------------------------------------+ -// | Licensed under the Apache License, Version 2.0 (the "License"); | -// | you may not use this file except in compliance with the License. | -// | You may obtain a copy of the License at | -// | http://www.apache.org/licenses/LICENSE-2.0 | -// | Unless required by applicable law or agreed to in writing, software | -// | distributed under the License is distributed on an "AS IS" BASIS, | -// | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | -// | implied. See the License for the specific language governing | -// | permissions and limitations under the License. | -// +----------------------------------------------------------------------+ -// | Author: Christian Stocker <christian.stocker@liip.ch> | -// +----------------------------------------------------------------------+ - - -//original name was lx_externalinput_clean -//renamed to prevent possible conflicts -class dhx_externalinput_clean { - // this basic clean should clean html code from - // lot of possible malicious code for Cross Site Scripting - // use it whereever you get external input - - // you can also set $filterOut to some use html cleaning, but I don't know of any code, which could - // exploit that. But if you want to be sure, set it to eg. array("Tidy","Dom"); - static function basic($string, $filterIn = array("Tidy","Dom","Striptags"), $filterOut = "none") { - $string = self::tidyUp($string, $filterIn); - $string = str_replace(array("&", "<", ">"), array("&amp;", "&lt;", "&gt;"), $string); - - // fix &entitiy\n; - $string = preg_replace('#(&\#*\w+)[\x00-\x20]+;#u', "$1;", $string); - $string = preg_replace('#(&\#x*)([0-9A-F]+);*#iu', "$1$2;", $string); - - $string = html_entity_decode($string, ENT_COMPAT, "UTF-8"); - - // remove any attribute starting with "on" or xmlns - $string = preg_replace('#(<[^>]+[\x00-\x20\"\'\/])(on|xmlns)[^>]*>#iUu', "$1>", $string); - - // remove javascript: and vbscript: protocol - $string = preg_replace('#([a-z]*)[\x00-\x20\/]*=[\x00-\x20\/]*([\`\'\"]*)[\x00-\x20\/]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iUu', '$1=$2nojavascript...', $string); - $string = preg_replace('#([a-z]*)[\x00-\x20\/]*=[\x00-\x20\/]*([\`\'\"]*)[\x00-\x20\/]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iUu', '$1=$2novbscript...', $string); - $string = preg_replace('#([a-z]*)[\x00-\x20\/]*=[\x00-\x20\/]*([\`\'\"]*)[\x00-\x20\/]*-moz-binding[\x00-\x20]*:#Uu', '$1=$2nomozbinding...', $string); - $string = preg_replace('#([a-z]*)[\x00-\x20\/]*=[\x00-\x20\/]*([\`\'\"]*)[\x00-\x20\/]*data[\x00-\x20]*:#Uu', '$1=$2nodata...', $string); - - //remove any style attributes, IE allows too much stupid things in them, eg. - //<span style="width: expression(alert('Ping!'));"></span> - // and in general you really don't want style declarations in your UGC - - $string = preg_replace('#(<[^>]+[\x00-\x20\"\'\/])style[^>]*>#iUu', "$1>", $string); - - //remove namespaced elements (we do not need them...) - $string = preg_replace('#</*\w+:\w[^>]*>#i', "", $string); - - //remove really unwanted tags - do { - $oldstring = $string; - $string = preg_replace('#</*(applet|meta|xml|blink|link|style|script|embed|object|iframe|frame|frameset|ilayer|layer|bgsound|title|base)[^>]*>#i', "", $string); - } while ($oldstring != $string); - - return self::tidyUp($string, $filterOut); - } - - static function tidyUp($string, $filters) { - if (is_array($filters)) { - foreach ($filters as $filter) { - $return = self::tidyUpWithFilter($string, $filter); - if ($return !== false) { - return $return; - } - } - } else { - $return = self::tidyUpWithFilter($string, $filters); - } - // if no filter matched, use the Striptags filter to be sure. - if ($return === false) { - return self::tidyUpModuleStriptags($string); - } else { - return $return; - } - } - - static private function tidyUpWithFilter($string, $filter) { - if (is_callable(array("self", "tidyUpModule" . $filter))) { - return call_user_func(array("self", "tidyUpModule" . $filter), $string); - } - return false; - } - - static private function tidyUpModuleStriptags($string) { - - return strip_tags($string); - } - - static private function tidyUpModuleNone($string) { - return $string; - } - - static private function tidyUpModuleDom($string) { - $dom = new domdocument(); - @$dom->loadHTML("<html><body>" . $string . "</body></html>"); - $string = ''; - foreach ($dom->documentElement->firstChild->childNodes as $child) { - $string .= $dom->saveXML($child); - } - return $string; - } - - static private function tidyUpModuleTidy($string) { - if (class_exists("tidy")) { - $tidy = new tidy(); - $tidyOptions = array("output-xhtml" => true, - "show-body-only" => true, - "clean" => true, - "wrap" => "350", - "indent" => true, - "indent-spaces" => 1, - "ascii-chars" => false, - "wrap-attributes" => false, - "alt-text" => "", - "doctype" => "loose", - "numeric-entities" => true, - "drop-proprietary-attributes" => true, - "enclose-text" => false, - "enclose-block-text" => false - - ); - $tidy->parseString($string, $tidyOptions, "utf8"); - $tidy->cleanRepair(); - return (string) $tidy; - } else { - return false; - } - } -} - -define("DHX_SECURITY_SAFETEXT", 1); -define("DHX_SECURITY_SAFEHTML", 2); -define("DHX_SECURITY_TRUSTED", 3); - -class ConnectorSecurity{ - static public $xss = DHX_SECURITY_SAFETEXT; - static public $security_key = false; - static public $security_var = "dhx_security"; - - static private $filterClass = null; - static function filter($value, $mode = false){ - if ($mode === false) - $mode = ConnectorSecurity::$xss; - - if ($mode == DHX_SECURITY_TRUSTED) - return $value; - if ($mode == DHX_SECURITY_SAFETEXT) - return filter_var($value, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES); - if ($mode == DHX_SECURITY_SAFEHTML){ - if (ConnectorSecurity::$filterClass == null) - ConnectorSecurity::$filterClass = new dhx_externalinput_clean(); - return ConnectorSecurity::$filterClass->basic($value); - } - throw new Error("Invalid security mode:"+$mode); - } - - static function CSRF_detected(){ - LogMaster::log("[SECURITY] Possible CSRF attack detected", array( - "referer" => $_SERVER["HTTP_REFERER"], - "remote" => $_SERVER["REMOTE_ADDR"] - )); - LogMaster::log("Request data", $_POST); - die(); - } - static function checkCSRF($edit){ - if (ConnectorSecurity::$security_key){ - if (!isset($_SESSION)) - @session_start(); - - if ($edit=== true){ - if (!isset($_POST[ConnectorSecurity::$security_var])) - return ConnectorSecurity::CSRF_detected(); - $master_key = $_SESSION[ConnectorSecurity::$security_var]; - $update_key = $_POST[ConnectorSecurity::$security_var]; - if ($master_key != $update_key) - return ConnectorSecurity::CSRF_detected(); - - return ""; - } - //data loading - if (!array_key_exists(ConnectorSecurity::$security_var,$_SESSION)){ - $_SESSION[ConnectorSecurity::$security_var] = md5(uniqid()); - } - - return $_SESSION[ConnectorSecurity::$security_var]; - } - - return ""; - } - -}
\ No newline at end of file |