/[cvs]/nfo/php/libs/org.netfrag.glib/DesignPattern/RemoteProxy.php
ViewVC logotype

Contents of /nfo/php/libs/org.netfrag.glib/DesignPattern/RemoteProxy.php

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.3 - (show annotations)
Wed Mar 5 16:10:17 2003 UTC (21 years, 5 months ago) by joko
Branch: MAIN
Changes since 1.2: +34 -3 lines
updated docu (phpDocumentor testing....)

1 <?php
2 /**
3 * This file contains the DesignPattern::RemoteProxy class
4 *
5 * @author Andreas Motl <andreas.motl@ilo.de>
6 * @package org.netfrag.glib
7 * @name DesignPattern::RemoteProxy
8 *
9 */
10
11 /**
12 * -------------------------------------------------------------------------
13 * $Id: RemoteProxy.php,v 1.2 2003/03/05 12:14:02 joko Exp $
14 * -------------------------------------------------------------------------
15 * $Log: RemoteProxy.php,v $
16 * Revision 1.2 2003/03/05 12:14:02 joko
17 * renamed method
18 * constructor argument expansion
19 *
20 * Revision 1.1 2003/03/03 22:06:46 joko
21 * refactored from Data::Driver::Proxy
22 *
23 * Revision 1.3 2003/03/01 04:56:38 joko
24 * new comment style for large blocks - stolen from phpHtmlLib
25 * commit-log encapsulated into such a block
26 * introduced some documentation
27 * refactored todo (now also inside a stylish block)
28 *
29 * Revision 1.2 2003/02/13 21:48:09 joko
30 * + caching mechanisms more configurable now
31 *
32 * Revision 1.1 2003/02/09 17:23:21 joko
33 * + refactored from flib/Application/RPC/ProxyObject.php
34 *
35 * Revision 1.7 2003/02/03 03:31:38 jonen
36 * - moved '$encoder->toISO()' to 'Remote.php'
37 *
38 * Revision 1.6 2002/12/22 13:26:20 jonen
39 * + added support of tangram independent id (e.g. Data::UUID) toggled by option at conrtuctor
40 *
41 * Revision 1.5 2002/12/18 22:36:49 jonen
42 * + added support to get remote objects via backend via 'guid'
43 * + renamed '_loadBackend' to '_loadRemote'
44 * + constructor now accepts additional options:
45 * + remote: try to get object via '_loadRemote' ...
46 * + oid: use the given identifier as an 'oid' when doing '_loadRemote'
47 * + guid: use the given identifier as a 'guid' when doing '_loadRemote'
48 *
49 * Revision 1.4 2002/12/12 02:46:31 joko
50 * + state (session) gets flushed when data was successfully loaded from remote side
51 * + fixed _loadBackend
52 * + fixed flushState
53 *
54 * Revision 1.3 2002/12/06 04:12:54 joko
55 * + replaced 'xyzCache' through 'xyzProxy'
56 * + function store(...)
57 *
58 * Revision 1.2 2002/12/05 21:44:09 joko
59 * + debugging
60 *
61 * Revision 1.1 2002/12/01 17:23:58 joko
62 * + initial check-in
63 *
64 * Revision 1.11 2002/11/12 06:05:58 cvsjoko
65 * + renamed class: Text_Encode -> TextEncode
66 *
67 * Revision 1.10 2002/10/29 19:15:33 cvsjoko
68 * - moved utf8/iso-conversion to lib/utils/Text_Encode.php
69 *
70 * Revision 1.9 2002/10/26 12:32:36 cvsjoko
71 * - removed debugging via "print"
72 * + added generic logging via PEAR::Log
73 *
74 * Revision 1.8 2002/10/22 09:51:38 cvsmax
75 * + moved semi-method 'createBackend' to method $site->user->create at User.class.php
76 *
77 * Revision 1.7 2002/10/21 18:27:09 cvsjoko
78 * - manually disabled any form of caching
79 *
80 * Revision 1.6 2002/10/17 03:48:47 cvsmax
81 * + new
82 * + function _createBackend create new Backend
83 * + function _create api-create
84 *
85 * Revision 1.5 2002/10/16 03:37:54 cvsjoko
86 * + bugfix: wrong comparison in restriction to save to array
87 *
88 * Revision 1.4 2002/10/10 03:04:23 cvsjoko
89 * + no debug-output
90 *
91 * Revision 1.3 2002/10/10 03:03:27 cvsjoko
92 * + bugfix: save object to cache only if payload from backend isn't empty
93 *
94 * Revision 1.2 2002/10/10 02:40:06 cvsjoko
95 * + new level of data-caching (session and persistant)
96 * + function _loadState loads data from session
97 * + function _saveState saves data to session
98 * + function save api-save (session & backend)
99 * + function _commit saves data to backend
100 * + handy utils
101 * + function _setAttributes
102 * + function flushState
103 *
104 * Revision 1.1 2002/10/09 00:51:39 cvsjoko
105 * + new
106 * -------------------------------------------------------------------------
107 */
108
109 /**
110 * Data::Driver::Proxy -- Multiple stage data fetching and caching
111 *
112 *
113 * This class (Data::Driver::Proxy) provides an abstract framework
114 * for loading/saving arbitrary data from/to data storages interfaced
115 * by storage *proxy*-drivers.
116 * Don't mix these up with the concrete storage *handle*-drivers
117 * doing the lowlevel stuff (opening files, talking sql, etc.).
118 * These proxy-drivers are "just" wrappers around them
119 * providing a more highlevel, consistent API making
120 * it easier for Data::Driver::Proxy to do its main work:
121 *
122 * Multiple stage data fetching and caching:
123 *
124 * DATA, ...
125 * ... also refered to as data, should be handled as
126 * something called data.
127 *
128 * STAGES
129 * x native php4 session: serialized payload
130 * x single rdbms table: serialized payload
131 * x ... via custom database wrapper
132 * x included php-file, included php-library
133 * o object, component, package, callbacks
134 * x ... via php PEAR DB abstraction objects
135 * x remote objects (items): flat attribute hash
136 * o use Data::Object::Identity
137 * o via Data::Driver::Proxy::RPC or others
138 * o Data::Object::Encoder: encodes/decodes values
139 * o Data::Object::Interpolator: interpolates/resolves references
140 *
141 * WORK
142 * x move data transparently around between these stages
143 *
144 * TOOLS
145 *
146 * x Overview - Packages, Handlers and Stages:
147 * This is weird. ;-)
148 * - A Package can be instantiated by its namespaced classname
149 * e.g.: "mkObject('My::Package');"
150 * - A Package can be a Handler for Data::Driver::Proxy
151 * - A Handler implements exactly one Stage
152 * - Data::Driver::Proxy itself embeds these Stages:
153 * x php4-session
154 * x rdbms-table
155 * - An example Handler is Data::Driver::RPC::Remote
156 *
157 * x Handlers:
158 * x Data::Driver::RPC::Remote
159 * Interacts with a RPC::XML server (todo: talk SOAP!)
160 * using PEAR::XML::RPC.
161 * It can cache data for "disconnected mode" using the
162 * o Data::Driver::phpHtmlLib
163 * o Data::Driver::PEAR::DB
164 * x Data::Driver::PEAR::Tree (via Data::Lift)
165 *
166 */
167
168 /**
169 * An attempt to implement some software design patterns...
170 * --- RemoteProxyPattern
171 *
172 * @link http://c2.com/cgi-bin/wiki?ProxyPattern
173 *
174 * @author Andreas Motl <andreas.motl@ilo.de>
175 * @link http://www.netfrag.org/~joko/
176 *
177 * @copyright (c) 2003 - All Rights reserved.
178 * @license GNU LGPL (GNU Lesser General Public License)
179 * @link http://www.gnu.org/licenses/lgpl.txt
180 *
181 * @package org.netfrag.glib
182 * @name DesignPattern::RemoteProxy
183 *
184 */
185
186 /**
187 * @todo
188 * <pre>
189 * x extend options to en-/disable caching via a) session and/or b) database
190 * o make feature available via runtime setter-method to these options
191 * o use PEAR::Cache for caching purposes!!!
192 * o refactor database access: use PEAR for this! no more 'connectdb' here!!!
193 * o make database connection more flexible to make possible
194 * to have different (probably named) proxy databases (besides a "main database")
195 * o rename this to Data::Proxy? or split into Data::Query, Data::Result and Data::Wrapper?
196 * </pre>
197 *
198 */
199
200 /**
201 * Load required modules:
202 *
203 */
204 loadModule('DesignPattern::Proxy');
205
206 class DesignPattern_RemoteProxy extends DesignPattern_Proxy {
207
208 var $objectId;
209 // purpose ...
210 var $meta;
211 var $payload;
212 var $attributes;
213 var $backend;
214
215 function DesignPattern_RemoteProxy($objectId = "", $options = array() ) {
216 logp(get_class($this) . "->new()", PEAR_LOG_INFO);
217 global $proxy;
218
219 // 2003-03-05 - modified constructor
220 // expand objectId
221 if (is_array($objectId)) {
222 $options = $objectId[1];
223 $objectId = $objectId[0];
224 }
225
226 // trace
227 //print Dumper($objectId, $options);
228
229 // initialization/startup
230 $this->_init_meta_options($objectId, $options);
231 $this->_init_caching();
232 $this->_init_load();
233
234 //print Dumper($this);
235
236 }
237
238 function _init_meta_options( $objectId="", $options = array() ) {
239 $this->meta = $options;
240
241 if ($objectId) {
242 $this->objectId = $objectId;
243
244 // set default load mechanism
245 if ( $this->meta[remote] && ((!$this->meta[oid] && !$this->meta[guid]) || ($this->meta[oid] && $this->meta[guid])) && (!$this->meta[key]) ) {
246 $this->meta[oid] = 1;
247 }
248
249 }
250 }
251
252 function _init_caching() {
253
254 if ($this->meta[cache][session]) {
255 session_register_safe("proxy");
256 }
257
258 if ($this->meta[remote]) {
259 //$this->backend = mkObject('Data::Driver::RPC::Remote', $this->meta[rpcinfo]);
260 $this->backend = php::mkComponent('DataSource::Proxy::XMLRPC', $this->meta[rpcinfo]);
261 }
262 }
263
264 function _init_load() {
265 if ($this->objectId) {
266 $this->load();
267 //$this->_saveProxy();
268 }
269 }
270
271
272 function load() {
273 logp(get_class($this) . "->load()", PEAR_LOG_INFO);
274 if (!$this->_loadState()) {
275 if (!$this->_loadProxy()) {
276
277 // just load object from remote side if its flagged to be a remote one ...
278 if ($this->meta[remote]) {
279 $this->_loadRemote();
280 }
281
282 }
283 }
284 }
285
286 function save($data, $type) {
287 $this->_setAttributes($data);
288 $this->_saveState();
289 if ($type == 'commit') {
290 $this->_commit();
291 }
292 if ($type == 'create') {
293 $this->_create();
294 }
295 }
296
297 function flush() {
298 $this->flushState();
299 $this->flushProxy();
300 }
301
302 function _commit() {
303 $this->_saveBackend($this->attributes);
304 $this->flushState();
305 $this->flushProxy();
306 }
307
308
309 // TODO: make this work
310 /*
311 function _create() {
312 $this->_createBackend($this->attributes);
313 $this->flushState();
314 $this->flushProxy();
315 }
316 */
317
318 function getResult() {
319 if (!$this->meta[decoded]) {
320 $this->_decode();
321 $this->_saveState();
322 }
323 return $this->attributes;
324 }
325
326 function _setAttributes($data) {
327 $this->attributes = $data;
328 }
329
330 function flushProxy() {
331 connectdb();
332 $sql = "DELETE FROM f_proxy WHERE oid='$this->objectId'";
333 send_sql($sql);
334 }
335
336 function flushState() {
337 global $proxy;
338 unset($proxy[$this->objectId]);
339 $this->meta[decoded] = 0;
340 }
341
342 function _loadState() {
343 global $proxy;
344
345 // trace
346 //print Dumper($this);
347
348 // debug
349 logp(get_class($this) . "->_loadState()");
350
351 if ($this->attributes = $proxy[$this->objectId]) {
352 //print "_loadState:" . dumpVar($this->attributes);
353 $this->meta[decoded] = 1;
354 // TODO: make a parameter from this (0 deactivates session-layer)
355 return 0;
356 }
357 }
358
359 function _saveState() {
360 global $proxy;
361 logp(get_class($this) . "->_saveState()");
362 $proxy[$this->objectId] = $this->attributes;
363 //print "_saveState: " . dumpVar($this->attributes);
364 // TODO: throw exception-message back to user if operation fails
365 }
366
367 function _loadProxy() {
368
369 // FIXME!
370 if (!$this->meta[cache][db]) { return; }
371
372 // trace & debug
373 //print Dumper($this);
374 logp(get_class($this) . "->_loadProxy()");
375
376 connectdb();
377 $sql = "SELECT payload FROM f_proxy WHERE oid='$this->objectId'";
378 if ($res = send_sql($sql)) {
379 $row = mysql_fetch_array($res, MYSQL_ASSOC);
380 if ($row) {
381 $this->payload = $row[payload];
382 // TODO: make a parameter from this (0 deactivates mysqldb-layer)
383 return 0;
384 }
385 }
386 }
387
388 // TODO: use PEAR here
389 function _saveProxy() {
390
391 // FIXME!
392 if (!$this->meta[cache][db]) { return; }
393
394 logp(get_class($this) . "->_saveProxy()");
395 connectdb();
396 if ($this->payload) {
397 //$sql = "INSERT INTO f_proxy SET payload='$this->payload' WHERE oid='$this->objectId'";
398 $sql = "INSERT INTO f_proxy SET oid='$this->objectId', payload='$this->payload'";
399 if (!send_sql($sql)) {
400 $sql = "UPDATE f_proxy SET payload='$this->payload' WHERE oid='$this->objectId'";
401 send_sql($sql);
402 }
403 }
404 }
405
406 function _loadRemote() {
407 logp(get_class($this) . "->_loadRemote()");
408
409 // trace
410 //print Dumper($this->meta);
411
412 // TODO: test backend for reachability first (eventually cache this information and "reset" it by another party)
413
414 // 1. check backend-handle
415 if (!$this->backend) {
416 logp(get_class($this) . "->_loadRemote: no backend handle, please check argument 'rpcinfo'", PEAR_LOG_CRIT);
417 return;
418 }
419
420 // determine backend action by metadata
421 // check for guid or oid
422 if ($this->meta[guid]) {
423 if (!$this->objectId) {
424 logp(get_class($this) . "->_loadRemote: argument 'guid' requires valid objectId", PEAR_LOG_WARNING);
425 return;
426 }
427 if (!$this->meta[classname]) {
428 logp(get_class($this) . "->_loadRemote: argument 'guid' requires 'classname'", PEAR_LOG_WARNING);
429 return;
430 }
431 $args = array( guid => $this->objectId, classname => $this->meta[classname] );
432 $result = $this->backend->send('getObjectByGuid', $args );
433
434 } elseif ($this->meta[oid]) {
435 if (!$this->objectId) {
436 logp(get_class($this) . "->_loadRemote: argument 'oid' requires valid objectId", PEAR_LOG_WARNING);
437 return;
438 }
439 $result = $this->backend->send('getObject', $this->objectId);
440
441 } elseif ($this->meta[key]) {
442 if (!$this->meta[command]) {
443 logp(get_class($this) . "->_loadRemote: argument 'key' requires 'command'", PEAR_LOG_WARNING);
444 return;
445 }
446 /*
447 if (!$this->meta[query]) {
448 logp(get_class($this) . "->_loadRemote: argument 'key' requires 'query'", PEAR_LOG_WARNING);
449 return;
450 }
451 */
452 $result = $this->backend->send($this->meta[command], $this->meta[query]);
453
454 }
455
456
457
458 if ($result) {
459 //print "result: " . dumpVar($result) . "<br>";
460 if (count($result) == 0) { return; }
461
462 // FIXME: this is dangerous!
463 if ($_GET[debug]) {
464 print Dumper($result);
465 }
466
467 $this->payload = serialize($result);
468 // ----- move this to _encode some times
469
470 $this->_saveProxy();
471 //print "oid: $this->objectId<br>";
472 $this->flushState();
473 } else {
474 //print "Error in _loadRemote!!!<br>";
475 logp(get_class($this) . "->_loadRemote: error while trying to talk to remote side", PEAR_LOG_CRIT);
476 }
477
478 }
479
480 function _saveBackend($result) {
481 logp(get_class($this) . "->_saveBackend()");
482
483 //$encoder = new TextEncode($result);
484 //$encoder->toUTF8();
485
486 // check for guid or oid
487 if($this->meta[guid]) {
488 $args = array( 'guid' => $this->objectId, 'classname' => $this->meta[classname], 'data' => $result );
489 $response = $this->backend->send('saveObjectByGuid', $args, array( utf8 => 1) );
490 }
491 if($this->meta[oid]) {
492 $response = $this->backend->send('saveObject', array('oid' => $this->objectId, 'data' => $result), array( utf8 => 1) );
493 }
494 }
495
496 function _decode() {
497 // fill attributes-hashtable from message-hashtable
498 if (!$this->payload) { return; }
499 //if ($this->attributes = $backend->decodeData($this->payload)) {
500 if ($this->attributes = unserialize($this->payload)) {
501 $this->meta[decoded] = 1;
502 }
503 }
504
505 function store($struct) {
506 $this->payload = serialize($struct);
507 $this->_saveProxy();
508 }
509
510 }
511
512 ?>

MailToCvsAdmin">MailToCvsAdmin
ViewVC Help
Powered by ViewVC 1.1.26 RSS 2.0 feed