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

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