[4001] | 1 | <?php
|
---|
| 2 |
|
---|
| 3 | /*! DataItemUpdate class for realization Optimistic concurrency control
|
---|
| 4 | Wrapper for DataItem object
|
---|
| 5 | It's used during outputing updates instead of DataItem object
|
---|
| 6 | Create wrapper for every data item with update information.
|
---|
| 7 | */
|
---|
| 8 | class DataItemUpdate extends DataItem {
|
---|
| 9 |
|
---|
| 10 |
|
---|
| 11 | /*! constructor
|
---|
| 12 | @param data
|
---|
| 13 | hash of data
|
---|
| 14 | @param config
|
---|
| 15 | DataConfig object
|
---|
| 16 | @param index
|
---|
| 17 | index of element
|
---|
| 18 | */
|
---|
| 19 | public function __construct($data,$config,$index,$type){
|
---|
| 20 | $this->config=$config;
|
---|
| 21 | $this->data=$data;
|
---|
| 22 | $this->index=$index;
|
---|
| 23 | $this->skip=false;
|
---|
| 24 | $this->child = new $type($data, $config, $index);
|
---|
| 25 | }
|
---|
| 26 |
|
---|
| 27 | /*! returns parent_id (for Tree and TreeGrid components)
|
---|
| 28 | */
|
---|
| 29 | public function get_parent_id(){
|
---|
| 30 | if (method_exists($this->child, 'get_parent_id')) {
|
---|
| 31 | return $this->child->get_parent_id();
|
---|
| 32 | } else {
|
---|
| 33 | return '';
|
---|
| 34 | }
|
---|
| 35 | }
|
---|
| 36 |
|
---|
| 37 |
|
---|
| 38 | /*! generate XML on the data hash base
|
---|
| 39 | */
|
---|
| 40 | public function to_xml(){
|
---|
| 41 | $str= "<update ";
|
---|
| 42 | $str .= 'status="'.$this->data['type'].'" ';
|
---|
| 43 | $str .= 'id="'.$this->data['dataId'].'" ';
|
---|
| 44 | $str .= 'parent="'.$this->get_parent_id().'"';
|
---|
| 45 | $str .= '>';
|
---|
| 46 | $str .= $this->child->to_xml();
|
---|
| 47 | $str .= '</update>';
|
---|
| 48 | return $str;
|
---|
| 49 | }
|
---|
| 50 |
|
---|
| 51 | /*! return starting tag for XML string
|
---|
| 52 | */
|
---|
| 53 | public function to_xml_start(){
|
---|
| 54 | $str="<update ";
|
---|
| 55 | $str .= 'status="'.$this->data['type'].'" ';
|
---|
| 56 | $str .= 'id="'.$this->data['dataId'].'" ';
|
---|
| 57 | $str .= 'parent="'.$this->get_parent_id().'"';
|
---|
| 58 | $str .= '>';
|
---|
| 59 | $str .= $this->child->to_xml_start();
|
---|
| 60 | return $str;
|
---|
| 61 | }
|
---|
| 62 |
|
---|
| 63 | /*! return ending tag for XML string
|
---|
| 64 | */
|
---|
| 65 | public function to_xml_end(){
|
---|
| 66 | $str = $this->child->to_xml_end();
|
---|
| 67 | $str .= '</update>';
|
---|
| 68 | return $str;
|
---|
| 69 | }
|
---|
| 70 |
|
---|
| 71 | /*! returns false for outputing only current item without child items
|
---|
| 72 | */
|
---|
| 73 | public function has_kids(){
|
---|
| 74 | return false;
|
---|
| 75 | }
|
---|
| 76 |
|
---|
| 77 | /*! sets count of child items
|
---|
| 78 | @param value
|
---|
| 79 | count of child items
|
---|
| 80 | */
|
---|
| 81 | public function set_kids($value){
|
---|
| 82 | if (method_exists($this->child, 'set_kids')) {
|
---|
| 83 | $this->child->set_kids($value);
|
---|
| 84 | }
|
---|
| 85 | }
|
---|
| 86 |
|
---|
| 87 | /*! sets attribute for item
|
---|
| 88 | */
|
---|
| 89 | public function set_attribute($name, $value){
|
---|
| 90 | if (method_exists($this->child, 'set_attribute')) {
|
---|
| 91 | LogMaster::log("setting attribute: \nname = {$name}\nvalue = {$value}");
|
---|
| 92 | $this->child->set_attribute($name, $value);
|
---|
| 93 | } else {
|
---|
| 94 | LogMaster::log("set_attribute method doesn't exists");
|
---|
| 95 | }
|
---|
| 96 | }
|
---|
| 97 | }
|
---|
| 98 |
|
---|
| 99 |
|
---|
| 100 | class DataUpdate{
|
---|
| 101 |
|
---|
| 102 | protected $table; //!< table , where actions are stored
|
---|
| 103 | protected $url; //!< url for notification service, optional
|
---|
| 104 | protected $sql; //!< DB wrapper object
|
---|
| 105 | protected $config; //!< DBConfig object
|
---|
| 106 | protected $request; //!< DBRequestConfig object
|
---|
| 107 | protected $event;
|
---|
| 108 | protected $item_class;
|
---|
| 109 | protected $demu;
|
---|
| 110 |
|
---|
| 111 | //protected $config;//!< DataConfig instance
|
---|
| 112 | //protected $request;//!< DataRequestConfig instance
|
---|
| 113 |
|
---|
| 114 | /*! constructor
|
---|
| 115 |
|
---|
| 116 | @param connector
|
---|
| 117 | Connector object
|
---|
| 118 | @param config
|
---|
| 119 | DataConfig object
|
---|
| 120 | @param request
|
---|
| 121 | DataRequestConfig object
|
---|
| 122 | */
|
---|
| 123 | function __construct($sql, $config, $request, $table, $url){
|
---|
| 124 | $this->config= $config;
|
---|
| 125 | $this->request= $request;
|
---|
| 126 | $this->sql = $sql;
|
---|
| 127 | $this->table=$table;
|
---|
| 128 | $this->url=$url;
|
---|
| 129 | $this->demu = false;
|
---|
| 130 | }
|
---|
| 131 |
|
---|
| 132 | public function set_demultiplexor($path){
|
---|
| 133 | $this->demu = $path;
|
---|
| 134 | }
|
---|
| 135 |
|
---|
| 136 | public function set_event($master, $name){
|
---|
| 137 | $this->event = $master;
|
---|
| 138 | $this->item_class = $name;
|
---|
| 139 | }
|
---|
| 140 |
|
---|
| 141 | private function select_update($actions_table, $join_table, $id_field_name, $version, $user) {
|
---|
| 142 | $sql = "SELECT * FROM {$actions_table}";
|
---|
| 143 | $sql .= " LEFT OUTER JOIN {$join_table} ON ";
|
---|
| 144 | $sql .= "{$actions_table}.DATAID = {$join_table}.{$id_field_name} ";
|
---|
| 145 | $sql .= "WHERE {$actions_table}.ID > '{$version}' AND {$actions_table}.USER <> '{$user}'";
|
---|
| 146 | return $sql;
|
---|
| 147 | }
|
---|
| 148 |
|
---|
| 149 | private function get_update_max_version() {
|
---|
| 150 | $sql = "SELECT MAX(id) as VERSION FROM {$this->table}";
|
---|
| 151 | $res = $this->sql->query($sql);
|
---|
| 152 | $data = $this->sql->get_next($res);
|
---|
| 153 |
|
---|
| 154 | if ($data == false || $data['VERSION'] == false)
|
---|
| 155 | return 1;
|
---|
| 156 | else
|
---|
| 157 | return $data['VERSION'];
|
---|
| 158 | }
|
---|
| 159 |
|
---|
| 160 | private function log_update_action($actions_table, $dataId, $status, $user) {
|
---|
| 161 | $sql = "INSERT INTO {$actions_table} (DATAID, TYPE, USER) VALUES ('{$dataId}', '{$status}', '{$user}')";
|
---|
| 162 | $this->sql->query($sql);
|
---|
| 163 | if ($this->demu)
|
---|
| 164 | file_get_contents($this->demu);
|
---|
| 165 | }
|
---|
| 166 |
|
---|
| 167 |
|
---|
| 168 |
|
---|
| 169 |
|
---|
| 170 | /*! records operations in actions_table
|
---|
| 171 | @param action
|
---|
| 172 | DataAction object
|
---|
| 173 | */
|
---|
| 174 | public function log_operations($action) {
|
---|
| 175 | $type = $this->sql->escape($action->get_status());
|
---|
| 176 | $dataId = $this->sql->escape($action->get_new_id());
|
---|
| 177 | $user = $this->sql->escape($this->request->get_user());
|
---|
| 178 | if ($type!="error" && $type!="invalid" && $type !="collision") {
|
---|
| 179 | $this->log_update_action($this->table, $dataId, $type, $user);
|
---|
| 180 | }
|
---|
| 181 | }
|
---|
| 182 |
|
---|
| 183 |
|
---|
| 184 | /*! return action version in XMl format
|
---|
| 185 | */
|
---|
| 186 | public function get_version() {
|
---|
| 187 | $version = $this->get_update_max_version();
|
---|
| 188 | return "<userdata name='version'>".$version."</userdata>";
|
---|
| 189 | }
|
---|
| 190 |
|
---|
| 191 |
|
---|
| 192 | /*! adds action version in output XML as userdata
|
---|
| 193 | */
|
---|
| 194 | public function version_output() {
|
---|
| 195 | echo $this->get_version();
|
---|
| 196 | }
|
---|
| 197 |
|
---|
| 198 |
|
---|
| 199 | /*! create update actions in XML-format and sends it to output
|
---|
| 200 | */
|
---|
| 201 | public function get_updates() {
|
---|
| 202 | $sub_request = new DataRequestConfig($this->request);
|
---|
| 203 | $version = $this->request->get_version();
|
---|
| 204 | $user = $this->request->get_user();
|
---|
| 205 |
|
---|
| 206 | $sub_request->parse_sql($this->select_update($this->table, $this->request->get_source(), $this->config->id['db_name'], $version, $user));
|
---|
| 207 | $sub_request->set_relation(false);
|
---|
| 208 |
|
---|
| 209 | $output = $this->render_set($this->sql->select($sub_request), $this->item_class);
|
---|
| 210 |
|
---|
| 211 | ob_clean();
|
---|
| 212 | header("Content-type:text/xml");
|
---|
| 213 |
|
---|
| 214 | echo $this->updates_start();
|
---|
| 215 | echo $this->get_version();
|
---|
| 216 | echo $output;
|
---|
| 217 | echo $this->updates_end();
|
---|
| 218 | }
|
---|
| 219 |
|
---|
| 220 |
|
---|
| 221 | protected function render_set($res, $name){
|
---|
| 222 | $output="";
|
---|
| 223 | $index=0;
|
---|
| 224 | while ($data=$this->sql->get_next($res)){
|
---|
| 225 | $data = new DataItemUpdate($data,$this->config,$index, $name);
|
---|
| 226 | $this->event->trigger("beforeRender",$data);
|
---|
| 227 | $output.=$data->to_xml();
|
---|
| 228 | $index++;
|
---|
| 229 | }
|
---|
| 230 | return $output;
|
---|
| 231 | }
|
---|
| 232 |
|
---|
| 233 | /*! returns update start string
|
---|
| 234 | */
|
---|
| 235 | protected function updates_start() {
|
---|
| 236 | $start = '<updates>';
|
---|
| 237 | return $start;
|
---|
| 238 | }
|
---|
| 239 |
|
---|
| 240 | /*! returns update end string
|
---|
| 241 | */
|
---|
| 242 | protected function updates_end() {
|
---|
| 243 | $start = '</updates>';
|
---|
| 244 | return $start;
|
---|
| 245 | }
|
---|
| 246 |
|
---|
| 247 | /*! checks if action version given by client is deprecated
|
---|
| 248 | @param action
|
---|
| 249 | DataAction object
|
---|
| 250 | */
|
---|
| 251 | public function check_collision($action) {
|
---|
| 252 | $version = $this->sql->escape($this->request->get_version());
|
---|
| 253 | //$user = $this->sql->escape($this->request->get_user());
|
---|
| 254 | $last_version = $this->get_update_max_version();
|
---|
| 255 | if (($last_version > $version)&&($action->get_status() == 'update')) {
|
---|
| 256 | $action->error();
|
---|
| 257 | $action->set_status('collision');
|
---|
| 258 | }
|
---|
| 259 | }
|
---|
| 260 | }
|
---|
| 261 |
|
---|
| 262 | ?> |
---|