diff options
Diffstat (limited to 'codebase/connector/dataprocessor.php')
-rw-r--r-- | codebase/connector/dataprocessor.php | 505 |
1 files changed, 505 insertions, 0 deletions
diff --git a/codebase/connector/dataprocessor.php b/codebase/connector/dataprocessor.php new file mode 100644 index 0000000..e75fc85 --- /dev/null +++ b/codebase/connector/dataprocessor.php @@ -0,0 +1,505 @@ +<?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: {$operation} operation blocked"); + $action->error(); + } else { + $check = $this->connector->event->trigger("beforeProcessing",$action); + if (!$action->is_ready()) + $this->check_exts($action,$mode); + $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."='".$v."' "; + } + $str.=">{$this->output}</action>"; + return $str; + } + /*! 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 |