00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 include_once( "lib/ezxml/classes/ezxml.php" );
00042
00043 include_once( 'kernel/classes/datatypes/ezurl/ezurl.php' );
00044 include_once( 'lib/eztemplate/classes/eztemplateincludefunction.php' );
00045
00046 include_once( "lib/ezxml/classes/ezxml.php" );
00047
00048 if ( !class_exists( 'eZXMLSchema' ) )
00049 include_once( 'kernel/classes/datatypes/ezxmltext/ezxmlschema.php' );
00050
00051 class eZXMLOutputHandler
00052 {
00053
00054
00055
00056 function eZXMLOutputHandler( &$xmlData, $aliasedType, $contentObjectAttribute = null )
00057 {
00058 $this->XMLData =& $xmlData;
00059 $this->AliasedType = $aliasedType;
00060 $this->AliasedHandler = null;
00061
00062 if ( is_object( $contentObjectAttribute ) )
00063 {
00064 $this->ContentObjectAttribute =& $contentObjectAttribute;
00065 $this->ObjectAttributeID = $contentObjectAttribute->attribute( 'id' );
00066 }
00067
00068 $ini =& eZINI::instance( 'ezxml.ini' );
00069 if ( $ini->hasVariable( 'InputSettings', 'AllowMultipleSpaces' ) )
00070 {
00071 $allowMultipleSpaces = $ini->variable( 'InputSettings', 'AllowMultipleSpaces' );
00072 $this->AllowMultipleSpaces = $allowMultipleSpaces == 'true' ? true : false;
00073 }
00074 if ( $ini->hasVariable( 'InputSettings', 'AllowNumericEntities' ) )
00075 {
00076 $allowNumericEntities = $ini->variable( 'InputSettings', 'AllowNumericEntities' );
00077 $this->AllowNumericEntities = $allowNumericEntities == 'true' ? true : false;
00078 }
00079 }
00080
00081
00082
00083
00084 function attributes()
00085 {
00086 return array( 'output_text',
00087 'aliased_type',
00088 'aliased_handler',
00089 'view_template_name' );
00090 }
00091
00092
00093
00094
00095 function hasAttribute( $name )
00096 {
00097 return in_array( $name, $this->attributes() );
00098 }
00099
00100
00101
00102
00103 function &attribute( $name )
00104 {
00105 switch ( $name )
00106 {
00107 case 'output_text':
00108 {
00109 $retValue =& $this->outputText();
00110 } break;
00111 case 'aliased_type':
00112 {
00113 return $this->AliasedType;
00114 } break;
00115 case 'view_template_name':
00116 {
00117 $retValue =& $this->viewTemplateName();
00118 } break;
00119 case 'aliased_handler':
00120 {
00121 if ( $this->AliasedType !== false and
00122 $this->AliasHandler === null )
00123 {
00124 $this->AliasedHandler =& eZXMLText::inputHandler( $this->XMLData,
00125 $this->AliasedType,
00126 false,
00127 $this->ContentObjectAttribute );
00128 }
00129 return $this->AliasedHandler;
00130 } break;
00131 default:
00132 {
00133 eZDebug::writeError( "Attribute '$name' does not exist", 'eZXMLOutputHandler::attribute' );
00134 $retValue = null;
00135 } break;
00136 }
00137 return $retValue;
00138 }
00139
00140
00141
00142
00143 function &viewTemplateName()
00144 {
00145 $name = 'ezxmltext';
00146 $suffix = $this->viewTemplateSuffix();
00147 if ( $suffix !== false )
00148 $name .= '_' . $suffix;
00149 return $name;
00150 }
00151
00152
00153
00154
00155
00156
00157 function isValid()
00158 {
00159 return true;
00160 }
00161
00162
00163
00164
00165
00166 function &viewTemplateSuffix( &$contentobjectAttribute )
00167 {
00168 $suffix = false;
00169 return $suffix;
00170 }
00171
00172
00173
00174
00175 function xmlData()
00176 {
00177 return $this->XMLData;
00178 }
00179
00180
00181
00182
00183
00184 function &outputText()
00185 {
00186 if ( !$this->XMLData )
00187 {
00188 $output = '';
00189 return $output;
00190 }
00191
00192 $this->Tpl =& templateInit();
00193 $this->Res =& eZTemplateDesignResource::instance();
00194 if ( $this->ContentObjectAttribute )
00195 {
00196 $this->Res->setKeys( array( array( 'attribute_identifier', $this->ContentObjectAttribute->attribute( 'contentclass_attribute_identifier' ) ) ) );
00197 }
00198
00199 $xml = new eZXML();
00200 $this->Document =& $xml->domTree( $this->XMLData, array( "TrimWhiteSpace" => false, "SetParentNode" => true ) );
00201 if ( !$this->Document )
00202 {
00203 $this->Output = '';
00204 return $this->Output;
00205 }
00206
00207 $this->prefetch();
00208
00209 $this->XMLSchema =& eZXMLSchema::instance();
00210
00211
00212 foreach( $this->XMLSchema->availableElements() as $element )
00213 {
00214 if ( !isset( $this->OutputTags[$element] ) )
00215 $this->OutputTags[$element] = array();
00216 }
00217
00218 $this->NestingLevel = 0;
00219 $params = array();
00220
00221 $output = $this->outputTag( $this->Document->Root, $params );
00222 $this->Output = $output[1];
00223
00224 $this->Document->cleanup();
00225
00226 unset( $this->Document );
00227
00228 $this->Res->removeKey( 'attribute_identifier' );
00229 return $this->Output;
00230 }
00231
00232
00233 function prefetch()
00234 {
00235 $relatedObjectIDArray = array();
00236 $nodeIDArray = array();
00237
00238
00239 $links =& $this->Document->elementsByName( "link" );
00240
00241 if ( count( $links ) > 0 )
00242 {
00243 $linkIDArray = array();
00244
00245 foreach ( $links as $link )
00246 {
00247 $linkID = $link->attributeValue( 'url_id' );
00248 if ( $linkID && !in_array( $linkID, $linkIDArray ) )
00249 $linkIDArray[] = $linkID;
00250
00251 $objectID = $link->attributeValue( 'object_id' );
00252 if ( $objectID && !in_array( $objectID, $relatedObjectIDArray ) )
00253 $relatedObjectIDArray[] = $objectID;
00254
00255 $nodeID = $link->attributeValue( 'node_id' );
00256 if ( $nodeID && !in_array( $nodeID, $nodeIDArray ) )
00257 $nodeIDArray[] = $nodeID;
00258 }
00259
00260 if ( count( $linkIDArray ) > 0 )
00261 {
00262 $inIDSQL = implode( ', ', $linkIDArray );
00263
00264 $db =& eZDB::instance();
00265 $linkArray = $db->arrayQuery( "SELECT * FROM ezurl WHERE id IN ( $inIDSQL ) " );
00266
00267 foreach ( $linkArray as $linkRow )
00268 {
00269 $url = str_replace( "&", "&", $linkRow['url'] );
00270 $this->LinkArray[$linkRow['id']] = $url;
00271 }
00272 }
00273 }
00274
00275
00276 $objectArray =& $this->Document->elementsByName( "object" );
00277
00278 if ( count( $objectArray ) > 0 )
00279 {
00280 foreach ( $objectArray as $object )
00281 {
00282 $objectID = $object->attributeValue( 'id' );
00283 if ( $objectID != null && !in_array( $objectID, $relatedObjectIDArray ) )
00284 $relatedObjectIDArray[] = $objectID;
00285 }
00286 }
00287
00288 $embedTagArray =& $this->Document->elementsByName( "embed" );
00289 $embedInlineTagArray =& $this->Document->elementsByName( "embed-inline" );
00290
00291 $embedTags = array_merge( $embedTagArray, $embedInlineTagArray );
00292
00293 if ( count( $embedTags ) > 0 )
00294 {
00295 foreach ( $embedTags as $embedTag )
00296 {
00297 $objectID = $embedTag->attributeValue( 'object_id' );
00298 if ( $objectID && !in_array( $objectID, $relatedObjectIDArray ) )
00299 $relatedObjectIDArray[] = $objectID;
00300
00301 $nodeID = $embedTag->attributeValue( 'node_id' );
00302 if ( $nodeID && !in_array( $nodeID, $nodeIDArray ) )
00303 $nodeIDArray[] = $nodeID;
00304 }
00305 }
00306
00307 if ( $relatedObjectIDArray != null )
00308 $this->ObjectArray =& eZContentObject::fetchIDArray( $relatedObjectIDArray );
00309
00310 if ( $nodeIDArray != null )
00311 {
00312 $nodes = eZContentObjectTreeNode::fetch( $nodeIDArray );
00313
00314 if ( is_array( $nodes ) )
00315 {
00316 foreach( $nodes as $node )
00317 {
00318 $nodeID = $node->attribute( 'node_id' );
00319 $this->NodeArray["$nodeID"] = $node;
00320 }
00321 }
00322 elseif ( $nodes )
00323 {
00324 $node =& $nodes;
00325 $nodeID = $node->attribute( 'node_id' );
00326 $this->NodeArray["$nodeID"] = $node;
00327 }
00328 }
00329 }
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340 function outputTag( &$element, &$sibilingParams, $parentParams = array() )
00341 {
00342 $tagName = $element->nodeName;
00343 if ( isset( $this->OutputTags[$tagName] ) )
00344 {
00345 $currentTag =& $this->OutputTags[$tagName];
00346 }
00347 else
00348 $currentTag = null;
00349
00350
00351 $attributeNodes = $element->attributes();
00352 $attributes = array();
00353 foreach( $attributeNodes as $attrNode )
00354 {
00355 if ( $attrNode->Prefix && $attrNode->Prefix != 'custom' )
00356 $attrName = $attrNode->Prefix . ':' . $attrNode->LocalName;
00357 else
00358 $attrName = $attrNode->nodeName;
00359
00360
00361 if ( $attrName == 'class' )
00362 {
00363 $classesList = $this->XMLSchema->getClassesList( $tagName );
00364 if ( !in_array( $attrNode->value, $classesList ) )
00365 {
00366 eZDebug::writeWarning( "Using tag '$tagName' with class '$attrNode->value' is not allowed.", 'XML output handler' );
00367 return array( true, '' );
00368 }
00369 }
00370
00371 $attributes[$attrName] = $attrNode->value;
00372 }
00373
00374
00375 $attrDefaults = $this->XMLSchema->attrDefaultValues( $tagName );
00376 foreach( $attrDefaults as $name=>$value )
00377 {
00378 if ( !isset( $attributes[$name] ) )
00379 $attributes[$name] = $value;
00380 }
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393 $result = $this->callTagInitHandler( 'initHandler', $element, $attributes, $sibilingParams, $parentParams );
00394
00395
00396 $childrenOutput = array();
00397 if ( $element->hasChildNodes() )
00398 {
00399
00400
00401 $nextSibilingParams = array();
00402
00403 $this->NestingLevel++;
00404 foreach( array_keys( $element->Children ) as $key )
00405 {
00406 $child =& $element->Children[$key];
00407 $childOutput = $this->outputTag( $child, $nextSibilingParams, $parentParams );
00408
00409 if ( is_array( $childOutput[0] ) )
00410 $childrenOutput = array_merge( $childrenOutput, $childOutput );
00411 else
00412 $childrenOutput[] = $childOutput;
00413 }
00414 $this->NestingLevel--;
00415 }
00416 else
00417 {
00418 $childrenOutput = array( array( true, '' ) );
00419 }
00420
00421 if ( isset( $result['no_render'] ) && $result['no_render'] )
00422 {
00423 return $childrenOutput;
00424 }
00425
00426
00427 $vars = array();
00428
00429 if ( !isset( $currentTag['quickRender'] ) && isset( $currentTag['attrNamesTemplate'] ) )
00430 $attrRenameRules =& $currentTag['attrNamesTemplate'];
00431 elseif ( isset( $currentTag['quickRender'] ) && isset( $currentTag['attrNamesQuick'] ) )
00432 $attrRenameRules =& $currentTag['attrNamesQuick'];
00433 else
00434 $attrRenameRules = array();
00435
00436 foreach( $attributes as $name=>$value )
00437 {
00438 if ( isset( $attrRenameRules[$name] ) )
00439 {
00440 $vars[$attrRenameRules[$name]] = $value;
00441 continue;
00442 }
00443
00444 if ( substr( $name, 0, 6 ) == 'custom:' )
00445 $name = substr( $name, strpos( $name, ':' ) + 1 );
00446
00447 $vars[$name] = $value;
00448 }
00449
00450
00451
00452 foreach( $attrRenameRules as $attrName=>$varName )
00453 {
00454 if ( !isset( $attributes[$attrName] ) )
00455 $vars[$varName] = '';
00456 }
00457
00458 $this->TemplateUri = '';
00459
00460
00461
00462 if ( !isset( $currentTag['quickRender'] ) )
00463 {
00464
00465 if ( isset( $result['tpl_vars'] ) )
00466 {
00467 $vars = array_merge( $vars, $result['tpl_vars'] );
00468 }
00469
00470 foreach( $vars as $name=>$value )
00471 {
00472 $this->Tpl->setVariable( $name, $value, 'xmltagns' );
00473 }
00474
00475
00476 $designKeys = array();
00477 if ( isset( $currentTag['attrDesignKeys'] ) )
00478 {
00479 foreach( $currentTag['attrDesignKeys'] as $attrName=>$keyName )
00480 {
00481 if ( isset( $attributes[$attrName] ) && $attributes[$attrName] )
00482 $designKeys[$keyName] = $attributes[$attrName];
00483 }
00484 }
00485
00486 if ( isset( $result['design_keys'] ) )
00487 {
00488 $designKeys = array_merge( $designKeys, $result['design_keys'] );
00489 }
00490
00491 $existingKeys = $this->Res->keys();
00492 $savedKeys = array();
00493
00494
00495 foreach( $designKeys as $key=>$value )
00496 {
00497 if ( isset( $existingKeys[$key] ) )
00498 {
00499 $savedKeys[$key] = $existingKeys[$key];
00500 }
00501 $this->Res->setKeys( array( array( $key, $value ) ) );
00502 }
00503
00504
00505 if ( isset( $result['template_name'] ) )
00506 {
00507 $templateName = $result['template_name'];
00508 }
00509 else
00510 {
00511 $templateName = $element->nodeName;
00512 }
00513 $this->TemplateUri = $this->TemplatesPath . $templateName . '.tpl';
00514 }
00515
00516 $output = $this->callTagRenderHandler( 'renderHandler', $element, $childrenOutput, $vars );
00517
00518 if ( !isset( $currentTag['quickRender'] ) )
00519 {
00520
00521 foreach( $designKeys as $key=>$value )
00522 {
00523 if ( isset( $savedKeys[$key] ) )
00524 $this->Res->setKeys( array( array( $key, $savedKeys[$key] ) ) );
00525 else
00526 $this->Res->removeKey( $key );
00527 }
00528
00529
00530 foreach( $vars as $name=>$value )
00531 {
00532 if ( $this->Tpl->hasVariable( $name, 'xmltagns' ) )
00533 $this->Tpl->unsetVariable( $name, 'xmltagns' );
00534 }
00535 }
00536
00537 return $output;
00538 }
00539
00540 function renderTag( &$element, $content, $vars )
00541 {
00542 $currentTag =& $this->OutputTags[$element->nodeName];
00543 if ( $currentTag && isset( $currentTag['quickRender'] ) )
00544 {
00545 $renderedTag = '';
00546 $attrString = '';
00547 foreach( $vars as $name=>$value )
00548 {
00549 if ( $value != '' )
00550 $attrString .= " $name=\"$value\"";
00551 }
00552
00553 if ( isset( $currentTag['quickRender'][0] ) && $currentTag['quickRender'][0] )
00554 $renderedTag = '<' . $currentTag['quickRender'][0] . "$attrString>" . $content . '</' . $currentTag['quickRender'][0] . '>';
00555 else
00556 $renderedTag = $content;
00557
00558 if ( isset( $currentTag['quickRender'][1] ) && $currentTag['quickRender'][1] )
00559 $renderedTag .= $currentTag['quickRender'][1];
00560 }
00561 else
00562 {
00563 if ( isset( $currentTag['contentVarName'] ) )
00564 $contentVarName = $currentTag['contentVarName'];
00565 else
00566 $contentVarName = 'content';
00567
00568 $this->Tpl->setVariable( $contentVarName, $content, 'xmltagns' );
00569 eZTemplateIncludeFunction::handleInclude( $textElements, $this->TemplateUri, $this->Tpl, 'foo', 'xmltagns' );
00570 $renderedTag = is_array( $textElements ) ? implode( '', $textElements ) : '';
00571 }
00572 return $renderedTag;
00573 }
00574
00575
00576
00577 function renderAll( &$element, $childrenOutput, $vars )
00578 {
00579 $tagText = '';
00580 foreach( $childrenOutput as $childOutput )
00581 {
00582 $tagText .= $childOutput[1];
00583 }
00584 $tagText = $this->renderTag( $element, $tagText, $vars );
00585 return array( false, $tagText );
00586 }
00587
00588 function callTagInitHandler( $handlerName, &$element, &$attributes, &$sibilingParams, &$parentParams )
00589 {
00590 $result = array();
00591 $thisOutputTag =& $this->OutputTags[$element->nodeName];
00592 if ( isset( $thisOutputTag[$handlerName] ) )
00593 {
00594 if ( is_callable( array( $this, $thisOutputTag[$handlerName] ) ) )
00595 eval( '$result = $this->' . $thisOutputTag[$handlerName] . '( $element, $attributes, $sibilingParams, $parentParams );' );
00596 }
00597 return $result;
00598 }
00599
00600 function callTagRenderHandler( $handlerName, &$element, $childrenOutput, $vars )
00601 {
00602 $result = array();
00603 $thisOutputTag =& $this->OutputTags[$element->nodeName];
00604 if ( isset( $thisOutputTag[$handlerName] ) )
00605 $handlerFunction = $thisOutputTag[$handlerName];
00606 else
00607 $handlerFunction = 'renderAll';
00608
00609 if ( is_callable( array( $this, $handlerFunction ) ) )
00610 eval( '$result = $this->' . $handlerFunction . '( $element, $childrenOutput, $vars );' );
00611 else
00612 eZDebug::writeWarning( "'$handlerName' render handler for tag <$element->nodeName> doesn't exist: '" . $thisOutputTag[$handlerName] . "'.", 'eZXML converter' );
00613 return $result;
00614 }
00615
00616
00617
00618 var $OutputTags = array();
00619
00620
00621 var $TemplatesPath = 'design:content/datatype/view/ezxmltags/';
00622
00623
00624 var $XMLData;
00625 var $Document;
00626
00627 var $XMLSchema;
00628
00629 var $AliasedType;
00630 var $AliasedHandler;
00631
00632 var $Output = '';
00633 var $Tpl;
00634 var $TemplateURI = '';
00635 var $Res;
00636
00637 var $AllowMultipleSpaces = false;
00638 var $AllowNumericEntities = false;
00639
00640 var $ContentObjectAttribute;
00641 var $ObjectAttributeID;
00642
00643
00644 var $LinkArray = array();
00645
00646 var $ObjectArray = array();
00647
00648 var $NodeArray = array();
00649
00650 var $NestingLevel = 0;
00651 }
00652
00653 ?>