Documentation automatically generated from the source-code using phpDocumentor.
Official Homepage: xao-php.sourceforge.net
XAO
Official homepage | API home | class tree: XAO | index: XAO | all elements

Source for file XAO_AppDoc.php

Documentation is available at XAO_AppDoc.php


1 <?php
2 /**
3 * XAO_AppDoc.php
4 *
5 * This script provides the class definition for AppDoc. AppDoc
6 * creates the framework for XAO to be used in framwork mode. AppDoc inherits
7 * DomDoc and AppDoc is intended to be inherited by the end user
8 * - to provide the
9 * user with an "Application Object" that is customised by them. See the doc
10 * comments directly preceeding the class declaration for more information.
11 * It is advisable to consult the tutorials shipped with XAO to obtain an
12 * understanding of how this class is to be used.
13 *
14 * @author Terence Kearns
15 * @version 1.0 alpha
16 * @copyright Terence Kearns 2003
17 * @license LGPL (see http://www.gnu.org/licenses/lgpl.txt )
18 * @link http://xao-php.sourceforge.net
19 * @package XAO
20 * @see class DomDoc
21 */
22
23 /**
24 * Import XAO base class - DomDoc
25 *
26 * The AppDoc framework is extends DomDoc which extends XaoRoot.
27 *
28 * @import Transformer
30 */
31 include_once "XAO_DomDoc.php";
32
33 /**
34 * Import Transformer class for use by association
35 *
36 * This class encapsulates all XSLT functionality.
37 *
38 * @import Transformer
39 */
40 include_once "XAO_Transformer.php";
41
42 /**
43 * XML Application Object
44 *
45 * AppDoc is the "Application Object" part of the XAO acronym. It represents the
46 * "Application Document" in the context of XML being a document. So the contents
47 * delivered to the user by the "Application" is contentained in the "Document"
48 * held as a DOM XML document by AppDoc::objDoc. the objDoc property is inherited
49 * from the DomDoc class. The AppDoc class provides extra functionality on
50 * DomDoc that is specifically needed for typical "framework mode" usage of XAO.
51 * Usage of this class assumes that the user will be employing XAO in framework
52 * mode. In short, this is the framework class for XAO. It is advisable to
53 * consult the tutorials shipped with XAO to obtain an understanding of how this
54 * class is intended to be used.
55 *
56 * @package XAO
57 */
58 class AppDoc extends DomDoc {
59
60 /**
61 * Cache parameters for the XSLT tranformation result
62 *
63 * In the standard XAO framework, caching can be done at two stages. The
64 * first is at the content generation stage which uses $arrDocCacheParams,
65 * the second is at the transformation results stage which uses this array.
66 * The array has the same requirements and is used in exactly the same way
67 * as the $arrDocCacheParams array. It is passed to the Transformer class
68 * (by $this->Transform method) which then uses CacheMan to implement it.
69 * Also see doc comments at XaoRoot::arrCacheParams for more info.
70 *
71 * @access public
72 * @var array
73 */
74 var $arrXsltCacheParams = array();
75
76 /**
77 * Stylesheet parameters
78 *
79 * See documentation in the Transformer class on the variable with the
80 * same name.
81 *
82 * @access public
83 * @var array
84 */
85 var $arrXslParams = array();
86
87 /**
88 * Storage slot for alternative payload
89 *
90 * If this variable is populated, then this is all that is sent to the UA
91 * via the AppDoc::Send method. If it is left empty, then the AppDoc::Send
92 * method will send the serialised content of DomDoc::objDoc
93 * This method is provided as a method of short-circuiting the default
94 * behavior of AppDocc::Send - thereby allowing AppDoc::Send to be the
95 * single/only way for which the payload is transmitted. This is very
96 * important because it allows XAO framework to sentralise control script
97 * completion and payload transmission.
98 * An example of where an alternate payload is needed is an XSLT
99 * transformation result. Other instances, where the well-formedness of a
100 * payload cannot be garenteed, will also require the use of this string
101 * variable.
102 *
103 * @access public
104 * @var string
105 */
106 var $strAltPayload = false;
107
108 /**
109 * Debug data used when $this->blnDebug option is set to true
110 *
111 * This variable will contain extra diagnostic information as well as
112 * standard errors under certain circumstances. It is only outputted if
113 * $this->blnDebug is set.
114 *
115 * @access private
116 * @var string
117 */
118 var $_strDebugData;
119
120 /**
121 * Force client-side XSL Transformation attempt.
122 *
123 * This causes the TransformSend() method to bypass server-side
124 * transformation and send the source document directly to the client. If
125 * the stylsheet PI is set, then the client should find it and perform it's
126 * own transformation.
127 *
128 * @access public
129 * @var boolean
130 */
131 var $blnClientSideTransform = false;
132
133 /**
134 * Dedicated Error output display template
135 *
136 * Under certain conditions, the availability of a dedicated error template
137 * will cause an exceptional condition to output the error DOM object (with
138 * all it's errors so far) using the same rules as $this->Send(). An example
139 * is the Transform object which uses it when $this->blnDebug is turned off.
140 * If no dedicated error stylsheet is supplied, then it behaves differently.
141 * It is empty by default in case it proposes any security issues.
142 *
143 * @access public
144 * @var uri
145 */
146 var $uriErrorStyle;
147
148 /**
149 * Internal error style for debug output
150 *
151 * When $this->blnDebug is enabled, then the error document is appended
152 * using this a transformation with this error stylsheet. THIS IS NOT
153 * IMPLEMENTED AT THE MOMENT. IT MAY NEVER BE.
154 *
155 * @access private
156 * @var uri
157 */
158 var $_uriXaoErrorStyle = "XAO_errors.xsl";
159
160 /**
161 * Debug option
162 *
163 * Designed to be used during development, this object will cause error
164 * output to be more verbose unser certain conditions. It may also be used
165 * by the developer to output diagnostic information at run-time. It is kept
166 * off by default in case it proposes any security issues.
167 *
168 * @access public
169 * @var boolean
170 */
171 var $blnDebug = false;
172
173 /**
174 * Debug option
175 *
176 * Designed to be used during development, this object will cause error
177 * output to be more verbose unser certain conditions. It may also be used
178 * by the developer to output diagnostic information at run-time. It is kept
179 * off by default in case it proposes any security issues.
180 *
181 * @access public
182 * @var boolean
183 */
184 var $strForceContentType;
185
186 /**
187 * Current stylesheet URI
188 *
189 * This represents the current stylesheet that is used by this DomDoc.
190 * If a user overrides the $_uriStyleSheet member variable with a populated
191 * version, this->ndSetStylePI() is called with it in the contructor.
192 *
193 * @access private
194 * @var uri
195 */
196 var $_uriStyleSheet;
197
198 /**
199 * Stylesheet processing instruction node
200 *
201 * This is the node object representing the stylesheet PI. It is set using
202 * the ndSetStylePI() method which only matains one PI node for the
203 * stylesheet. If a user overrides the $_uriStyleSheet member variable with
204 * a populated version, this ndSetStylePI() is called with it in the
205 * contructor.
206 *
207 * @access public
208 * @var node
209 */
210 var $ndStylePi;
211
212 /**
213 * Which XSLT processor to use
214 *
215 * This option allows the user to choose which implemented XSLT processor
216 * to employ. At this stage, possible choices are:
217 * - SABLOTRON which uses the xslt_ functions built into PHP.
218 * - DOMXML which uses the experimental transformation capabilities of the
219 * native PHP domxml extension itself.
220 * Future implementations could use external procesors which may be Java,
221 * Com, or command-line executables.
222 *
223 * @access public
224 * @var string
225 */
226 var $strXsltProcessor = "DOMXML";
227
228 /**
229 * Stylesheet native PHP DOM XML object
230 *
231 * This variable is populated if the specified stylsheet is successfully
232 * opened as an XML document.
233 *
234 * @access public
235 * @var object
236 */
237 var $objXsl;
238
239 /**
240 * AppDoc constructor
241 *
242 * This method runs the parent constructor and sets up the xao namespace.
243 * There is no way to detect if a namespace declaration exists
244 * (to prevent duplicates). At the moment, one is inserted regardless!!!
245 * This is absolutely neccesary due to their usage by exceptions.
246 * WARNING::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
247 * THIS MEANS THAT YOU CANNOT IMPORT EXISTING XML FILES WHICH HAVE A
248 * THE NAMESPACE xmlns:xao ALREADY DECLARED IN THE ROOT ELEMENT.
249 * The current DOMXML extension allows multiple attributes of the same name
250 * to be inserted (not good). It's namespace functions don't allow a
251 * [non-default] namespace declaration to be inserted without changing the
252 * prefix of the tag in context - so we're forced to use the dubious
253 * "set_attribute()" method instead.
254 *
255 * @param mixed starting data
256 * @param integer how to use the staring data
257 * @return void
258 * @access public
259 */
260 function AppDoc(&$mxdStarter,$intUse = XAO_DOC_NEW) {
261 $this->DomDoc($mxdStarter,$intUse);
262 // automatically inject the XAO
263 // namespace into the document root
264 /*
265 */
266
267 if(is_object($this->ndRoot)) {
268 $this->ndRoot->set_attribute(
269 "xmlns:".$this->strXaoNamespacePrefix,
270 $this->
271 idXaoNamespace );
272 }
273 }
274
275 /**
276 * Insert stylesheet processing instruction
277 *
278 * This processing instruction is used by the transform() method if a
279 * stylesheet URI is not specifically provided to it. This method will
280 * automatically be called in the constructor if the user overrides the
281 * $this->_uriStyleSheet member attribute. It may, however, be called at any
282 * time by the user. Only one xsl stylsheet PI is maintained in the
283 * document. If it was already set at the time of the call to this method,
284 * then the new stylsheet URI will _replace_ the one in the existing PI.
285 *
286 * @param uri path to XSL stylesheet
287 * @param boolean Whether or not to check(parse) the file.
288 * @return bool success
289 * @access public
290 */
291 function &ndSetStylePI($uriStyleSheet,$blnCheck = true) {
292 $this->_TestForConstuctor();
293 if($blnCheck) {
294 if(!file_exists($uriStyleSheet)) {
295 $this->Throw(
296 "ndSetStylePI: The stylsheet you specified: <strong>"
297 .$uriStyleSheet."</strong> does not exist. Set local file "
298 ."checking (parsing) to false in the second argument of "
299 ."DomDoc::ndSetStylePI() if the file exists remotely or "
300 ."you want to override checking.",
301 $this->arrSetErrFnc(__FUNCTION__,__LINE__),
302 true
303 );
304 return false;
305 }
306 }
307 $this->_uriStyleSheet = $uriStyleSheet;
308 $strPiCont = ' type="text/xsl" href="'.$this->_uriStyleSheet.'"';
309 $strPiTarget = 'xml-stylesheet';
310 $piStyle = $this->objDoc->create_processing_instruction(
311 $strPiTarget, $strPiCont
312 );
313 $this->_uriStyleSheet = str_replace("\\","/",$this->_uriStyleSheet);
314 if(!is_object($piStyle)) {
315 $this->Throw(
316 "ndSetStylePI: Unable to create processing instruction using "
317 ."target of ".$strPiTarget." and content of ".$strPiCont,
318 $this->arrSetErrFnc(__FUNCTION__,__LINE__),true
319 );
320 return false;
321 }
322 else{
323 // if one exists, replace it
324 if(is_object($this->ndStylePi)) {
325 $this->ndStylePi->replace_node($piStyle);
326 }
327 // otherwise create it
328 else {
329 $this->ndStylePi = $this->objDoc->insert_before(
330 $piStyle, $this->
331 ndRoot );
332 }
333 }
334 if(is_object($this->ndStylePi)) {
335 return $this->ndStylePi;
336 }
337 else {
338 return false;
339 }
340 }
341
342 /**
343 * Get the absolute system location of the internal error stylsheet.
344 *
345 * This method is needed to enforce a location that is relative to
346 * XAO_AppDoc.php and not the last file in the call stack. See notes on
347 * $this->SetInternalErrorStyle();
348 *
349 * @return uri Absolute path to internal error stylsheet.
350 * @access public
351 */
352 function uriGetInternalErrorStyle() {
353 $this->_TestForConstuctor();
354 return dirname(__FILE__)."/".$this->_uriXaoErrorStyle;
355 }
356
357 /**
358 * Set the name of the internal error stylsheet using in debug mode
359 *
360 * This shouldn't need to be changed. However, if it is not appropriate
361 * for your circumstances, you may change it. Bear in mind that the uri
362 * must be specified as a relative path to the physical location of the
363 * xao DomDoc.php file.
364 *
365 * @param uri Relative path to internal error stylesheet
366 * @return void
367 * @access public
368 */
369 function SetInternalErrorStyle($uri) {
370 $this->_uriXaoErrorStyle = $uri;
371 }
372
373
374 /**
375 * Prepares $this->strAltPayload with XSLT transformation result data
376 *
377 * This function is usually called just prior to $this->Send()
378 * It is used when XSLT tranformations are required. It short-circuits the
379 * behaviour of $this->Send by populating $this->strAltPayload the results
380 * of the transformation. Note that this method requires a cirtain amount of
381 * preparation work by the user - ie. a stylsheet must be set using
382 * $this->ndSetStylePi()
383 *
384 * @return void
385 * @access public
386 */
387 function Transform($arrCacheParams = null) {
388 $arrCacheParams = array();
389 $this->_TestForConstuctor();
390 // $this->strAltPayload is not modified
391 // if the browser is to transform the
392 // contents of $this->objDoc
393 if(!$this->blnClientSideTransform) {
394
395 // Associate a new transformer
396 $objXT =& new Transformer($this->objDoc,$this->_uriStyleSheet);
397 // pass on transform properties
398 $objXT->strXsltProcessor = $this->strXsltProcessor;
399 $objXT->strXaoNamespacePrefix = $this->strXaoNamespacePrefix;
400 $objXT->arrCacheParams = $this->arrXsltCacheParams;
401 $objXT->arrXslParams = $this->arrXslParams;
402 if(count($arrCacheParams)) $objXT->arrCacheParams = $arrCacheParams;
403
404 // set up namespaces in stylsheet
405 /*
406 can't do namespaces because there is no way to detect if a
407 namespace declaration exists (to prevent duplicates)
408 WARNING:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
409 THIS MEANS THAT YOU HAVE TO DECLARE THE xao NAMESPACE YOURSELF
410 (MANUALLY) IN ALL YOUR STYLESHEET (IF YOU WANT TO USE TEMPLATES
411 THAT MATCH ANY XAO STUFF LIKE xao:exceptions).
412 */
413
414 /*
415 if(isset($objXT->ndStyleRoot)) {
416 if(is_object($objXT->ndStyleRoot)) {
417 var_dump($objXT->ndStyleRoot->attributes());
418 die();
419 if(
420 // to do: This detection does not work.
421 !$objXT->ndStyleRoot->has_attribute(
422 "xmlns:".$this->strXaoNamespacePrefix
423 )
424 ) {
425 //var_dump($objXT->objStyle->dump_node($objXT->ndStyleRoot));
426 //die("<br />We did not detect the namespace.");
427 $objXT->ndStyleRoot->set_attribute(
428 "xmlns:".$this->strXaoNamespacePrefix,
429 $this->idXaoNamespace
430 );
431 }
432 }
433 }
434 */
435 // See if there were any problems
436 // reported by the Transfromer instance
437 if(strlen($objXT->strError)) {
438 $this->Throw(
439 $objXT->strError,
440 $this->arrSetErrFnc(__FUNCTION__,__LINE__)
441 );
442 }
443 else {
444 // perform the actual transformation and
445 // pass the results to
446 // $this->strAltPayload
447 if($objXT->Transform()) {
448 $this->strAltPayload = $objXT->strXsltResult;
449 if($this->blnDebug) {
450 global $_GET
451 if(isset($_GET["xao:XSL"])) {
452 $this->strAltPayload =
453 $objXT->objStyle->dump_mem(true);
454 }
455 }
456 }
457 else {
458 $this->Throw(
459 $objXT->strError,
460 $this->arrSetErrFnc(__FUNCTION__,__LINE__)
461 );
462 }
463 }
464 }
465 }
466
467
468 /**
469 * Send the serialised XML content of this object to the client
470 *
471 * This function will emit the contents of this XML document as a string to
472 * the user-agent. It checks to see if the option was set to bind the error
473 * data [built up from usage of $this->Throw()] to the content. It also
474 * signals the user agent to expect text in XML format.
475 * When XAO is used as a framework, then some sort of send
476 *
477 * @param string alternate payload which will be sent
478 * @access public
479 */
480 function Send($strAlt = "") {
481
482 $this->_TestForConstuctor();
483 // This method may well be the last one
484 // that is called by the host PHP script
485 // in which case, try and collect all
486 // user errors.
487 $this->_TrapErrors();
488
489 if(strlen($strAlt)) $this->strAltPayload = $strAlt;
490 // If this object is running in debug
491 // mode, then special XAO URL directives
492 // can be acted on.
493 if($this->blnDebug) {
494 global $_GET
495 // this debug directive causes a source
496 // dump of the XML content regardless of
497 // any alternate payload.
498 if(isset($_GET["xao:XML"])) {
499 //$this->strAltPayload = $this->xmlGetDoc();
500 header("Content-Type: text/plain");
501 die($this->xmlGetDoc());
502 }
503 elseif(isset($_GET["xao:Text"])) {
504 $this->strForceContentType = "text/plain";
505 }
506 }
507
508 if(strlen($this->strAltPayload)) {
509 if(strlen($this->strForceContentType))
510 header("Content-Type: ".$this->strForceContentType);
511 elseif(substr($this->strAltPayload,1,4) == "?xml")
512 header("Content-Type: text/xml");
513 echo $this->strAltPayload;
514 }
515 else {
516 if(strlen($this->strForceContentType))
517 header("Content-Type: ".$this->strForceContentType);
518 else
519 header("Content-Type: text/xml");
520 echo $this->xmlGetDoc();
521 }
522 }
523
524 /**
525 * Return data that would be destined for the client (in current state)
526 *
527 * This function is specific to AppDoc and not DomDoc because of the
528 * strAltPayload member attribute. This function can be used by the
529 * RpcController class if the user bases their request class on AppDoc. For
530 * instnace, they may want to take advantage of AppDoc's transform
531 * capabilities to convernt proprietary content into another format such
532 * as RSS.
533 *
534 * @return string
535 * @access public
536 */
537 function strGetPayload() {
538 if(strlen($this->strAltPayload) return $this->strAltPayload;
539 return $this->xmlGetDoc();
540 }
541
542 /**
543 * Wrapper for parent::throw() function adding ability to abort script
544 *
545 * This function basically calls the parent function of the same name but
546 * also allows the caller to optionally abort the script if the last
547 * argument is set to true.
548 *
549 * @param string Main error message
550 * @param array A hash of name/vals which will be attributes in the
551 * exception tag
552 * @access public
553 */
554 function Throw($strErrMsg,$arrAttribs = null,$blnDie = false) {
555 if(is_null($arrAttribs)) $arrAttribs = array();
556 parent::Throw($strErrMsg,$arrAttribs);
557 if($blnDie) die("<br />\n".$this->strError.$this->strDebugData);
558 }
559
560 /**
561 * Try to trap any user-triggered errors for handling by DomDoc::throw
562 *
563 * This function is a partial solution for general PHP error handling based
564 * on PHP's own error management capabilities. Unfortunately, PHP will only
565 * allow your error handling call-back function to process what it calls
566 * "USER" errors - errors that are triggered using the trigger_error() or
567 * user_error() functions. PHP does not let you manage PHP generated errors.
568 * Furthermore, this function is only useful when people use XAO in framework
569 * mode and neccesarily name their Application document object $objAppDoc
570 *
571 * @access private
572 */
573 function _TrapErrors() {
574 // this method is only useful if you
575 // name your Application document object
576 // $objAppDoc
577 global $objAppDoc
578 // custom error handler cannot be set
579 // from within an object. It also needs
580 // the handler to be a router to the
581 // application object (if found in the
582 // global scope).
583 if(is_object($objAppDoc)) {
584 set_error_handler("ErrorRouter");
585 }
586 }
587 } // END CLASS
588
589
590 /**
591 * Custom error handler function
592 *
593 * Normally everything in XAO adheres strictly to being coded as object oriented,
594 * however, since that's not how PHP was designed, exceptions have to be made.
595 * The following function is referred to by the AppDoc::_TrapErrors() method
596 * as specified by the set_error_handler("ErrorRouter") function. The call-back
597 * specified in set_error_handler() is not able to exist inside a class
598 * definition if it is to work as intended with PHPs custom error handling. It
599 * is only effective if the user instantiates $objAppDoc as part of a
600 * conventional XAO methodology.
601 *
602 * @param string error code
603 * @param string error message
604 * @param string error location of context script
605 * @param integer line number of context script
606 * @param array any arguments involved in an errored function
607 * @access private
608 */
609 function ErrorRouter($strErrCode, $strErrMsg, $uriContext, $intLine, $mxdArgs) {
610 // This is the sort of nonsense required
611 // by a non-oo approach.
612 global $objAppDoc
613
614 $arrAttribs = array(
615 "code" => $strErrCode,
616 "file" => $uriContext,
617 "line" => $intLine,
618 "context" => implode(",",$mxdArgs)
619 );
620 // ATM, error reports require an XML
621 // aware user-agent.
622 $objAppDoc->Throw($strErrMsg,$arrAttribs);
623 }
624 ?>

Documentation generated on Tue, 23 Sep 2003 18:33:53 +1000 by phpDocumentor 1.2.2