diff --git a/README.md b/README.md index 969d5f3..95032eb 100644 --- a/README.md +++ b/README.md @@ -23,15 +23,9 @@ and paging) as well as server-side sorting and filtering. External links -------------- - * Documentation - http://docs.dhtmlx.com/doku.php?id=dhtmlxconnector:toc - * Video introduction - http://dhtmlx.com/docs/products/dhtmlxConnector/index.shtml - + * Documentation - http://docs.dhtmlx.com/connector__php__index.html Other languages --------------- - * Java - [wiki](http://docs.dhtmlx.com/doku.php?id=dhtmlxconnectorjava:toc), - [package](http://www.dhtmlx.com/x/download/regular/dhtmlxConnector_v09_java.zip) - * .Net - [wiki](http://docs.dhtmlx.com/doku.php?id=dhtmlxconnectornet:toc), - [package](http://www.dhtmlx.com/x/download/regular/dhtmlxConnector_v09_net.zip) - * ColdFustion - [wiki](http://docs.dhtmlx.com/doku.php?id=dhtmlxconnectorcf:toc), - [package](http://www.dhtmlx.com/x/download/regular/dhtmlxConnector_v10_cfm.zip) + * Java - [documentation](http://docs.dhtmlx.com/connector__java__index.html), + [github](https://github.com/DHTMLX/connector-java) diff --git a/codebase/base_connector.php b/codebase/base_connector.php old mode 100644 new mode 100755 index 26f1f8b..622fb17 --- a/codebase/base_connector.php +++ b/codebase/base_connector.php @@ -282,38 +282,38 @@ public function to_xml_end(){ Can be used on its own to provide raw data. **/ class Connector { + + private $id_seed=0; //!< default value, used to generate auto-IDs + private $db; //!< db connection resource + 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 ) + protected $updating=false;//!< flag of update mode ( response for data-update ) + protected $dload;//!< flag of dyn. loading mode + protected $data_separator = "\n"; + protected $live_update = false; // actions table name for autoupdating + protected $live_update_data_type = "DataUpdate"; + 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; 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; + public $model=false; + public $access; //!< AccessMaster instance + public $sql; //DataWrapper instance + public $event; //EventMaster instance + public $limit=false; /*! constructor @@ -330,7 +330,7 @@ class Connector { 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 (!$type) $type="PDO"; if (class_exists($type."DBDataWrapper",false)) $type.="DBDataWrapper"; if (!$item_type) $item_type="DataItem"; if (!$data_type) $data_type="DataProcessor"; @@ -419,7 +419,7 @@ public function configure($table,$id="",$fields=false,$extra=false,$relation_id= $id = $info["key"]; } $this->config->init($id,$fields,$extra,$relation_id); - if (strpos(trim($table), " ")!==false) + if (is_string($table) && strpos(trim($table), " ")!==false) $this->request->parse_sql($table); else $this->request->set_source($table); @@ -700,6 +700,9 @@ protected function end_run(){ */ public function set_encoding($encoding){ $this->encoding=$encoding; + if ($this->live_update !== false) { + $this->live_update->set_encoding($this->encoding); + } } /*! enable or disable dynamic loading mode @@ -810,6 +813,10 @@ public function set_options($name,$options){ $this->options[$name]=$options; } + public function get_options() { + return $this->options; + } + public function insert($data) { $action = new DataAction('inserted', false, $data); @@ -850,9 +857,10 @@ public function update($data) { @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); + public function enable_live_update($table, $url=false, $origin_table = false){ + $this->live_update = new $this->live_update_data_type($this->sql, $this->config, $this->request, $table,$url, array("connector" => $this, "table" => $origin_table)); $this->live_update->set_event($this->event,$this->names["item_class"]); + $this->live_update->set_encoding($this->encoding); $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")); diff --git a/codebase/db_common.php b/codebase/db_common.php old mode 100644 new mode 100755 index f6391d2..3650cfa --- a/codebase/db_common.php +++ b/codebase/db_common.php @@ -8,6 +8,8 @@ /*! manager of data request **/ class DataRequestConfig{ + + private $action_mode = ""; private $filters; //!< array of filtering rules private $relation=false; //!< ID or other element used for linking hierarchy private $sort_by; //!< sorting field @@ -52,6 +54,7 @@ public function copy($proto){ $this->relation =$proto->get_relation(); $this->user = $proto->user; $this->version = $proto->version; + $this->action_mode = $proto->action_mode; } /*! convert self to string ( for logs ) @@ -69,6 +72,15 @@ public function __toString(){ return $str; } + public function set_action_mode($action_mode) { + $this->action_mode = $action_mode; + return $this; + } + + public function get_action_mode() { + return $this->action_mode; + } + /*! returns set of filtering rules @return set of filtering rules @@ -205,7 +217,6 @@ 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 @@ -1089,69 +1100,6 @@ public function __construct($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.'`'; - } -} +include_once(__DIR__."/db_pdo.php"); ?> \ No newline at end of file diff --git a/codebase/db_mysql.php b/codebase/db_mysql.php new file mode 100644 index 0000000..d31d210 --- /dev/null +++ b/codebase/db_mysql.php @@ -0,0 +1,67 @@ +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_mysqli.php b/codebase/db_mysqli.php index 6740a3b..83beeed 100644 --- a/codebase/db_mysqli.php +++ b/codebase/db_mysqli.php @@ -4,6 +4,7 @@ @license GPL, see license.txt */ require_once("db_common.php"); +require_once("db_mysql.php"); class MySQLiDBDataWrapper extends MySQLDBDataWrapper{ @@ -53,4 +54,4 @@ public function fields_list($table) { } -?> \ No newline at end of file +?> diff --git a/codebase/db_phpci2.php b/codebase/db_phpci2.php old mode 100644 new mode 100755 index 9d10d99..220a126 --- a/codebase/db_phpci2.php +++ b/codebase/db_phpci2.php @@ -9,7 +9,7 @@ if you plan to use it for Oracle - use Oracle connection type instead **/ -class PHPCIDBDataWrapper extends DBDataWrapper{ +class PHPCI2DBDataWrapper extends DBDataWrapper{ private $last_result;//!< store result or last operation public function query($sql){ diff --git a/codebase/db_phpyii1.php b/codebase/db_phpyii1.php old mode 100644 new mode 100755 index 616d7f3..bbbd943 --- a/codebase/db_phpyii1.php +++ b/codebase/db_phpyii1.php @@ -6,7 +6,7 @@ require_once("db_common.php"); -class PHPYiiDBDataWrapper extends ArrayDBDataWrapper{ +class PHPYii1DBDataWrapper extends ArrayDBDataWrapper{ public function select($sql){ if (is_array($this->connection)) //result of findAll $res = $this->connection; diff --git a/codebase/gantt_connector.php b/codebase/gantt_connector.php old mode 100644 new mode 100755 index 3577835..a7a9c81 --- a/codebase/gantt_connector.php +++ b/codebase/gantt_connector.php @@ -31,15 +31,36 @@ function to_xml(){ } } +class GanttLinkDataItem extends DataItem { + + public function to_xml_start(){ + $str="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.">"; + } + +} /*! Connector class for dhtmlxGantt **/ class GanttConnector extends Connector{ + private $action_mode = ""; + public $links_table = ""; + + protected $live_update_data_type = "GanttDataUpdate"; 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 @@ -87,8 +108,14 @@ public function __construct($res,$type=false,$item_type=false,$data_type=false,$ function parse_request(){ parent::parse_request(); - if (isset($_GET["gantt_mode"]) && $_GET["gantt_mode"] == "links") - $this->links_mode = true; + $action_links = "links"; + if(isset($_GET["gantt_mode"]) && $_GET["gantt_mode"] == $action_links) { + $this->action_mode = $action_links; + $this->request->set_action_mode($action_links); + $this->options[$action_links]->request->set_action_mode($action_links); + $this->options[$action_links]->request->set_user($this->request->get_user()); + } + if (count($this->config->text)){ if (isset($_GET["to"])) @@ -119,11 +146,70 @@ function delete_related_links($action){ } } - public function render_links($table,$id="",$fields=false,$extra=false,$relation_id=false) { + public function render_links($table,$id="",$fields=false,$extra=false) { $links = new GanttLinksConnector($this->get_connection(),$this->names["db_class"]); + + if($this->live_update) + $links->enable_live_update($this->live_update->get_table()); + $links->render_table($table,$id,$fields,$extra); $this->set_options("links", $links); + $this->links_table = $table; + } + + + /*! 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->action_mode == "links") && 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(); } + } /*! DataProcessor class for Gantt component @@ -174,6 +260,7 @@ function to_xml(){ class JSONGanttConnector extends GanttConnector { protected $data_separator = ","; + protected $live_update_data_type = "JSONGanttDataUpdate"; /*! constructor @@ -218,7 +305,7 @@ 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).'"}'; + $str[]='{"id":"'.$this->xmlentities($k).'", "value":"'.$this->xmlentities($k).'", "label":"'.$this->xmlentities($v).'"}'; $options=implode(",",$str); } $this->options[$name]=$options; @@ -267,66 +354,25 @@ protected function output_as_xml($res){ public function render_links($table,$id="",$fields=false,$extra=false,$relation_id=false) { $links = new JSONGanttLinksConnector($this->get_connection(),$this->names["db_class"]); + + if($this->live_update) + $links->enable_live_update($this->live_update->get_table()); + $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; - } +class GanttLinksConnector extends OptionsConnector { + protected $live_update_data_type = "GanttDataUpdate"; - } - } - $this->end_run(); + public function __construct($res,$type=false,$item_type=false,$data_type=false,$render_type=false){ + if (!$item_type) $item_type="GanttLinkDataItem"; + parent::__construct($res,$type,$item_type,$data_type,$render_type); } -} - -class GanttLinksConnector extends OptionsConnector { public function render(){ if (!$this->init_flag){ $this->init_flag=true; @@ -345,6 +391,7 @@ public function save() { class JSONGanttLinksConnector extends JSONOptionsConnector { + protected $live_update_data_type = "JSONGanttDataUpdate"; public function render(){ if (!$this->init_flag){ $this->init_flag=true; @@ -361,4 +408,60 @@ public function save() { } } +class JSONGanttDataUpdate extends JSONDataUpdate { + + public function get_updates() { + $updates = $this->get_data_updates(); + //ToDo: Add rendering for data. + } + + + private function get_data_updates() { + $actions_table = $this->table; + $version = $this->request->get_version(); + $user = $this->request->get_user(); + + $select_actions = "SELECT DATAID, TYPE, USER FROM {$actions_table}"; + $select_actions .= " WHERE {$actions_table}.ID > '{$version}' AND {$actions_table}.USER <> '{$user}'"; + + + $output = array(); + $index = 0; + $actions_query = $this->sql->query($select_actions); + while($action_data=$this->sql->get_next($actions_query)){ + $action_type = $action_data["TYPE"]; + $type_parts = explode("#", $action_type); + $action_mode = $type_parts[1]; + if($action_mode == "links") { + $data = $this->select_links_for_action($action_data["DATAID"]); + $data = new DataItemUpdate($data, $this->config, $index, $this->item_class); + } + else { + $data = $this->select_task_for_action($action_data["DATAID"]); + $data = new DataItemUpdate($data, $this->config, $index, $this->item_class); + } + + array_push($output, $data); + $index++; + } + + return $output; + } + + protected function select_task_for_action($taskId) { + $tasks_table = $this->request->get_source(); + $field_task_id = $this->config->id['db_name']; + $select_actions_tasks = "SELECT * FROM {$tasks_table} WHERE {$taskId} = {$tasks_table}.{$field_task_id}"; + return $this->sql->get_next($this->sql->query($select_actions_tasks)); + } + + protected function select_links_for_action($taskId) { + $links_connector_options = $this->options["connector"]->get_options(); + $links_table = $links_connector_options["links"]->get_request()->get_source(); + $field_task_id = $this->config->id['db_name']; + $select_actions_tasks = "SELECT * FROM {$links_table} WHERE {$taskId} = {$links_table}.{$field_task_id}"; + return $this->sql->get_next($this->sql->query($select_actions_tasks)); + } +} + ?> \ No newline at end of file diff --git a/codebase/mixed_connector.php b/codebase/mixed_connector.php index 461d6ec..99edf86 100644 --- a/codebase/mixed_connector.php +++ b/codebase/mixed_connector.php @@ -7,22 +7,52 @@ 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; - } + private $_data_type = null; + + function __construct($dataType = "json") { + $this->_data_type = $dataType; + } + + protected $attributes = array(); + protected $connectors = array(); + + public function add($name, $conn) { + $this->connectors[$name] = $conn; + } + + public function render() { + if($this->_data_type == "json") + $this->render_json(); + else + $this->render_xml(); + } + + private function render_json() { + $result = "{"; + $parts = array(); + foreach($this->connectors as $name => $conn) { + $conn->asString(true); + $parts[] = "\"".$name."\":".($conn->render())."\n"; + } + $result .= implode(",\n", $parts)."}"; + echo $result; + } + + private function render_xml() { + $result = ""; + $parts = array(); + + foreach($this->connectors as $name => $conn) { + $conn->asString(true); + $parts[] = "<".$name.">".($conn->render())."\n"; + } + $result .= implode("", $parts); + $this->output_as_xml($result); + } + + protected function output_as_xml($res) { + echo "encoding."' ?>".$this->xml_start().$res.$this->xml_end(); + } } ?> \ No newline at end of file diff --git a/codebase/scheduler_connector.php b/codebase/scheduler_connector.php old mode 100644 new mode 100755 index ee0cd20..7aa46e1 --- a/codebase/scheduler_connector.php +++ b/codebase/scheduler_connector.php @@ -136,6 +136,7 @@ function to_xml(){ class JSONSchedulerConnector extends SchedulerConnector { protected $data_separator = ","; + protected $live_update_data_type = "JSONDataUpdate"; /*! constructor @@ -180,7 +181,7 @@ 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).'"}'; + $str[]='{"id":"'.$this->xmlentities($k).'", "value":"'.$this->xmlentities($k).'", "label":"'.$this->xmlentities($v).'"}'; $options=implode(",",$str); } $this->options[$name]=$options; diff --git a/codebase/update.php b/codebase/update.php old mode 100644 new mode 100755 index dacc211..4e73e93 --- a/codebase/update.php +++ b/codebase/update.php @@ -1,266 +1,354 @@ -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= "data['type'].'" '; - $str .= 'id="'.$this->data['dataId'].'" '; - $str .= 'parent="'.$this->get_parent_id().'"'; - $str .= '>'; - $str .= $this->child->to_xml(); - $str .= ''; - return $str; - } - - /*! return starting tag for XML string - */ - public function to_xml_start(){ - $str="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 .= ''; - 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 "".$version.""; - } - - - /*! 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 = ''; - return $start; - } - - /*! returns update end string - */ - protected function updates_end() { - $start = ''; - 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 +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= "data['action_table_type'].'" '; + $str .= 'id="'.$this->data['dataId'].'" '; + $str .= 'parent="'.$this->get_parent_id().'"'; + $str .= '>'; + $str .= $this->child->to_xml(); + $str .= ''; + return $str; + } + + /*! return starting tag for XML string + */ + public function to_xml_start(){ + $str="data['action_table_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 .= ''; + 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 $encoding="utf-8"; + 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, $options){ + $this->config= $config; + $this->request= $request; + $this->sql = $sql; + $this->table=$table; + $this->url=$url; + $this->demu = false; + $this->options = $options; + } + + public function set_demultiplexor($path){ + $this->demu = $path; + } + + public function set_event($master, $name){ + $this->event = $master; + $this->item_class = $name; + } + + public function set_encoding($encoding){ + $this->encoding = $encoding; + } + + protected function select_update($actions_table, $join_table, $id_field_name, $version, $user) { + + if ($this->options["table"] !== false) + $join_table = $this->options["table"]; + + $sql = "SELECT $join_table.*, {$actions_table}.id, {$actions_table}.dataId, {$actions_table}.type as action_table_type, {$actions_table}.user 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; + } + + protected 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); + } + + public function get_table() { + return $this->table; + } + + /*! 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") { + $action_mode = $this->request->get_action_mode(); + if(!empty($action_mode)) + $type .= "#".$action_mode; + + $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 "".$version.""; + } + + + /*! 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; charset=".$this->encoding); + + 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 = ''; + return $start; + } + + /*! returns update end string + */ + protected function updates_end() { + $start = ''; + 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'); + } + } +} + + +class JSONDataItemUpdate extends DataItemUpdate { + + public function to_xml() { + return array( + "status" => $this->data["action_table_type"], + "id" => $this->data["dataId"], + "parent" => $this->get_parent_id(), + "data" => $this->child->to_xml() + ); + } + +} + +class JSONDataUpdate extends DataUpdate { + + /*! adds action version in output XML as userdata +*/ + public function version_output($conn, $out) { + $outJson = json_decode($out->__toString(), true); + if(!isset($outJson["userdata"])) + $outJson["userdata"] = array(); + + $outJson["userdata"] = array_merge($outJson["userdata"], $this->get_version()); + $out->reset(); + $out->add(json_encode($outJson)); + } + + /*! return action version in XMl format + */ + public function get_version() { + $version = array("version" => $this->get_update_max_version()); + return $version; + } + + 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); + + if(!isset($output["userdata"])) + $output["userdata"] = array(); + + $output["userdata"] = array_merge($output["userdata"], $this->get_version()); + $this->output(json_encode($output)); + } + + protected function render_set($res, $name){ + $output = array(); + $index = 0; + while($data = $this->sql->get_next($res)) { + $data = new JSONDataItemUpdate($data, $this->config, $index, $name); + $this->event->trigger("beforeRender", $data); + array_push($output, $data->to_xml()); + $index++; + } + + return array("updates" => $output); + } + + protected function output($res){ + $out = new OutputWriter($res, ""); + $out->set_type("json"); + $this->event->trigger("beforeOutput", $this, $out); + $out->output("", true, $this->encoding); + } + +} + +?> diff --git a/samples/combo/01_basic.html b/samples/combo/01_basic.html index 129140a..10c3ea2 100644 --- a/samples/combo/01_basic.html +++ b/samples/combo/01_basic.html @@ -1,15 +1,14 @@ - + Filtering and Autocomplete mode + + + + - - - - -
diff --git a/samples/combo/01_basic_connector.php b/samples/combo/01_basic_connector.php index 1ef8df4..847c9df 100644 --- a/samples/combo/01_basic_connector.php +++ b/samples/combo/01_basic_connector.php @@ -1,5 +1,4 @@ + Filtering and Autocomplete mode + + + + - - - - -
diff --git a/samples/combo/02_sql_connector.php b/samples/combo/02_sql_connector.php index cf0e559..1d5a1a1 100644 --- a/samples/combo/02_sql_connector.php +++ b/samples/combo/02_sql_connector.php @@ -1,6 +1,5 @@ configure("tasks","taskId","taskName","","parentId"); - $conn = new MixedConnector($res, "PDO"); + $conn = new MixedConnector("json"); $conn->add("country_data", $data1); $conn->add("countries", $data2); $conn->render(); diff --git a/samples/common/02_easyfilter_connector.php b/samples/common/02_easyfilter_connector.php index 0d7c35c..a002aab 100644 --- a/samples/common/02_easyfilter_connector.php +++ b/samples/common/02_easyfilter_connector.php @@ -1,6 +1,5 @@ + Static loading + diff --git a/samples/dataview/01_static_loading.php b/samples/dataview/01_static_loading.php index 10b8ee6..337ccbb 100644 --- a/samples/dataview/01_static_loading.php +++ b/samples/dataview/01_static_loading.php @@ -1,5 +1,4 @@ + Dynamic loading + diff --git a/samples/dataview/02_dynamic_loading.php b/samples/dataview/02_dynamic_loading.php index 858c2b7..46d635f 100644 --- a/samples/dataview/02_dynamic_loading.php +++ b/samples/dataview/02_dynamic_loading.php @@ -1,6 +1,4 @@ +