|
eZ Publish
[trunk]
|
00001 <?php 00002 /** 00003 * File containing the eZRSSExport class. 00004 * 00005 * @copyright Copyright (C) 1999-2012 eZ Systems AS. All rights reserved. 00006 * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2 00007 * @version //autogentag// 00008 * @package kernel 00009 */ 00010 00011 /*! 00012 \class eZRSSExport ezrssexport.php 00013 \brief Handles RSS Export in eZ Publish 00014 00015 RSSExport is used to create RSS feeds from published content. See kernel/rss for more files. 00016 */ 00017 00018 class eZRSSExport extends eZPersistentObject 00019 { 00020 const STATUS_VALID = 1; 00021 const STATUS_DRAFT = 0; 00022 00023 /*! 00024 Initializes a new RSSExport. 00025 */ 00026 function eZRSSExport( $row ) 00027 { 00028 $this->eZPersistentObject( $row ); 00029 } 00030 00031 static function definition() 00032 { 00033 return array( 'fields' => array( 'id' => array( 'name' => 'ID', 00034 'datatype' => 'integer', 00035 'default' => 0, 00036 'required' => true ), 00037 'node_id' => array( 'name' => 'NodeID', 00038 'datatype' => 'integer', 00039 'default' => 0, 00040 'required' => false ), 00041 'title' => array( 'name' => 'Title', 00042 'datatype' => 'string', 00043 'default' => ezpI18n::tr( 'kernel/rss', 'New RSS Export' ), 00044 'required' => true ), 00045 'url' => array( 'name' => 'URL', 00046 'datatype' => 'string', 00047 'default' => '', 00048 'required' => true ), 00049 'site_access' => array( 'name' => 'SiteAccess', 00050 'datatype' => 'string', 00051 'default' => '', 00052 'required' => true ), 00053 'modified' => array( 'name' => 'Modified', 00054 'datatype' => 'integer', 00055 'default' => 0, 00056 'required' => true ), 00057 'modifier_id' => array( 'name' => 'ModifierID', 00058 'datatype' => 'integer', 00059 'default' => 0, 00060 'required' => true, 00061 'foreign_class' => 'eZUser', 00062 'foreign_attribute' => 'contentobject_id', 00063 'multiplicity' => '1..*' ), 00064 'created' => array( 'name' => 'Created', 00065 'datatype' => 'integer', 00066 'default' => 0, 00067 'required' => true ), 00068 'creator_id' => array( 'name' => 'CreatorID', 00069 'datatype' => 'integer', 00070 'default' => 0, 00071 'required' => true, 00072 'foreign_class' => 'eZUser', 00073 'foreign_attribute' => 'contentobject_id', 00074 'multiplicity' => '1..*' ), 00075 'description' => array( 'name' => 'Description', 00076 'datatype' => 'string', 00077 'default' => '', 00078 'required' => false ), 00079 'image_id' => array( 'name' => 'ImageID', 00080 'datatype' => 'integer', 00081 'default' => 0, 00082 'required' => false ), 00083 'rss_version' => array( 'name' => 'RSSVersion', 00084 'datatype' => 'string', 00085 'default' => 0, 00086 'required' => true ), 00087 'active' => array( 'name' => 'Active', 00088 'datatype' => 'integer', 00089 'default' => 0, 00090 'required' => true ), 00091 'status' => array( 'name' => 'Status', 00092 'datatype' => 'integer', 00093 'default' => 0, 00094 'required' => true ), 00095 'access_url' => array( 'name' => 'AccessURL', 00096 'datatype' => 'string', 00097 'default' => 'rss_feed', 00098 'required' => false ), 00099 'number_of_objects' => array( 'name' => 'NumberOfObjects', 00100 'datatype' => 'integer', 00101 'default' => 0, 00102 'required' => true ), 00103 'main_node_only' => array( 'name' => 'MainNodeOnly', 00104 'datatype' => 'integer', 00105 'default' => 0, 00106 'required' => true ) ), 00107 'keys' => array( 'id', 'status' ), 00108 'function_attributes' => array( 'item_list' => 'itemList', 00109 'modifier' => 'modifier', 00110 'rss-xml' => 'rssXml', // deprecated 00111 'rss-xml-content' => 'rssXmlContent', // new attribute which uses the Feed component 00112 'image_path' => 'imagePath', 00113 'image_node' => 'imageNode' ), 00114 'increment_key' => 'id', 00115 'sort' => array( 'title' => 'asc' ), 00116 'class_name' => 'eZRSSExport', 00117 'name' => 'ezrss_export' ); 00118 00119 } 00120 00121 /*! 00122 \static 00123 Creates a new RSS Export 00124 \param User ID 00125 00126 \return the URL alias object 00127 */ 00128 static function create( $user_id ) 00129 { 00130 $config = eZINI::instance( 'site.ini' ); 00131 $dateTime = time(); 00132 $row = array( 'id' => null, 00133 'node_id', '', 00134 'title' => ezpI18n::tr( 'kernel/classes', 'New RSS Export' ), 00135 'site_access' => '', 00136 'modifier_id' => $user_id, 00137 'modified' => $dateTime, 00138 'creator_id' => $user_id, 00139 'created' => $dateTime, 00140 'status' => self::STATUS_DRAFT, 00141 'url' => 'http://'. $config->variable( 'SiteSettings', 'SiteURL' ), 00142 'description' => '', 00143 'image_id' => 0, 00144 'active' => 1, 00145 'access_url' => '' ); 00146 return new eZRSSExport( $row ); 00147 } 00148 00149 /*! 00150 Store Object to database 00151 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 00152 the calls within a db transaction; thus within db->begin and db->commit. 00153 */ 00154 function store( $storeAsValid = false ) 00155 { 00156 $dateTime = time(); 00157 $user = eZUser::currentUser(); 00158 if ( $this->ID == null ) 00159 { 00160 eZPersistentObject::store(); 00161 return; 00162 } 00163 00164 $db = eZDB::instance(); 00165 $db->begin(); 00166 if ( $storeAsValid ) 00167 { 00168 $oldStatus = $this->attribute( 'status' ); 00169 $this->setAttribute( 'status', eZRSSExport::STATUS_VALID ); 00170 } 00171 $this->setAttribute( 'modified', $dateTime ); 00172 $this->setAttribute( 'modifier_id', $user->attribute( "contentobject_id" ) ); 00173 eZPersistentObject::store(); 00174 $db->commit(); 00175 if ( $storeAsValid ) 00176 { 00177 $this->setAttribute( 'status', $oldStatus ); 00178 } 00179 } 00180 00181 /*! 00182 Remove the RSS Export. 00183 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 00184 the calls within a db transaction; thus within db->begin and db->commit. 00185 */ 00186 function removeThis() 00187 { 00188 $exportItems = $this->fetchItems(); 00189 00190 $db = eZDB::instance(); 00191 $db->begin(); 00192 foreach ( $exportItems as $item ) 00193 { 00194 $item->remove(); 00195 } 00196 eZPersistentObject::remove(); 00197 $db->commit(); 00198 } 00199 00200 /*! 00201 \static 00202 Fetches the RSS Export by ID. 00203 00204 \param RSS Export ID 00205 */ 00206 static function fetch( $id, $asObject = true, $status = eZRSSExport::STATUS_VALID ) 00207 { 00208 return eZPersistentObject::fetchObject( eZRSSExport::definition(), 00209 null, 00210 array( "id" => $id, 00211 'status' => $status ), 00212 $asObject ); 00213 } 00214 00215 /*! 00216 \static 00217 Fetches the RSS Export by feed access url and is active. 00218 00219 \param RSS Export access url 00220 */ 00221 static function fetchByName( $access_url, $asObject = true ) 00222 { 00223 return eZPersistentObject::fetchObject( eZRSSExport::definition(), 00224 null, 00225 array( 'access_url' => $access_url, 00226 'active' => 1, 00227 'status' => self::STATUS_VALID ), 00228 $asObject ); 00229 } 00230 00231 /*! 00232 \static 00233 Fetches complete list of RSS Exports. 00234 */ 00235 static function fetchList( $asObject = true ) 00236 { 00237 return eZPersistentObject::fetchObjectList( eZRSSExport::definition(), 00238 null, array( 'status' => self::STATUS_VALID ), null, null, 00239 $asObject ); 00240 } 00241 00242 function itemList() 00243 { 00244 return $this->fetchItems(); 00245 } 00246 00247 function imageNode() 00248 { 00249 if ( isset( $this->ImageID ) and $this->ImageID ) 00250 { 00251 return eZContentObjectTreeNode::fetch( $this->ImageID ); 00252 } 00253 return null; 00254 } 00255 00256 function imagePath() 00257 { 00258 if ( isset( $this->ImageID ) and $this->ImageID ) 00259 { 00260 $objectNode = eZContentObjectTreeNode::fetch( $this->ImageID ); 00261 if ( isset( $objectNode ) ) 00262 { 00263 $retValue = ''; 00264 $path_array = $objectNode->attribute( 'path_array' ); 00265 for ( $i = 0; $i < count( $path_array ); $i++ ) 00266 { 00267 $treenode = eZContentObjectTreeNode::fetch( $path_array[$i], false, false ); 00268 00269 if( $i != 0 ) 00270 { 00271 $retValue .= '/'; 00272 } 00273 00274 $retValue .= array_key_exists( 'name', $treenode ) ? $treenode['name'] : ''; 00275 } 00276 return $retValue; 00277 } 00278 } 00279 return null; 00280 00281 } 00282 00283 function modifier() 00284 { 00285 if ( isset( $this->ModifierID ) and $this->ModifierID ) 00286 { 00287 return eZUser::fetch( $this->ModifierID ); 00288 } 00289 return null; 00290 } 00291 00292 /** 00293 * Generates an RSS feed document based on the rss_version attribute. 00294 * 00295 * @deprecated since 4.2 00296 * @return DomDocument XML document 00297 */ 00298 function rssXml() 00299 { 00300 switch( $this->attribute( 'rss_version' ) ) 00301 { 00302 case '1.0': 00303 { 00304 return $this->fetchRSS1_0(); 00305 } break; 00306 00307 case '2.0': 00308 { 00309 return $this->fetchRSS2_0(); 00310 } break; 00311 00312 default: 00313 { 00314 return null; 00315 } break; 00316 } 00317 00318 return null; 00319 } 00320 00321 /** 00322 * Generates an RSS feed document based on the rss_version attribute. 00323 * 00324 * It uses the Feed component from eZ Components. 00325 * 00326 * Supported types: 'rss1', 'rss2', 'atom'. 00327 * 00328 * @since 4.2 00329 * @return string XML document as a string 00330 */ 00331 function rssXmlContent() 00332 { 00333 try 00334 { 00335 switch ( $this->attribute( 'rss_version' ) ) 00336 { 00337 case '1.0': 00338 { 00339 return $this->generateFeed( 'rss1' ); 00340 } break; 00341 00342 case '2.0': 00343 { 00344 return $this->generateFeed( 'rss2' ); 00345 } break; 00346 00347 case 'ATOM': 00348 { 00349 return $this->generateFeed( 'atom' ); 00350 } break; 00351 00352 default: 00353 { 00354 return null; 00355 } break; 00356 } 00357 } 00358 catch ( ezcFeedException $e ) 00359 { 00360 return '<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang=""><title>The RSS feed you were trying to access contains some errors and cannot be generated: ' . $e->getMessage() . ' Please contact the webmaster.</title></feed>'; 00361 } 00362 00363 return null; 00364 } 00365 00366 /*! 00367 Fetches RSS Items related to this RSS Export. The RSS Export Items contain information about which nodes to export information from 00368 00369 \param RSSExport ID (optional). Uses current RSSExport's ID as default 00370 00371 \return RSSExportItem list. null if no RSS Export items found 00372 */ 00373 function fetchItems( $id = false, $status = eZRSSExport::STATUS_VALID ) 00374 { 00375 if ( $id === false ) 00376 { 00377 if ( isset( $this ) ) 00378 { 00379 $id = $this->ID; 00380 $status = $this->Status; 00381 } 00382 else 00383 { 00384 $itemList = null; 00385 return $itemList; 00386 } 00387 } 00388 if ( $id !== null ) 00389 $itemList = eZRSSExportItem::fetchFilteredList( array( 'rssexport_id' => $id, 'status' => $status ) ); 00390 else 00391 $itemList = null; 00392 return $itemList; 00393 } 00394 00395 function getObjectListFilter() 00396 { 00397 if ( $this->MainNodeOnly == 1 ) 00398 { 00399 $this->MainNodeOnly = true; 00400 } 00401 else 00402 { 00403 $this->MainNodeOnly = false; 00404 } 00405 00406 return array( 'number_of_objects' => intval($this->NumberOfObjects), 00407 'main_node_only' => $this->MainNodeOnly 00408 ); 00409 } 00410 00411 /** 00412 * Get a RSS xml document based on the RSS 2.0 standard based on the RSS Export settings defined by this object 00413 * 00414 * @deprecated since 4.2 00415 * @return string RSS 2.0 XML document 00416 */ 00417 function fetchRSS2_0() 00418 { 00419 $locale = eZLocale::instance(); 00420 00421 // Get URL Translation settings. 00422 $config = eZINI::instance(); 00423 if ( $config->variable( 'URLTranslator', 'Translation' ) == 'enabled' ) 00424 { 00425 $useURLAlias = true; 00426 } 00427 else 00428 { 00429 $useURLAlias = false; 00430 } 00431 00432 if ( $this->attribute( 'url' ) == '' ) 00433 { 00434 $baseItemURL = ''; 00435 eZURI::transformURI( $baseItemURL, false, 'full' ); 00436 $baseItemURL .= '/'; 00437 } 00438 else 00439 { 00440 $baseItemURL = $this->attribute( 'url' ).'/'; //.$this->attribute( 'site_access' ).'/'; 00441 } 00442 00443 $doc = new DOMDocument( '1.0', 'utf-8' ); 00444 $doc->formatOutput = true; 00445 $root = $doc->createElement( 'rss' ); 00446 $root->setAttribute( 'version', '2.0' ); 00447 $root->setAttribute( 'xmlns:atom', 'http://www.w3.org/2005/Atom' ); 00448 $doc->appendChild( $root ); 00449 00450 $channel = $doc->createElement( 'channel' ); 00451 $root->appendChild( $channel ); 00452 00453 $atomLink = $doc->createElement( 'atom:link' ); 00454 $atomLink->setAttribute( 'href', $baseItemURL . "rss/feed/" . $this->attribute( 'access_url' ) ); 00455 $atomLink->setAttribute( 'rel', 'self' ); 00456 $atomLink->setAttribute( 'type', 'application/rss+xml' ); 00457 $channel->appendChild( $atomLink ); 00458 00459 $channelTitle = $doc->createElement( 'title' ); 00460 $channelTitle->appendChild( $doc->createTextNode( $this->attribute( 'title' ) ) ); 00461 $channel->appendChild( $channelTitle ); 00462 00463 $channelLink = $doc->createElement( 'link' ); 00464 $channelLink->appendChild( $doc->createTextNode( $this->attribute( 'url' ) ) ); 00465 $channel->appendChild( $channelLink ); 00466 00467 $channelDescription = $doc->createElement( 'description' ); 00468 $channelDescription->appendChild( $doc->createTextNode( $this->attribute( 'description' ) ) ); 00469 $channel->appendChild( $channelDescription ); 00470 00471 $channelLanguage = $doc->createElement( 'language' ); 00472 $channelLanguage->appendChild( $doc->createTextNode( $locale->httpLocaleCode() ) ); 00473 $channel->appendChild( $channelLanguage ); 00474 00475 $imageURL = $this->fetchImageURL(); 00476 if ( $imageURL !== false ) 00477 { 00478 $image = $doc->createElement( 'image' ); 00479 00480 $imageUrlNode = $doc->createElement( 'url' ); 00481 $imageUrlNode->appendChild( $doc->createTextNode( $imageURL ) ); 00482 $image->appendChild( $imageUrlNode ); 00483 00484 $imageTitle = $doc->createElement( 'title' ); 00485 $imageTitle->appendChild( $doc->createTextNode( $this->attribute( 'title' ) ) ); 00486 $image->appendChild( $imageTitle ); 00487 00488 $imageLink = $doc->createElement( 'link' ); 00489 $imageLink->appendChild( $doc->createTextNode( $this->attribute( 'url' ) ) ); 00490 $image->appendChild( $imageLink ); 00491 00492 $channel->appendChild( $image ); 00493 } 00494 00495 $cond = array( 00496 'rssexport_id' => $this->ID, 00497 'status' => $this->Status 00498 ); 00499 $rssSources = eZRSSExportItem::fetchFilteredList( $cond ); 00500 00501 $nodeArray = eZRSSExportItem::fetchNodeList( $rssSources, $this->getObjectListFilter() ); 00502 00503 if ( is_array( $nodeArray ) && count( $nodeArray ) ) 00504 { 00505 $attributeMappings = eZRSSExportItem::getAttributeMappings( $rssSources ); 00506 00507 foreach ( $nodeArray as $node ) 00508 { 00509 $object = $node->attribute( 'object' ); 00510 $dataMap = $object->dataMap(); 00511 if ( $useURLAlias === true ) 00512 { 00513 $nodeURL = $this->urlEncodePath( $baseItemURL . $node->urlAlias() ); 00514 } 00515 else 00516 { 00517 $nodeURL = $baseItemURL . 'content/view/full/' . $node->attribute( 'node_id' ); 00518 } 00519 00520 // keep track if there's any match 00521 $doesMatch = false; 00522 // start mapping the class attribute to the respective RSS field 00523 foreach ( $attributeMappings as $attributeMapping ) 00524 { 00525 // search for correct mapping by path 00526 if ( $attributeMapping[0]->attribute( 'class_id' ) == $object->attribute( 'contentclass_id' ) and 00527 in_array( $attributeMapping[0]->attribute( 'source_node_id' ), $node->attribute( 'path_array' ) ) ) 00528 { 00529 // found it 00530 $doesMatch = true; 00531 // now fetch the attributes 00532 $title = $dataMap[$attributeMapping[0]->attribute( 'title' )]; 00533 $description = $dataMap[$attributeMapping[0]->attribute( 'description' )]; 00534 // category is optional 00535 $catAttributeIdentifier = $attributeMapping[0]->attribute( 'category' ); 00536 $category = $catAttributeIdentifier ? $dataMap[$catAttributeIdentifier] : false; 00537 break; 00538 } 00539 } 00540 00541 if( !$doesMatch ) 00542 { 00543 // no match 00544 eZDebug::writeWarning( __METHOD__ . ': Cannot find matching RSS source node for content object in '.__FILE__.', Line '.__LINE__ ); 00545 $retValue = null; 00546 return $retValue; 00547 } 00548 00549 $item = $doc->createElement( 'item' ); 00550 00551 // title RSS element with respective class attribute content 00552 $titleContent = $title->attribute( 'content' ); 00553 if ( $titleContent instanceof eZXMLText ) 00554 { 00555 $outputHandler = $titleContent->attribute( 'output' ); 00556 $itemTitleText = $outputHandler->attribute( 'output_text' ); 00557 } 00558 else 00559 { 00560 $itemTitleText = $titleContent; 00561 } 00562 00563 $itemTitle = $doc->createElement( 'title' ); 00564 $itemTitle->appendChild( $doc->createTextNode( $itemTitleText ) ); 00565 $item->appendChild( $itemTitle ); 00566 00567 $itemLink = $doc->createElement( 'link' ); 00568 $itemLink->appendChild( $doc->createTextNode( $nodeURL ) ); 00569 $item->appendChild( $itemLink ); 00570 00571 $itemGuid = $doc->createElement( 'guid' ); 00572 $itemGuid->appendChild( $doc->createTextNode( $nodeURL ) ); 00573 $item->appendChild( $itemGuid ); 00574 00575 // description RSS element with respective class attribute content 00576 $descriptionContent = $description->attribute( 'content' ); 00577 if ( $descriptionContent instanceof eZXMLText ) 00578 { 00579 $outputHandler = $descriptionContent->attribute( 'output' ); 00580 $itemDescriptionText = $outputHandler->attribute( 'output_text' ); 00581 } 00582 else 00583 { 00584 $itemDescriptionText = $descriptionContent; 00585 } 00586 00587 $itemDescription = $doc->createElement( 'description' ); 00588 $itemDescription->appendChild( $doc->createTextNode( $itemDescriptionText ) ); 00589 $item->appendChild( $itemDescription ); 00590 00591 // category RSS element with respective class attribute content 00592 if ( $category ) 00593 { 00594 $categoryContent = $category->attribute( 'content' ); 00595 if ( $categoryContent instanceof eZXMLText ) 00596 { 00597 $outputHandler = $categoryContent->attribute( 'output' ); 00598 $itemCategoryText = $outputHandler->attribute( 'output_text' ); 00599 } 00600 elseif ( $categoryContent instanceof eZKeyword ) 00601 { 00602 $itemCategoryText = $categoryContent->keywordString(); 00603 } 00604 else 00605 { 00606 $itemCategoryText = $categoryContent; 00607 } 00608 00609 $itemCategory = $doc->createElement( 'category' ); 00610 $itemCategory->appendChild( $doc->createTextNode( $itemCategoryText ) ); 00611 $item->appendChild( $itemCategory ); 00612 } 00613 00614 $itemPubDate = $doc->createElement( 'pubDate' ); 00615 $itemPubDate->appendChild( $doc->createTextNode( gmdate( 'D, d M Y H:i:s', $object->attribute( 'published' ) ) .' GMT' ) ); 00616 00617 $item->appendChild( $itemPubDate ); 00618 00619 $channel->appendChild( $item ); 00620 } 00621 } 00622 00623 return $doc; 00624 } 00625 00626 /** 00627 * Get a RSS xml document based on the RSS 1.0 standard based on the RSS Export settings defined by this object 00628 * 00629 * @deprecated since 4.2 00630 * @return DomDocument RSS 1.0 XML document 00631 */ 00632 function fetchRSS1_0() 00633 { 00634 $imageURL = $this->fetchImageURL(); 00635 00636 // Get URL Translation settings. 00637 $config = eZINI::instance( 'site.ini' ); 00638 if ( $config->variable( 'URLTranslator', 'Translation' ) == 'enabled' ) 00639 { 00640 $useURLAlias = true; 00641 } 00642 else 00643 { 00644 $useURLAlias = false; 00645 } 00646 00647 if ( $this->attribute( 'url' ) == '' ) 00648 { 00649 $baseItemURL = ''; 00650 eZURI::transformURI( $baseItemURL, false, 'full' ); 00651 $baseItemURL .= '/'; 00652 } 00653 else 00654 { 00655 $baseItemURL = $this->attribute( 'url' ).'/'; //.$this->attribute( 'site_access' ).'/'; 00656 } 00657 00658 $doc = new DOMDocument( '1.0', 'utf-8' ); 00659 $root = $doc->createElementNS( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdf:RDF' ); 00660 $doc->appendChild( $root ); 00661 00662 $channel = $doc->createElementNS( 'http://purl.org/rss/1.0/', 'channel' ); 00663 $channel->setAttributeNS( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdf:about', $this->attribute( 'url' ) ); 00664 $root->appendChild( $channel ); 00665 00666 $channelTitle = $doc->createElement( 'title' ); 00667 $channelTitle->appendChild( $doc->createTextNode( $this->attribute( 'title' ) ) ); 00668 $channel->appendChild( $channelTitle ); 00669 00670 $channelUrl = $doc->createElement( 'link' ); 00671 $channelUrl->appendChild( $doc->createTextNode( $this->attribute( 'url' ) ) ); 00672 $channel->appendChild( $channelUrl ); 00673 00674 $channelDescription = $doc->createElement( 'description' ); 00675 $channelDescription->appendChild( $doc->createTextNode( $this->attribute( 'description' ) ) ); 00676 $channel->appendChild( $channelDescription ); 00677 00678 if ( $imageURL !== false ) 00679 { 00680 $channelImage = $doc->createElement( 'image' ); 00681 $channelImage->setAttributeNS( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdf:resource', $imageURL ); 00682 $channel->appendChild( $channelImage ); 00683 00684 $image = $doc->createElement( 'image' ); 00685 $image->setAttributeNS( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdf:about', $imageURL ); 00686 00687 $imageTitle = $doc->createElement( 'title' ); 00688 $imageTitle->appendChild( $doc->createTextNode( $this->attribute( 'title' ) ) ); 00689 $image->appendChild( $imageTitle ); 00690 00691 $imageLink = $doc->createElement( 'link' ); 00692 $imageLink->appendChild( $doc->createTextNode( $this->attribute( 'url' ) ) ); 00693 $image->appendChild( $imageLink ); 00694 00695 $imageUrlNode = $doc->createElement( 'url' ); 00696 $imageUrlNode->appendChild( $doc->createTextNode( $imageURL ) ); 00697 $image->appendChild( $imageUrlNode ); 00698 00699 $root->appendChild( $image ); 00700 } 00701 00702 $items = $doc->createElement( 'items' ); 00703 $channel->appendChild( $items ); 00704 00705 $rdfSeq = $doc->createElementNS( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdf:Seq' ); 00706 $items->appendChild( $rdfSeq ); 00707 00708 $cond = array( 00709 'rssexport_id' => $this->ID, 00710 'status' => $this->Status 00711 ); 00712 $rssSources = eZRSSExportItem::fetchFilteredList( $cond ); 00713 00714 $nodeArray = eZRSSExportItem::fetchNodeList( $rssSources, $this->getObjectListFilter() ); 00715 00716 if ( is_array( $nodeArray ) && count( $nodeArray ) ) 00717 { 00718 $attributeMappings = eZRSSExportItem::getAttributeMappings( $rssSources ); 00719 00720 foreach ( $nodeArray as $node ) 00721 { 00722 $object = $node->attribute( 'object' ); 00723 $dataMap = $object->dataMap(); 00724 if ( $useURLAlias === true ) 00725 { 00726 $nodeURL = $this->urlEncodePath( $baseItemURL . $node->urlAlias() ); 00727 } 00728 else 00729 { 00730 $nodeURL = $baseItemURL . 'content/view/full/' . $node->attribute( 'node_id' ); 00731 } 00732 00733 $rdfSeqLi = $doc->createElementNS( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdf:li' ); 00734 $rdfSeqLi->setAttributeNS( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdf:resource', $nodeURL ); 00735 $rdfSeq->appendChild( $rdfSeqLi ); 00736 00737 // keep track if there's any match 00738 $doesMatch = false; 00739 // start mapping the class attribute to the respective RSS field 00740 foreach ( $attributeMappings as $attributeMapping ) 00741 { 00742 // search for correct mapping by path 00743 if ( $attributeMapping[0]->attribute( 'class_id' ) == $object->attribute( 'contentclass_id' ) and 00744 in_array( $attributeMapping[0]->attribute( 'source_node_id' ), $node->attribute( 'path_array' ) ) ) 00745 { 00746 // found it 00747 $doesMatch = true; 00748 // now fetch the attributes 00749 $title = $dataMap[$attributeMapping[0]->attribute( 'title' )]; 00750 $description = $dataMap[$attributeMapping[0]->attribute( 'description' )]; 00751 break; 00752 } 00753 } 00754 00755 if( !$doesMatch ) 00756 { 00757 // no match 00758 eZDebug::writeWarning( __METHOD__ . ': Cannot find matching RSS source node for content object in '.__FILE__.', Line '.__LINE__ ); 00759 $retValue = null; 00760 return $retValue; 00761 } 00762 00763 // title RSS element with respective class attribute content 00764 $titleContent = $title->attribute( 'content' ); 00765 if ( $titleContent instanceof eZXMLText ) 00766 { 00767 $outputHandler = $titleContent->attribute( 'output' ); 00768 $itemTitleText = $outputHandler->attribute( 'output_text' ); 00769 } 00770 else 00771 { 00772 $itemTitleText = $titleContent; 00773 } 00774 00775 $itemTitle = $doc->createElement( 'title' ); 00776 $itemTitle->appendChild( $doc->createTextNode( $itemTitleText ) ); 00777 00778 // description RSS element with respective class attribute content 00779 $descriptionContent = $description->attribute( 'content' ); 00780 if ( $descriptionContent instanceof eZXMLText ) 00781 { 00782 $outputHandler = $descriptionContent->attribute( 'output' ); 00783 $itemDescriptionText = $outputHandler->attribute( 'output_text' ); 00784 } 00785 else 00786 { 00787 $itemDescriptionText = $descriptionContent; 00788 } 00789 00790 $itemDescription = $doc->createElement( 'description' ); 00791 $itemDescription->appendChild( $doc->createTextNode( $itemDescriptionText ) ); 00792 00793 $itemLink = $doc->createElement( 'link' ); 00794 $itemLink->appendChild( $doc->createTextNode( $nodeURL ) ); 00795 00796 $item = $doc->createElementNS( 'http://purl.org/rss/1.0/', 'item' ); 00797 $item->setAttributeNS( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdf:about', $nodeURL ); 00798 00799 $item->appendChild( $itemTitle ); 00800 $item->appendChild( $itemLink ); 00801 $item->appendChild( $itemDescription ); 00802 00803 $root->appendChild( $item ); 00804 } 00805 } 00806 00807 return $doc; 00808 } 00809 00810 /** 00811 * Generates an RSS feed document with type $type and returns it as a string. 00812 * 00813 * It uses the Feed component from eZ Components. 00814 * 00815 * Supported types: 'rss1', 'rss2', 'atom'. 00816 * 00817 * @since 4.2 00818 * @param string $type One of 'rss1', 'rss2' and 'atom' 00819 * @return string XML document as a string 00820 */ 00821 function generateFeed( $type ) 00822 { 00823 $locale = eZLocale::instance(); 00824 00825 // Get URL Translation settings. 00826 $config = eZINI::instance(); 00827 if ( $config->variable( 'URLTranslator', 'Translation' ) == 'enabled' ) 00828 { 00829 $useURLAlias = true; 00830 } 00831 else 00832 { 00833 $useURLAlias = false; 00834 } 00835 00836 if ( $this->attribute( 'url' ) == '' ) 00837 { 00838 $baseItemURL = ''; 00839 eZURI::transformURI( $baseItemURL, false, 'full' ); 00840 $baseItemURL .= '/'; 00841 } 00842 else 00843 { 00844 $baseItemURL = $this->attribute( 'url' ) . '/'; //.$this->attribute( 'site_access' ).'/'; 00845 } 00846 00847 $feed = new ezcFeed(); 00848 00849 $feed->title = htmlspecialchars( 00850 $this->attribute( 'title' ), ENT_NOQUOTES, 'UTF-8' 00851 ); 00852 00853 $link = $feed->add( 'link' ); 00854 $link->href = htmlspecialchars( $baseItemURL, ENT_NOQUOTES, 'UTF-8' ); 00855 00856 $feed->description = htmlspecialchars( 00857 $this->attribute( 'description' ), ENT_NOQUOTES, 'UTF-8' 00858 ); 00859 $feed->language = $locale->httpLocaleCode(); 00860 00861 // to add the <atom:link> element needed for RSS2 00862 $feed->id = htmlspecialchars( 00863 $baseItemURL . 'rss/feed/' . $this->attribute( 'access_url' ), 00864 ENT_NOQUOTES, 'UTF-8' 00865 ); 00866 00867 // required for ATOM 00868 $feed->updated = time(); 00869 $author = $feed->add( 'author' ); 00870 $author->email = htmlspecialchars( 00871 $config->variable( 'MailSettings', 'AdminEmail' ), 00872 ENT_NOQUOTES, 'UTF-8' 00873 ); 00874 $creatorObject = eZContentObject::fetch( $this->attribute( 'creator_id' ) ); 00875 if ( $creatorObject instanceof eZContentObject ) 00876 { 00877 $author->name = htmlspecialchars( 00878 $creatorObject->attribute('name'), ENT_NOQUOTES, 'UTF-8' 00879 ); 00880 } 00881 00882 $imageURL = $this->fetchImageURL(); 00883 if ( $imageURL !== false ) 00884 { 00885 $imageURL = htmlspecialchars( $imageURL, ENT_NOQUOTES, 'UTF-8' ); 00886 $image = $feed->add( 'image' ); 00887 00888 // Required for RSS1 00889 $image->about = $imageURL; 00890 00891 $image->url = $imageURL; 00892 $image->title = htmlspecialchars( 00893 $this->attribute( 'title' ), ENT_NOQUOTES, 'UTF-8' 00894 ); 00895 $image->link = $link->href; 00896 } 00897 00898 $cond = array( 00899 'rssexport_id' => $this->ID, 00900 'status' => $this->Status 00901 ); 00902 $rssSources = eZRSSExportItem::fetchFilteredList( $cond ); 00903 00904 $nodeArray = eZRSSExportItem::fetchNodeList( $rssSources, $this->getObjectListFilter() ); 00905 00906 if ( is_array( $nodeArray ) && count( $nodeArray ) ) 00907 { 00908 $attributeMappings = eZRSSExportItem::getAttributeMappings( $rssSources ); 00909 00910 foreach ( $nodeArray as $node ) 00911 { 00912 if ( $node->attribute('is_hidden') && !eZContentObjectTreeNode::showInvisibleNodes() ) 00913 { 00914 // if the node is hidden skip past it and don't add it to the RSS export 00915 continue; 00916 } 00917 $object = $node->attribute( 'object' ); 00918 $dataMap = $object->dataMap(); 00919 if ( $useURLAlias === true ) 00920 { 00921 $nodeURL = $this->urlEncodePath( $baseItemURL . $node->urlAlias() ); 00922 } 00923 else 00924 { 00925 $nodeURL = $baseItemURL . 'content/view/full/' . $node->attribute( 'node_id' ); 00926 } 00927 00928 // keep track if there's any match 00929 $doesMatch = false; 00930 // start mapping the class attribute to the respective RSS field 00931 foreach ( $attributeMappings as $attributeMapping ) 00932 { 00933 // search for correct mapping by path 00934 if ( $attributeMapping[0]->attribute( 'class_id' ) == $object->attribute( 'contentclass_id' ) and 00935 in_array( $attributeMapping[0]->attribute( 'source_node_id' ), $node->attribute( 'path_array' ) ) ) 00936 { 00937 // found it 00938 $doesMatch = true; 00939 // now fetch the attributes 00940 $title = $dataMap[$attributeMapping[0]->attribute( 'title' )]; 00941 // description is optional 00942 $descAttributeIdentifier = $attributeMapping[0]->attribute( 'description' ); 00943 $description = $descAttributeIdentifier ? $dataMap[$descAttributeIdentifier] : false; 00944 // category is optional 00945 $catAttributeIdentifier = $attributeMapping[0]->attribute( 'category' ); 00946 $category = $catAttributeIdentifier ? $dataMap[$catAttributeIdentifier] : false; 00947 // enclosure is optional 00948 $enclosureAttributeIdentifier = $attributeMapping[0]->attribute( 'enclosure' ); 00949 $enclosure = $enclosureAttributeIdentifier ? $dataMap[$enclosureAttributeIdentifier] : false; 00950 break; 00951 } 00952 } 00953 00954 if( !$doesMatch ) 00955 { 00956 // no match 00957 eZDebug::writeError( 'Cannot find matching RSS attributes for datamap on node: ' . $node->attribute( 'node_id' ), __METHOD__ ); 00958 return null; 00959 } 00960 00961 // title RSS element with respective class attribute content 00962 $titleContent = $title->attribute( 'content' ); 00963 if ( $titleContent instanceof eZXMLText ) 00964 { 00965 $outputHandler = $titleContent->attribute( 'output' ); 00966 $itemTitleText = $outputHandler->attribute( 'output_text' ); 00967 } 00968 else 00969 { 00970 $itemTitleText = $titleContent; 00971 } 00972 00973 $item = $feed->add( 'item' ); 00974 00975 $item->title = htmlspecialchars( $itemTitleText, ENT_NOQUOTES, 'UTF-8' ); 00976 00977 $link = $item->add( 'link' ); 00978 $link->href = htmlspecialchars( $nodeURL, ENT_NOQUOTES, 'UTF-8' ); 00979 00980 switch ( $type ) 00981 { 00982 case 'rss2': 00983 $item->id = $object->attribute( 'remote_id' ); 00984 $item->id->isPermaLink = false; 00985 break; 00986 default: 00987 $item->id = $nodeURL; 00988 } 00989 00990 $itemCreatorObject = $node->attribute('creator'); 00991 if ( $itemCreatorObject instanceof eZContentObject ) 00992 { 00993 $author = $item->add( 'author' ); 00994 $author->name = htmlspecialchars( 00995 $itemCreatorObject->attribute('name'), ENT_NOQUOTES, 'UTF-8' 00996 ); 00997 $author->email = $config->variable( 'MailSettings', 'AdminEmail' ); 00998 } 00999 01000 // description RSS element with respective class attribute content 01001 if ( $description ) 01002 { 01003 $descContent = $description->attribute( 'content' ); 01004 if ( $descContent instanceof eZXMLText ) 01005 { 01006 $outputHandler = $descContent->attribute( 'output' ); 01007 $itemDescriptionText = htmlspecialchars( 01008 $outputHandler->attribute( 'output_text' ), ENT_NOQUOTES, 'UTF-8' 01009 ); 01010 } 01011 else if ( $descContent instanceof eZImageAliasHandler ) 01012 { 01013 $itemImage = $descContent->hasAttribute( 'rssitem' ) ? $descContent->attribute( 'rssitem' ) : $descContent->attribute( 'rss' ); 01014 $origImage = $descContent->attribute( 'original' ); 01015 eZURI::transformURI( $itemImage['full_path'], true, 'full' ); 01016 eZURI::transformURI( $origImage['full_path'], true, 'full' ); 01017 $itemDescriptionText = '<a href="' . htmlspecialchars( $origImage['full_path'] ) 01018 . '"><img alt="' . htmlspecialchars( $descContent->attribute( 'alternative_text' ) ) 01019 . '" src="' . htmlspecialchars( $itemImage['full_path'] ) 01020 . '" width="' . $itemImage['width'] 01021 . '" height="' . $itemImage['height'] 01022 . '" /></a>'; 01023 } 01024 else 01025 { 01026 $itemDescriptionText = htmlspecialchars( 01027 $descContent, ENT_NOQUOTES, 'UTF-8' 01028 ); 01029 } 01030 $item->description = $itemDescriptionText; 01031 } 01032 01033 // category RSS element with respective class attribute content 01034 if ( $category ) 01035 { 01036 $categoryContent = $category->attribute( 'content' ); 01037 if ( $categoryContent instanceof eZXMLText ) 01038 { 01039 $outputHandler = $categoryContent->attribute( 'output' ); 01040 $itemCategoryText = $outputHandler->attribute( 'output_text' ); 01041 } 01042 elseif ( $categoryContent instanceof eZKeyword ) 01043 { 01044 $itemCategoryText = $categoryContent->keywordString(); 01045 } 01046 else 01047 { 01048 $itemCategoryText = $categoryContent; 01049 } 01050 01051 if ( $itemCategoryText ) 01052 { 01053 $cat = $item->add( 'category' ); 01054 $cat->term = htmlspecialchars( 01055 $itemCategoryText, ENT_NOQUOTES, 'UTF-8' 01056 ); 01057 } 01058 } 01059 01060 // enclosure RSS element with respective class attribute content 01061 if ( $enclosure ) 01062 { 01063 $encItemURL = false; 01064 $enclosureContent = $enclosure->attribute( 'content' ); 01065 if ( $enclosureContent instanceof eZMedia ) 01066 { 01067 $enc = $item->add( 'enclosure' ); 01068 $enc->length = $enclosureContent->attribute('filesize'); 01069 $enc->type = $enclosureContent->attribute('mime_type'); 01070 $encItemURL = 'content/download/' . $enclosure->attribute('contentobject_id') 01071 . '/' . $enclosureContent->attribute( 'contentobject_attribute_id' ) 01072 . '/' . urlencode( $enclosureContent->attribute( 'original_filename' ) ); 01073 eZURI::transformURI( $encItemURL, false, 'full' ); 01074 } 01075 else if ( $enclosureContent instanceof eZBinaryFile ) 01076 { 01077 $enc = $item->add( 'enclosure' ); 01078 $enc->length = $enclosureContent->attribute('filesize'); 01079 $enc->type = $enclosureContent->attribute('mime_type'); 01080 $encItemURL = 'content/download/' . $enclosure->attribute('contentobject_id') 01081 . '/' . $enclosureContent->attribute( 'contentobject_attribute_id' ) 01082 . '/version/' . $enclosureContent->attribute( 'version' ) 01083 . '/file/' . urlencode( $enclosureContent->attribute( 'original_filename' ) ); 01084 eZURI::transformURI( $encItemURL, false, 'full' ); 01085 } 01086 else if ( $enclosureContent instanceof eZImageAliasHandler ) 01087 { 01088 $enc = $item->add( 'enclosure' ); 01089 $origImage = $enclosureContent->attribute( 'original' ); 01090 $enc->length = $origImage['filesize']; 01091 $enc->type = $origImage['mime_type']; 01092 $encItemURL = $origImage['full_path']; 01093 eZURI::transformURI( $encItemURL, true, 'full' ); 01094 } 01095 01096 if ( $encItemURL ) 01097 { 01098 $enc->url = htmlspecialchars( $encItemURL, ENT_NOQUOTES, 'UTF-8' ); 01099 } 01100 } 01101 01102 $item->published = $object->attribute( 'published' ); 01103 $item->updated = $object->attribute( 'published' ); 01104 } 01105 } 01106 return $feed->generate( $type ); 01107 } 01108 01109 /*! 01110 \private 01111 01112 Fetch Image from current ezrss export object. If non exist, or invalid, return false 01113 01114 \return valid image url 01115 */ 01116 function fetchImageURL() 01117 { 01118 01119 $imageNode = $this->attribute( 'image_node' ); 01120 if ( !$imageNode ) 01121 return false; 01122 01123 $imageObject = $imageNode->attribute( 'object' ); 01124 if ( !$imageObject ) 01125 return false; 01126 01127 $dataMap = $imageObject->attribute( 'data_map' ); 01128 if ( !$dataMap ) 01129 return false; 01130 01131 $imageAttribute = $dataMap['image']; 01132 if ( !$imageAttribute ) 01133 return false; 01134 01135 $imageHandler = $imageAttribute->attribute( 'content' ); 01136 if ( !$imageHandler ) 01137 return false; 01138 01139 $imageAlias = $imageHandler->imageAlias( 'rss' ); 01140 if( !$imageAlias ) 01141 return false; 01142 01143 $url = eZSys::hostname() . eZSys::wwwDir() .'/'. $imageAlias['url']; 01144 $url = preg_replace( "#^(//)#", "/", $url ); 01145 01146 return 'http://'.$url; 01147 } 01148 01149 /*! 01150 \private 01151 01152 Performs rawurlencode() on the path part of the URL. The rest is not touched. 01153 01154 \return partially encoded url 01155 */ 01156 function urlEncodePath( $url ) 01157 { 01158 // Raw encode the path part of the URL 01159 $urlComponents = parse_url( $url ); 01160 $pathParts = explode( '/', $urlComponents['path'] ); 01161 foreach ( $pathParts as $key => $pathPart ) 01162 { 01163 $pathParts[$key] = rawurlencode( $pathPart ); 01164 } 01165 $encodedPath = implode( '/', $pathParts ); 01166 01167 // Rebuild the URL again, like this: scheme://user:pass@host/path?query#fragment 01168 $encodedUrl = $urlComponents['scheme'] . '://'; 01169 01170 if ( isset( $urlComponents['user'] ) ) 01171 { 01172 $encodedUrl .= $urlComponents['user']; 01173 if ( isset( $urlComponents['pass'] ) ) 01174 { 01175 $encodedUrl .= ':' . $urlComponents['pass']; 01176 } 01177 $encodedUrl .= '@'; 01178 } 01179 01180 $encodedUrl .= $urlComponents['host']; 01181 if ( isset( $urlComponents['port'] ) ) 01182 { 01183 $encodedUrl .= ':' . $urlComponents['port']; 01184 } 01185 $encodedUrl .= $encodedPath; 01186 01187 if ( isset( $urlComponents['query'] ) ) 01188 { 01189 $encodedUrl .= '?' . $urlComponents['query']; 01190 } 01191 01192 if ( isset( $urlComponents['fragment'] ) ) 01193 { 01194 $encodedUrl .= '#' . $urlComponents['fragment']; 01195 } 01196 01197 return $encodedUrl; 01198 } 01199 } 01200 ?>