|
eZ Publish
[trunk]
|
00001 <?php 00002 /** 00003 * File containing the eZContentClassPackageHandler 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 eZContentObjectPackageHandler ezcontentobjectpackagehandler.php 00013 \brief Handles content objects in the package system 00014 00015 */ 00016 00017 class eZContentObjectPackageHandler extends eZPackageHandler 00018 { 00019 const MAX_LISTED_OBJECTS = 30; 00020 00021 // If number of objects in the package is bigger than this constant, 00022 // they are stored in separate files to prevent memory overflow. 00023 // 'null' means always use separate files 00024 const STORE_OBJECTS_TO_SEPARATE_FILES_THRESHOLD = 100; 00025 00026 const INSTALL_OBJECTS_ERROR_RANGE_FROM = 1; 00027 const INSTALL_OBJECTS_ERROR_RANGE_TO = 100; 00028 const UNINSTALL_OBJECTS_ERROR_RANGE_FROM = 101; 00029 const UNINSTALL_OBJECTS_ERROR_RANGE_TO = 200; 00030 00031 /*! 00032 Constructor 00033 */ 00034 function eZContentObjectPackageHandler() 00035 { 00036 $this->eZPackageHandler( 'ezcontentobject', 00037 array( 'extract-install-content' => true ) ); 00038 } 00039 00040 /*! 00041 Fetches object stored in separate xml file 00042 */ 00043 function fetchObjectFromFile( $objectFileNode ) 00044 { 00045 $fileName = $objectFileNode->getAttribute( 'filename' ); 00046 $filePath = $this->Package->path() . '/' . $this->contentObjectDirectory() . '/' . $fileName; 00047 $dom = $this->Package->fetchDOMFromFile( $filePath ); 00048 00049 if ( $dom ) 00050 { 00051 $objectNode = $dom->documentElement; 00052 } 00053 else 00054 { 00055 eZDebug::writeError( "Can't fetch object from package file: $filePath", __METHOD__ ); 00056 $objectNode = false; 00057 } 00058 00059 return $objectNode; 00060 } 00061 00062 function getRealObjectNode( $objectNode ) 00063 { 00064 if ( $objectNode->localName == 'object' ) 00065 { 00066 $realObjectNode = $objectNode; 00067 } 00068 else 00069 { 00070 $realObjectNode = $this->fetchObjectFromFile( $objectNode ); 00071 } 00072 return $realObjectNode; 00073 } 00074 00075 /*! 00076 Returns an explanation for the content object install item. 00077 00078 The explanaition is actually a list having the following structure: 00079 array( array( 'description' => 'Content object Foo' ), 00080 array( 'description' => 'Content object Bar' ), 00081 array( 'description' => 'Content object Baz' ) ); 00082 00083 When number of items in the above list is too high, 00084 the following array is returned instead: 00085 array( 'description' => 'NNN content objects' ); 00086 00087 00088 */ 00089 function explainInstallItem( $package, $installItem, $requestedInfo = array() ) 00090 { 00091 $this->Package = $package; 00092 00093 if ( $installItem['filename'] ) 00094 { 00095 $filename = $installItem['filename']; 00096 $subdirectory = $installItem['sub-directory']; 00097 if ( $subdirectory ) 00098 $filepath = $subdirectory . '/' . $filename . '.xml'; 00099 else 00100 $filepath = $filename . '.xml'; 00101 00102 $filepath = $package->path() . '/' . $filepath; 00103 00104 $dom = $package->fetchDOMFromFile( $filepath ); 00105 00106 if ( !$dom ) 00107 return null; 00108 00109 $content = $dom->documentElement; 00110 $objectListNode = $content->getElementsByTagName( 'object-list' )->item( 0 ); 00111 if ( $objectListNode ) 00112 { 00113 $realObjectNodes = $objectListNode->getElementsByTagName( 'object' ); 00114 } 00115 else 00116 { 00117 // If objects are stored in separate files (new format) 00118 $objectListNode = $content->getElementsByTagName( 'object-files-list' )->item( 0 ); 00119 $objectNodes = $objectListNode->getElementsByTagName( 'object-file' ); 00120 00121 if ( count( $objectNodes ) > self::MAX_LISTED_OBJECTS ) 00122 { 00123 return array( 'description' => ezpI18n::tr( 'kernel/package', '%number content objects', false, 00124 array( '%number' => count( $objectNodes ) ) ) ); 00125 } 00126 00127 $realObjectNodes = array(); 00128 foreach( $objectNodes as $objectNode ) 00129 { 00130 $realObjectNode = $this->fetchObjectFromFile( $objectNode ); 00131 if ( !$realObjectNode ) 00132 continue; 00133 00134 $realObjectNodes[] = $realObjectNode; 00135 } 00136 } 00137 00138 // create descriptions array 00139 $objectNames = array(); 00140 foreach( $realObjectNodes as $objectNode ) 00141 { 00142 $objectName = 00143 $objectNode->getAttribute( 'name' ) . 00144 ' (' . $objectNode->getAttributeNS( 'http://ez.no/ezobject', 'class_identifier' ) .')'; 00145 00146 // get info about translations. 00147 $languageInfo = array(); 00148 $versionList = $objectNode->getElementsByTagName( 'version-list' )->item( 0 ); 00149 $versions = $versionList->getElementsByTagName( 'version' ); 00150 foreach( $versions as $version ) 00151 { 00152 $versionInfo = $version->getElementsByTagName( 'object-translation' ); 00153 foreach( $versionInfo as $info ) 00154 { 00155 $languageInfo[] = $info->getAttribute( 'language' ); 00156 } 00157 } 00158 00159 $objectNames[] = array( 'description' => 00160 ezpI18n::tr( 'kernel/package', 'Content object %objectname', false, 00161 array( '%objectname' => $objectName ) ), 00162 'language_info' => $languageInfo ); 00163 } 00164 return $objectNames; 00165 } 00166 } 00167 00168 /*! 00169 Add Node list to ezcontentobject package handler. 00170 00171 \param nodeID node id 00172 \param isSubtree subtree (optional, default true ) 00173 */ 00174 function addNode( $nodeID, $isSubtree = true ) 00175 { 00176 $this->RootNodeIDArray[] = $nodeID; 00177 $this->NodeIDArray[] = $nodeID; 00178 00179 if ( $isSubtree ) 00180 { 00181 $nodeArray = eZContentObjectTreeNode::subTreeByNodeID( array( 'AsObject' => false ), $nodeID ); 00182 foreach( $nodeArray as $node ) 00183 { 00184 $this->NodeIDArray[] = $node['node_id']; 00185 } 00186 } 00187 } 00188 00189 /*! 00190 Generate package based on NodeArray and input options 00191 00192 \param package 00193 \param options 00194 */ 00195 function generatePackage( $package, $options ) 00196 { 00197 $this->Package = $package; 00198 $remoteIDArray = array(); 00199 $this->NodeIDArray = array_unique( $this->NodeIDArray ); 00200 foreach( $this->NodeIDArray as $nodeID ) 00201 { 00202 $this->NodeObjectArray[(string)$nodeID] = eZContentObjectTreeNode::fetch( $nodeID ); 00203 } 00204 00205 foreach( $this->RootNodeIDArray as $nodeID ) 00206 { 00207 $this->RootNodeObjectArray[(string)$nodeID] = eZContentObjectTreeNode::fetch( $nodeID ); 00208 } 00209 00210 $this->generateObjectArray( $options['node_assignment'] ); 00211 00212 $classIDArray = false; 00213 if ( $options['include_classes'] ) 00214 { 00215 $remoteIDArray['class'] = array(); 00216 $classIDArray = $this->generateClassIDArray(); 00217 00218 foreach ( $classIDArray as $classID ) 00219 { 00220 eZContentClassPackageHandler::addClass( $package, $classID ); 00221 } 00222 } 00223 00224 $dom = new DOMDocument( '1.0', 'utf-8' ); 00225 $packageRoot = $dom->createElement( 'content-object' ); 00226 $dom->appendChild( $packageRoot ); 00227 00228 $objectListDOMNode = $this->createObjectListNode( $options ); 00229 $importedObjectListDOMNode = $dom->importNode( $objectListDOMNode, true ); 00230 $packageRoot->appendChild( $importedObjectListDOMNode ); 00231 00232 $overrideSettingsArray = false; 00233 $templateFilenameArray = false; 00234 if ( $options['include_templates'] ) 00235 { 00236 $overrideSettingsListNode = $this->generateOverrideSettingsArray( $options['site_access_array'], $options['minimal_template_set'] ); 00237 $importedOverrideSettingsListNode = $dom->importNode( $overrideSettingsListNode, true ); 00238 $packageRoot->appendChild( $importedOverrideSettingsListNode ); 00239 00240 $designTemplateListNode = $this->generateTemplateFilenameArray(); 00241 $importedDesignTemplateListNode = $dom->importNode( $designTemplateListNode, true ); 00242 $packageRoot->appendChild( $importedDesignTemplateListNode ); 00243 00244 $fetchAliasListNode = $this->generateFetchAliasArray(); 00245 $importedFetchAliasListNode = $dom->importNode( $fetchAliasListNode, true ); 00246 $packageRoot->appendChild( $importedFetchAliasListNode ); 00247 } 00248 00249 $siteAccessListDOMNode = $this->createSiteAccessListNode( $options ); 00250 $importedSiteAccessListDOMNode = $dom->importNode( $siteAccessListDOMNode, true ); 00251 $packageRoot->appendChild( $importedSiteAccessListDOMNode ); 00252 00253 $topNodeListDOMNode = $this->createTopNodeListDOMNode( $options ); 00254 $importedTopNodeListDOMNode = $dom->importNode( $topNodeListDOMNode, true ); 00255 $packageRoot->appendChild( $importedTopNodeListDOMNode ); 00256 00257 //$filename = substr( md5( mt_rand() ), 0, 8 ); 00258 $filename = 'contentobjects'; 00259 $this->Package->appendInstall( 'ezcontentobject', false, false, true, 00260 $filename, $this->contentObjectDirectory(), 00261 array( 'content' => $packageRoot ) ); 00262 $this->Package->appendInstall( 'ezcontentobject', false, false, false, 00263 $filename, $this->contentObjectDirectory(), 00264 array( 'content' => false ) ); 00265 } 00266 00267 /*! 00268 \private 00269 Create DOMNode for list of top nodes. 00270 00271 \param options 00272 */ 00273 function createTopNodeListDOMNode( $options ) 00274 { 00275 $dom = new DOMDocument( '1.0', 'utf-8' ); 00276 $topNodeListDOMNode = $dom->createElement( 'top-node-list' ); 00277 $dom->appendChild( $topNodeListDOMNode ); 00278 00279 foreach( $this->RootNodeObjectArray as $rootNode ) 00280 { 00281 unset( $topNode ); 00282 $topNode = $dom->createElement( 'top-node' ); 00283 $topNode->appendChild( $dom->createTextNode( $rootNode->attribute( 'name' ) ) ); 00284 $topNode->setAttribute( 'node-id', $rootNode->attribute( 'node_id' ) ); 00285 $topNode->setAttribute( 'remote-id', $rootNode->attribute( 'remote_id' ) ); 00286 $topNodeListDOMNode->appendChild( $topNode ); 00287 } 00288 00289 return $topNodeListDOMNode; 00290 } 00291 00292 /*! 00293 \private 00294 Create DOMNode for list of added siteaccesses. 00295 00296 \param options 00297 */ 00298 function createSiteAccessListNode( $options ) 00299 { 00300 $dom = new DOMDocument( '1.0', 'utf-8' ); 00301 $siteAccessListDOMNode = $dom->createElement( 'site-access-list' ); 00302 $dom->appendChild( $siteAccessListDOMNode ); 00303 00304 foreach( $options['site_access_array'] as $siteAccess ) 00305 { 00306 unset( $siteAccessNode ); 00307 $siteAccessNode = $dom->createElement( 'site-access' ); 00308 $siteAccessNode->appendChild( $dom->createTextNode( $siteAccess ) ); 00309 $siteAccessListDOMNode->appendChild( $siteAccessNode ); 00310 } 00311 00312 return $siteAccessListDOMNode; 00313 } 00314 00315 /*! 00316 \private 00317 Serializes and adds all contentobjects to package 00318 00319 \param options 00320 */ 00321 function createObjectListNode( $options ) 00322 { 00323 if ( $options['versions'] == 'current' ) 00324 { 00325 $version = true; 00326 } 00327 else 00328 { 00329 $version = false; 00330 } 00331 00332 $path = $this->Package->path() . '/' . $this->contentObjectDirectory(); 00333 if ( !file_exists( $path ) ) 00334 eZDir::mkdir( $path, false, true ); 00335 00336 $dom = new DOMDocument( '1.0', 'utf-8' ); 00337 00338 // Store objects to separate files or not 00339 $storeToMultiple = count( $this->ObjectArray ) >= self::STORE_OBJECTS_TO_SEPARATE_FILES_THRESHOLD ? true : false; 00340 if ( $storeToMultiple ) 00341 $objectListNode = $dom->createElement( 'object-files-list' ); 00342 else 00343 $objectListNode = $dom->createElement( 'object-list' ); 00344 00345 $dom->appendChild( $objectListNode ); 00346 00347 foreach( array_keys( $this->ObjectArray ) as $objectID ) 00348 { 00349 $objectNode = $this->ObjectArray[$objectID]->serialize( $this->Package, $version, $options, $this->NodeObjectArray, $this->RootNodeIDArray ); 00350 00351 if ( $storeToMultiple ) 00352 { 00353 $fileName = 'object-' . $objectNode->getAttribute( 'remote_id' ) . '.xml'; 00354 $filePath = $path . '/' . $fileName; 00355 00356 $objectFileNode = $dom->createElement( 'object-file' ); 00357 $objectFileNode->setAttribute( 'filename', $fileName ); 00358 $objectListNode->appendChild( $objectFileNode ); 00359 00360 $partDOM = new DOMDocument( '1.0', 'utf-8' ); 00361 $partDOM->formatOutput = true; 00362 $importedObjectNode = $partDOM->importNode( $objectNode, true ); 00363 $partDOM->appendChild( $importedObjectNode ); 00364 $this->Package->storeDOM( $filePath, $partDOM ); 00365 unset( $partDOM ); 00366 unset( $objectFileNode ); 00367 } 00368 else 00369 { 00370 $importedObjectNode = $dom->importNode( $objectNode, true ); 00371 $objectListNode->appendChild( $importedObjectNode ); 00372 } 00373 unset( $objectNode ); 00374 } 00375 00376 return $objectListNode; 00377 } 00378 00379 /*! 00380 \private 00381 Generate list of content objects to export, and store them to 00382 00383 \param nodeAssignment which node assignments to include, either 'selected' or 'main' 00384 */ 00385 function generateObjectArray( $nodeAssignment ) 00386 { 00387 foreach( $this->NodeObjectArray as $contentNode ) 00388 { 00389 if ( $nodeAssignment == 'main' ) 00390 { 00391 if ( $contentNode->attribute( 'main_node_id' ) == $contentNode->attribute( 'node_id' ) ) 00392 { 00393 $this->ObjectArray[(string)$contentNode->attribute( 'contentobject_id' )] = $contentNode->object(); 00394 } 00395 } 00396 else 00397 { 00398 $this->ObjectArray[(string)$contentNode->attribute( 'contentobject_id' )] = $contentNode->object(); 00399 } 00400 } 00401 } 00402 00403 /*! 00404 \private 00405 */ 00406 function &generateFetchAliasArray() 00407 { 00408 $dom = new DOMDocument( '1.0', 'utf-8' ); 00409 $fetchAliasListDOMNode = $dom->createElement( 'fetch-alias-list' ); 00410 $registeredAliases = array(); 00411 00412 foreach( array_keys( $this->TemplateFileArray ) as $siteAccess ) 00413 { 00414 $aliasINI = eZINI::instance( 'fetchalias.ini', 'settings', null, null, true ); 00415 $aliasINI->prependOverrideDir( "siteaccess/$siteAccess", false, 'siteaccess' ); 00416 $aliasINI->loadCache(); 00417 00418 foreach ( $this->TemplateFileArray[$siteAccess] as $filename ) 00419 { 00420 $fp = fopen( $filename, 'r' ); 00421 if ( !$fp ) 00422 { 00423 eZDebug::writeError( 'Could not open ' . $filename . ' during content object export.', __METHOD__ ); 00424 continue; 00425 } 00426 00427 $str = fread( $fp, filesize( $filename ) ); 00428 00429 $matchArray = array(); 00430 preg_match_all( "#.*fetch_alias\([ ]*([a-zA-Z0-9_]+)[ |,|)]+.*#U", $str, $matchArray, PREG_PATTERN_ORDER ); 00431 00432 foreach( $matchArray[1] as $fetchAlias ) 00433 { 00434 if ( isset( $registeredAliases[$fetchAlias] ) ) 00435 { 00436 continue; 00437 } 00438 $registeredAliases[$fetchAlias] = true; 00439 00440 unset( $fetchAliasDOMNode ); 00441 $fetchAliasDOMNode = $dom->createElement( 'fetch-alias' ); 00442 $fetchAliasDOMNode->setAttribute( 'name', $fetchAlias ); 00443 $fetchAliasDOMNode->setAttribute( 'site-access', $siteAccess ); 00444 00445 $fetchBlock = $aliasINI->group( $fetchAlias ); 00446 if ( isset( $fetchBlock['Constant'] ) ) 00447 { 00448 foreach ( $fetchBlock['Constant'] as $matchKey => $value ) 00449 { 00450 if ( strpos( $matchKey, 'class_' ) === 0 && 00451 is_int( $value ) ) 00452 { 00453 $contentClass = eZContentClass::fetch( $value ); 00454 $fetchBlock['Constant']['class_remote_id'] = $contentClass->attribute( 'remote_id' ); 00455 } 00456 if ( strpos( $matchKey, 'node_' ) === 0 && 00457 is_int( $value ) ) 00458 { 00459 $contentTreeNode = eZContentObjectTreeNode::fetch( $value ); 00460 $fetchBlock['Constant']['node_remote_id'] = $contentTreeNode->attribute( 'remote_id' ); 00461 } 00462 if ( strpos( $matchKey, 'parent_node_' ) === 0 && 00463 is_int( $value ) ) 00464 { 00465 $contentTreeNode = eZContentObjectTreeNode::fetch( $value ); 00466 $fetchBlock['Constant']['parent_node_remote_id'] = $contentTreeNode->attribute( 'remote_id' ); 00467 } 00468 if ( strpos( $matchKey, 'object_' ) === 0 && 00469 is_int( $value ) ) 00470 { 00471 $contentObject = eZContentObject::fetch( $value ); 00472 $fetchBlock['Constant']['object_remote_id'] = $contentObject->attribute( 'remote_id' ); 00473 } 00474 } 00475 } 00476 $importedNode = $dom->importNode( eZContentObjectPackageHandler::createElementNodeFromArray( $fetchAlias, $fetchBlock ), true ); 00477 $fetchAliasDOMNode->appendChild( $importedNode ); 00478 $fetchAliasListDOMNode->appendChild( $fetchAliasDOMNode ); 00479 } 00480 } 00481 } 00482 return $fetchAliasListDOMNode; 00483 } 00484 00485 /*! 00486 \private 00487 */ 00488 function &generateTemplateFilenameArray() 00489 { 00490 $dom = new DOMDocument( '1.0', 'utf-8' ); 00491 00492 $templateListDOMNode = $dom->createElement( 'template-list' ); 00493 $dom->appendChild( $templateListDOMNode ); 00494 00495 foreach( array_keys( $this->OverrideSettingsArray ) as $siteAccess ) 00496 { 00497 $this->TemplateFileArray[$siteAccess] = array(); 00498 $overrideArray = eZTemplateDesignResource::overrideArray( $siteAccess ); 00499 00500 foreach( $this->OverrideSettingsArray[$siteAccess] as $override ) 00501 { 00502 $customMatchArray = $overrideArray['/' . $override['Source']]['custom_match']; 00503 00504 foreach( $customMatchArray as $customMatch ) 00505 { 00506 if ( $customMatch['conditions'] == null ) 00507 { 00508 //$templateListDOMNode->appendChild( $this->createDOMNodeFromFile( $customMatch['match_file'], $siteAccess, 'design' ) ); 00509 //$this->TemplateFileArray[$siteAccess][] = $customMatch['match_file']; 00510 } 00511 else if ( count( array_diff( $customMatch['conditions'], $override['Match'] ) ) == 0 && 00512 count( array_diff( $override['Match'], $customMatch['conditions'] ) ) == 0 ) 00513 { 00514 unset( $node ); 00515 $node = $this->createDOMNodeFromFile( $customMatch['match_file'], $siteAccess, 'design' ); 00516 $importedNode = $dom->importNode( $node, true ); 00517 $templateListDOMNode->appendChild( $importedNode ); 00518 $this->TemplateFileArray[$siteAccess][] = $customMatch['match_file']; 00519 } 00520 } 00521 } 00522 } 00523 return $templateListDOMNode; 00524 00525 //TODO : add templates included in templates here. 00526 } 00527 00528 /*! 00529 \private 00530 Add file to repository and return DONNode description of file 00531 00532 \param filename 00533 \param siteAccess 00534 \param filetype (optional) 00535 */ 00536 function createDOMNodeFromFile( $filename, $siteAccess, $filetype = false ) 00537 { 00538 $path = substr( $filename, strpos( $filename, '/', 7 ) ); 00539 00540 $dom = new DOMDocument( '1.0', 'utf-8' ); 00541 $fileDOMNode = $dom->createElement( 'file' ); 00542 $fileDOMNode->setAttribute( 'site-access', $siteAccess ); 00543 00544 if ( $filetype !== false ) 00545 { 00546 $fileDOMNode->setAttribute( 'file-type', $filetype ); 00547 } 00548 00549 $dom->appendChild( $fileDOMNode ); 00550 $originalPathNode = $dom->createElement( 'original-path' ); 00551 $originalPathNode->appendChild( $dom->createTextNode( $filename ) ); 00552 $fileDOMNode->appendChild( $originalPathNode ); 00553 $pathNode = $dom->createElement( 'path' ); 00554 $pathNode->appendChild( $dom->createTextNode( $path ) ); 00555 $fileDOMNode->appendChild( $pathNode ); 00556 00557 $destinationPath = $this->Package->path() . '/' . eZContentObjectPackageHandler::contentObjectDirectory() . '/' . $path; 00558 eZDir::mkdir( eZDir::dirpath( $destinationPath ), false, true ); 00559 eZFileHandler::copy( $filename, $destinationPath ); 00560 00561 return $fileDOMNode; 00562 } 00563 00564 /*! 00565 \private 00566 Get all template overrides used by exported objects 00567 00568 \param siteAccessArray site access array 00569 */ 00570 function &generateOverrideSettingsArray( $siteAccessArray, $minimalTemplateSet ) 00571 { 00572 $datatypeHash = array(); 00573 $simpleMatchList = array(); 00574 $regexpMatchList = array(); 00575 foreach ( $siteAccessArray as $siteAccess ) 00576 { 00577 $overrideINI = eZINI::instance( 'override.ini', 'settings', null, null, true ); 00578 $overrideINI->prependOverrideDir( "siteaccess/$siteAccess", false, 'siteaccess' ); 00579 $overrideINI->loadCache(); 00580 00581 $matchBlock = false; 00582 $blockMatchArray = array(); 00583 00584 foreach( array_keys( $this->NodeObjectArray ) as $nodeID ) 00585 { 00586 // Extract some information that will be used 00587 unset( $contentNode, $contentObject, $contentClass ); 00588 $contentNode = $this->NodeObjectArray[$nodeID]; 00589 $contentObject = $contentNode->attribute( 'object' ); 00590 $contentClass = $contentObject->attribute( 'content_class' ); 00591 $attributeList = $contentClass->fetchAttributes( false, false, false ); 00592 $datatypeList = array(); 00593 foreach ( $attributeList as $attribute ) 00594 { 00595 $datatypeList[] = $attribute['data_type_string']; 00596 if ( !isset( $datatypeHash[$attribute['data_type_string']] ) ) 00597 { 00598 $datatype = eZDataType::create( $attribute['data_type_string'] ); 00599 $datatypeHash[$attribute['data_type_string']] = $datatype; 00600 if ( !method_exists( $datatype, 'templateList' ) ) 00601 continue; 00602 $templateList = $datatype->templateList(); 00603 if ( $templateList === false ) 00604 continue; 00605 foreach ( $templateList as $templateMatch ) 00606 { 00607 if ( is_string( $templateMatch ) ) 00608 { 00609 $simpleMatchList[] = $templateMatch; 00610 } 00611 else if ( is_array( $templateMatch ) ) 00612 { 00613 if ( $templateMatch[0] == 'regexp' ) 00614 { 00615 $regexpMatchList[] = $templateMatch[1]; 00616 } 00617 } 00618 } 00619 } 00620 } 00621 $datatypeText = implode( '|', array_unique( $datatypeList ) ); 00622 00623 foreach( array_keys( $overrideINI->groups() ) as $blockName ) 00624 { 00625 if ( isset( $blockMatchArray[$blockName] ) ) 00626 { 00627 continue; 00628 } 00629 00630 $blockData = $overrideINI->group( $blockName ); 00631 $sourceName = $blockData['Source']; 00632 $matchSettings = false; 00633 if ( isset( $blockData['Match'] ) ) 00634 $matchSettings = $blockData['Match']; 00635 00636 $matchValue = array(); 00637 $validMatch = true; 00638 $hasMatchType = false; 00639 if ( $matchSettings ) 00640 { 00641 foreach( array_keys( $matchSettings ) as $matchType ) 00642 { 00643 switch( $matchType ) 00644 { 00645 case 'object': 00646 { 00647 $hasMatchType = true; 00648 if ( $contentNode->attribute( 'contentobject_id' ) != $matchSettings[$matchType] ) 00649 { 00650 $validMatch = false; 00651 } 00652 else 00653 { 00654 $matchValue[$this->OverrideObjectRemoteID] = $contentObject->attribute( 'remote_id' ); 00655 } 00656 } break; 00657 00658 case 'node': 00659 { 00660 $hasMatchType = true; 00661 if ( $nodeID != $matchSettings[$matchType] ) 00662 { 00663 $validMatch = false; 00664 } 00665 else 00666 { 00667 $matchValue[$this->OverrideNodeRemoteID] = $contentNode->attribute( 'remote_id' ); 00668 } 00669 } break; 00670 00671 case 'parent_node': 00672 { 00673 $hasMatchType = true; 00674 if ( $contentNode->attribute( 'parent_node_id' ) != $matchSettings[$matchType] ) 00675 { 00676 $validMatch = false; 00677 } 00678 else 00679 { 00680 $parentNode = $contentNode->attribute( 'parent' ); 00681 $matchValue[$this->OverrideParentNodeRemoteID] = $parentNode->attribute( 'remote_id' ); 00682 } 00683 } break; 00684 00685 case 'class': 00686 { 00687 $hasMatchType = true; 00688 if ( $contentObject->attribute( 'contentclass_id' ) != $matchSettings[$matchType] ) 00689 { 00690 $validMatch = false; 00691 } 00692 else 00693 { 00694 $matchValue[$this->OverrideClassRemoteID] = $contentClass->attribute( 'remote_id' ); 00695 } 00696 } break; 00697 00698 case 'class_identifier': 00699 { 00700 $hasMatchType = true; 00701 if ( $contentObject->attribute( 'class_identifier' ) != $matchSettings[$matchType] ) 00702 { 00703 $validMatch = false; 00704 } 00705 } break; 00706 00707 case 'section': 00708 { 00709 $hasMatchType = true; 00710 if ( $contentObject->attribute( 'section_id' ) != $matchSettings[$matchType] ) 00711 { 00712 $validMatch = false; 00713 } 00714 } break; 00715 00716 case 'depth': 00717 { 00718 $hasMatchType = true; 00719 if ( $contentNode->attribute( 'depth' ) != $matchSettings[$matchType] ) 00720 { 00721 $validMatch = false; 00722 } 00723 } break; 00724 } 00725 00726 if ( !$validMatch ) 00727 { 00728 break; 00729 } 00730 } 00731 } 00732 else 00733 { 00734 $validMatch = false; 00735 } 00736 00737 if ( !$hasMatchType ) 00738 { 00739 // Datatype match, we include overrides for datatype templates 00740 if ( preg_match( "#^content/datatype/[a-zA-Z]+/(" . $datatypeText . ")\\.tpl$#", $sourceName ) ) 00741 { 00742 $validMatch = true; 00743 $hasMatchType = true; 00744 } 00745 else if ( in_array( $sourceName, $simpleMatchList ) ) 00746 { 00747 $validMatch = true; 00748 $hasMatchType = true; 00749 } 00750 else 00751 { 00752 foreach ( $regexpMatchList as $regexpMatch ) 00753 { 00754 if ( preg_match( $regexpMatch, $sourceName ) ) 00755 { 00756 $validMatch = true; 00757 $hasMatchType = true; 00758 } 00759 } 00760 } 00761 } 00762 00763 if ( $validMatch ) 00764 { 00765 if ( !$minimalTemplateSet or 00766 $hasMatchType ) 00767 { 00768 $blockMatchArray[$blockName] = array_merge( $blockData, 00769 $matchValue ); 00770 } 00771 } 00772 } 00773 } 00774 $this->OverrideSettingsArray[$siteAccess] = $blockMatchArray; 00775 } 00776 00777 $dom = new DOMDocument( '1.0', 'utf-8' ); 00778 00779 $overrideSettingsListDOMNode = $dom->createElement( 'override-list' ); 00780 $dom->appendChild( $overrideSettingsListDOMNode ); 00781 foreach ( $this->OverrideSettingsArray as $siteAccess => $blockMatchArray ) 00782 { 00783 foreach( $blockMatchArray as $blockName => $iniGroup ) 00784 { 00785 unset( $blockMatchNode ); 00786 $blockMatchNode = $dom->createElement( 'block' ); 00787 $blockMatchNode->setAttribute( 'name', $blockName ); 00788 $blockMatchNode->setAttribute( 'site-access', $siteAccess ); 00789 $importedNode = $dom->importNode( eZContentObjectPackageHandler::createElementNodeFromArray( $blockName, $iniGroup ), true ); 00790 $blockMatchNode->appendChild( $importedNode ); 00791 $overrideSettingsListDOMNode->appendChild( $blockMatchNode ); 00792 } 00793 } 00794 return $overrideSettingsListDOMNode; 00795 } 00796 00797 /*! 00798 \private 00799 Get list of all class objects used in by the nodes in NodeArray 00800 */ 00801 function &generateClassIDArray() 00802 { 00803 $classIDArray = array(); 00804 foreach( $this->NodeObjectArray as $nodeObject ) 00805 { 00806 $contentObject = $nodeObject->object(); 00807 $classIDArray[] = $contentObject->attribute( 'contentclass_id' ); 00808 } 00809 $classIDArray = array_unique( $classIDArray ); 00810 return $classIDArray; 00811 } 00812 00813 /*! 00814 Uninstalls all previously installed content objects. 00815 */ 00816 function uninstall( $package, $installType, $parameters, 00817 $name, $os, $filename, $subdirectory, 00818 $content, &$installParameters, 00819 &$installData ) 00820 { 00821 $this->Package = $package; 00822 00823 if ( isset( $installParameters['error']['error_code'] ) ) 00824 $errorCode = $installParameters['error']['error_code']; 00825 else 00826 $errorCode = false; 00827 00828 // Error codes reserverd for content object uninstallation 00829 if ( !$errorCode || ( $errorCode >= self::UNINSTALL_OBJECTS_ERROR_RANGE_FROM && 00830 $errorCode <= self::UNINSTALL_OBJECTS_ERROR_RANGE_TO ) ) 00831 { 00832 $objectListNode = $content->getElementsByTagName( 'object-list' )->item( 0 ); 00833 if ( $objectListNode ) 00834 { 00835 $objectNodes = $objectListNode->getElementsByTagName( 'object' ); 00836 } 00837 else 00838 { 00839 $objectListNode = $content->getElementsByTagName( 'object-files-list' )->item( 0 ); 00840 $objectNodes = $objectListNode->getElementsByTagName( 'object-file' ); 00841 } 00842 00843 // loop intentionally from the last until the first 00844 // objects need to be uninstalled in reverse order of installation 00845 for ( $i = $objectNodes->length - 1; $i >=0; $i-- ) 00846 { 00847 $objectNode = $objectNodes->item( $i ); 00848 $realObjectNode = $this->getRealObjectNode( $objectNode ); 00849 00850 $objectRemoteID = $realObjectNode->getAttribute( 'remote_id' ); 00851 $name = $realObjectNode->getAttribute( 'name' ); 00852 00853 if ( isset( $installParameters['error']['error_code'] ) && 00854 !$this->isErrorElement( $objectRemoteID, $installParameters ) ) 00855 continue; 00856 00857 if ( isset( $object ) ) 00858 { 00859 eZContentObject::clearCache( $object->attribute( 'id' ) ); 00860 unset( $object ); 00861 } 00862 $object = eZContentObject::fetchByRemoteID( $objectRemoteID ); 00863 00864 if ( $object !== null ) 00865 { 00866 $modified = $object->attribute( 'modified' ); 00867 $published = $object->attribute( 'published' ); 00868 if ( $modified > $published ) 00869 { 00870 $choosenAction = $this->errorChoosenAction( eZContentObject::PACKAGE_ERROR_MODIFIED, 00871 $installParameters, false, $this->HandlerType ); 00872 00873 if ( $choosenAction == eZContentObject::PACKAGE_KEEP ) 00874 { 00875 continue; 00876 } 00877 if ( $choosenAction != eZContentObject::PACKAGE_DELETE ) 00878 { 00879 $installParameters['error'] = array( 'error_code' => eZContentObject::PACKAGE_ERROR_MODIFIED, 00880 'element_id' => $objectRemoteID, 00881 'description' => ezpI18n::tr( 'kernel/package', 00882 "Object '%objectname' has been modified since installation. Are you sure you want to remove it?", 00883 false, array( '%objectname' => $name ) ), 00884 'actions' => array( eZContentObject::PACKAGE_DELETE => ezpI18n::tr( 'kernel/package', 'Remove' ), 00885 eZContentObject::PACKAGE_KEEP => ezpI18n::tr( 'kernel/package', 'Keep object' ) ) ); 00886 return false; 00887 } 00888 } 00889 00890 $assignedNodes = $object->attribute( 'assigned_nodes' ); 00891 $assignedNodeIDArray = array(); 00892 foreach( $assignedNodes as $node ) 00893 { 00894 $assignedNodeIDArray[] = $node->attribute( 'node_id' ); 00895 } 00896 if ( count( $assignedNodeIDArray ) == 0 ) 00897 continue; 00898 $info = eZContentObjectTreeNode::subtreeRemovalInformation( $assignedNodeIDArray ); 00899 $childrenCount = $info['total_child_count']; 00900 00901 if ( $childrenCount > 0 ) 00902 { 00903 $choosenAction = $this->errorChoosenAction( eZContentObject::PACKAGE_ERROR_HAS_CHILDREN, 00904 $installParameters, false, $this->HandlerType ); 00905 00906 if ( $choosenAction == eZContentObject::PACKAGE_KEEP ) 00907 { 00908 continue; 00909 } 00910 if ( $choosenAction != eZContentObject::PACKAGE_DELETE ) 00911 { 00912 $installParameters['error'] = array( 'error_code' => eZContentObject::PACKAGE_ERROR_HAS_CHILDREN, 00913 'element_id' => $objectRemoteID, 00914 'description' => ezpI18n::tr( 'kernel/package', 00915 "Object '%objectname' has %childrencount sub-item(s) that will be removed.", 00916 false, array( '%objectname' => $name, 00917 '%childrencount' => $childrenCount ) ), 00918 'actions' => array( eZContentObject::PACKAGE_DELETE => ezpI18n::tr( 'kernel/package', "Remove object and its sub-item(s)" ), 00919 eZContentObject::PACKAGE_KEEP => ezpI18n::tr( 'kernel/package', 'Keep object' ) ) ); 00920 return false; 00921 } 00922 } 00923 00924 eZContentObjectTreeNode::removeSubtrees( $assignedNodeIDArray, false ); 00925 00926 //eZContentObjectOperations::remove( $object->attribute( 'id' ) ); 00927 } 00928 else 00929 { 00930 eZDebug::writeNotice( "Can't uninstall object '$name': object not found", __METHOD__ ); 00931 } 00932 00933 unset( $realObjectNode ); 00934 } 00935 } 00936 return true; 00937 } 00938 00939 /*! 00940 Creates a new contentobject as defined in the xml structure. 00941 */ 00942 function install( $package, $installType, $parameters, 00943 $name, $os, $filename, $subdirectory, 00944 $content, &$installParameters, 00945 &$installData ) 00946 { 00947 $this->Package = $package; 00948 00949 if ( isset( $installParameters['error']['error_code'] ) ) 00950 $errorCode = $installParameters['error']['error_code']; 00951 else 00952 $errorCode = false; 00953 00954 // Error codes reservered for content object installation 00955 if ( !$errorCode || ( $errorCode >= self::INSTALL_OBJECTS_ERROR_RANGE_FROM && 00956 $errorCode <= self::INSTALL_OBJECTS_ERROR_RANGE_TO ) ) 00957 { 00958 $objectListNode = $content->getElementsByTagName( 'object-list' )->item( 0 ); 00959 if ( $objectListNode ) 00960 { 00961 $objectNodes = $objectListNode->getElementsByTagName( 'object' ); 00962 } 00963 else 00964 { 00965 $objectListNode = $content->getElementsByTagName( 'object-files-list' )->item( 0 ); 00966 $objectNodes = $objectListNode->getElementsByTagName( 'object-file' ); 00967 } 00968 00969 00970 if ( !$this->installContentObjects( $objectNodes, 00971 $content->getElementsByTagName( 'top-node-list' )->item( 0 ), 00972 $installParameters ) ) 00973 return false; 00974 $errorCode = false; 00975 } 00976 00977 if ( !$this->installTemplates( $content->getElementsByTagName( 'template-list' )->item( 0 ), 00978 $package, 00979 $subdirectory, 00980 $installParameters ) ) 00981 return false; 00982 00983 00984 if ( !$this->installOverrides( $content->getElementsByTagName( 'override-list' )->item( 0 ), 00985 $installParameters ) ) 00986 return false; 00987 00988 if ( !$this->installFetchAliases( $content->getElementsByTagName( 'fetch-alias-list' )->item( 0 ), 00989 $installParameters ) ) 00990 return false; 00991 00992 return true; 00993 } 00994 00995 /*! 00996 \private 00997 00998 Serialize and install content objects 00999 01000 \param objectNodes object-list DOMNode 01001 \param topNodeListNode 01002 \param installParameters install parameters 01003 */ 01004 function installContentObjects( $objectNodes, $topNodeListNode, &$installParameters ) 01005 { 01006 if ( isset( $installParameters['user_id'] ) ) 01007 $userID = $installParameters['user_id']; 01008 else 01009 $userID = eZUser::currentUserID(); 01010 01011 $handlerType = $this->handlerType(); 01012 $firstInstalledID = null; 01013 01014 foreach( $objectNodes as $objectNode ) 01015 { 01016 $realObjectNode = $this->getRealObjectNode( $objectNode ); 01017 01018 // Cycle until we reach an element where error has occured. 01019 // If action has been choosen, try install this item again, else skip it. 01020 if ( isset( $installParameters['error']['error_code'] ) && 01021 !$this->isErrorElement( $realObjectNode->getAttribute( 'remote_id' ), $installParameters ) ) 01022 { 01023 continue; 01024 } 01025 01026 //we are here, it means we'll try to install some object. 01027 if ( !$firstInstalledID ) 01028 { 01029 $firstInstalledID = $realObjectNode->getAttribute( 'remote_id' ); 01030 } 01031 01032 $newObject = eZContentObject::unserialize( $this->Package, $realObjectNode, $installParameters, $userID, $handlerType ); 01033 if ( !$newObject ) 01034 { 01035 return false; 01036 } 01037 01038 if ( is_object( $newObject ) ) 01039 { 01040 eZContentObject::clearCache( $newObject->attribute( 'id' ) ); 01041 unset( $newObject ); 01042 } 01043 unset( $realObjectNode ); 01044 01045 if ( isset( $installParameters['error'] ) && count( $installParameters['error'] ) ) 01046 { 01047 $installParameters['error'] = array(); 01048 } 01049 } 01050 01051 $this->installSuspendedNodeAssignment( $installParameters ); 01052 $this->installSuspendedObjectRelations( $installParameters ); 01053 01054 // Call postUnserialize on all installed objects 01055 foreach( $objectNodes as $objectNode ) 01056 { 01057 if ( $objectNode->localName == 'object' ) 01058 { 01059 $remoteID = $objectNode->getAttribute( 'remote_id' ); 01060 } 01061 else 01062 { 01063 $remoteID = substr( $objectNode->getAttribute( 'filename' ), 7, 32 ); 01064 } 01065 01066 // Begin from the object that we started from in the previous cycle 01067 if ( $firstInstalledID && $remoteID != $firstInstalledID ) 01068 { 01069 continue; 01070 } 01071 else 01072 { 01073 $firstInstalledID = null; 01074 } 01075 01076 $object = eZContentObject::fetchByRemoteID( $remoteID ); 01077 if ( is_object( $object ) ) 01078 { 01079 $object->postUnserialize( $this->Package ); 01080 eZContentObject::clearCache( $object->attribute( 'id' ) ); 01081 } 01082 unset( $object ); 01083 } 01084 01085 return true; 01086 } 01087 01088 /*! 01089 \private 01090 01091 \param install parameters 01092 */ 01093 function installSuspendedNodeAssignment( &$installParameters ) 01094 { 01095 if ( !isset( $installParameters['suspended-nodes'] ) ) 01096 { 01097 return; 01098 } 01099 foreach ( $installParameters['suspended-nodes'] as $parentNodeRemoteID => $suspendedNodeInfo ) 01100 { 01101 $parentNode = eZContentObjectTreeNode::fetchByRemoteID( $parentNodeRemoteID ); 01102 if ( $parentNode !== null ) 01103 { 01104 $nodeInfo = $suspendedNodeInfo['nodeinfo']; 01105 $nodeInfo['parent_node'] = $parentNode->attribute( 'node_id' ); 01106 01107 $existNodeAssignment = eZPersistentObject::fetchObject( eZNodeAssignment::definition(), 01108 null, 01109 $nodeInfo ); 01110 $nodeInfo['priority'] = $suspendedNodeInfo['priority']; 01111 if( !is_object( $existNodeAssignment ) ) 01112 { 01113 $nodeAssignment = eZNodeAssignment::create( $nodeInfo ); 01114 $nodeAssignment->store(); 01115 } 01116 01117 $contentObject = eZContentObject::fetch( $nodeInfo['contentobject_id'] ); 01118 if ( is_object( $contentObject ) && $contentObject->attribute( 'current_version' ) == $nodeInfo['contentobject_version'] ) 01119 { 01120 eZOperationHandler::execute( 'content', 'publish', array( 'object_id' => $nodeInfo['contentobject_id'], 01121 'version' => $nodeInfo['contentobject_version'] ) ); 01122 } 01123 if ( isset( $nodeInfo['is_main'] ) && $nodeInfo['is_main'] ) 01124 { 01125 $existingMainNode = eZContentObjectTreeNode::fetchByRemoteID( $nodeInfo['parent_remote_id'], false ); 01126 if ( $existingMainNode ) 01127 { 01128 eZContentObjectTreeNode::updateMainNodeID( $existingMainNode['node_id'], 01129 $nodeInfo['contentobject_id'], 01130 $nodeInfo['contentobject_version'], 01131 $nodeInfo['parent_node'] ); 01132 } 01133 } 01134 } 01135 else 01136 { 01137 eZDebug::writeError( 'Can not find parent node by remote-id ID = ' . $parentNodeRemoteID, __METHOD__ ); 01138 } 01139 unset( $installParameters['suspended-nodes'][$parentNodeRemoteID] ); 01140 } 01141 } 01142 01143 /*! 01144 \private 01145 01146 Installs suspended content object relations (need for complex content-relations structure) 01147 01148 \param install parameters 01149 */ 01150 function installSuspendedObjectRelations( &$installParameters ) 01151 { 01152 if ( !isset( $installParameters['suspended-relations'] ) ) 01153 { 01154 return; 01155 } 01156 foreach( $installParameters['suspended-relations'] as $suspendedObjectRelation ) 01157 { 01158 $contentObjectID = $suspendedObjectRelation['contentobject-id']; 01159 $contentObjectVersionID = $suspendedObjectRelation['contentobject-version']; 01160 01161 $contentObjectVersion = eZContentObjectVersion::fetchVersion( $contentObjectVersionID, $contentObjectID ); 01162 if ( is_object( $contentObjectVersion ) ) 01163 { 01164 $relatedObjectRemoteID = $suspendedObjectRelation['related-object-remote-id']; 01165 $relatedObject = eZContentObject::fetchByRemoteID( $relatedObjectRemoteID ); 01166 $relatedObjectID = ( $relatedObject !== null ) ? $relatedObject->attribute( 'id' ) : null; 01167 01168 if ( $relatedObjectID ) 01169 { 01170 $relatedObject->addContentObjectRelation( $relatedObjectID, $contentObjectVersionID, $contentObjectID ); 01171 } 01172 else 01173 { 01174 eZDebug::writeError( 'Can not find related object by remote-id ID = ' . $relatedObjectRemoteID, __METHOD__ ); 01175 } 01176 } 01177 } 01178 unset( $installParameters['suspended-relations'] ); 01179 } 01180 01181 /*! 01182 \private 01183 01184 Set and install templates 01185 01186 \param template list 01187 \param package 01188 \param subdirectory 01189 \param install parameters. 01190 */ 01191 function installTemplates( $templateList, $package, $subdirectory, &$installParameters ) 01192 { 01193 if ( !$templateList ) 01194 { 01195 return true; 01196 } 01197 $siteAccessDesignPathArray = array(); 01198 $templateRootPath = $package->path() . '/' . $subdirectory; 01199 foreach( $templateList->getElementsByTagName( 'file' ) as $fileNode ) 01200 { 01201 $originalSiteAccess = $fileNode->getAttribute( 'site-access' ); 01202 if ( isset( $installParameters['site_access_map'][$originalSiteAccess] ) ) 01203 { 01204 $newSiteAccess = $installParameters['site_access_map'][$originalSiteAccess]; 01205 } 01206 else 01207 { 01208 $newSiteAccess = $installParameters['site_access_map']['*']; 01209 } 01210 01211 if ( !isset( $siteAccessDesignPathArray[$newSiteAccess] ) ) 01212 { 01213 $ini = eZINI::instance( 'site.ini', 'settings', null, null, true ); 01214 $ini->prependOverrideDir( "siteaccess/$newSiteAccess", false, 'siteaccess' ); 01215 $ini->loadCache(); 01216 01217 if ( isset( $installParameters['design_map'] ) ) 01218 { 01219 $designMap = $installParameters['design_map']; 01220 if ( isset( $designMap[$originalSiteAccess] ) ) 01221 $siteAccessDesignPathArray[$newSiteAccess] = eZTemplateDesignResource::designStartPath() . '/' . $designMap[$originalSiteAccess]; 01222 else 01223 $siteAccessDesignPathArray[$newSiteAccess] = eZTemplateDesignResource::designStartPath() . '/' . $designMap['*']; 01224 } 01225 else 01226 { 01227 $siteAccessDesignPathArray[$newSiteAccess] = eZTemplateDesignResource::designStartPath() . '/' . $ini->variable( "DesignSettings", "StandardDesign" ); 01228 } 01229 } 01230 01231 $path = ''; 01232 foreach( $fileNode->childNodes as $pathNode ) 01233 { 01234 if ( $pathNode->nodeName == 'path' ) 01235 { 01236 $path = $pathNode->nodeValue; 01237 break; 01238 } 01239 } 01240 01241 $sourcePath = $templateRootPath . $path; 01242 $destinationPath = $siteAccessDesignPathArray[$newSiteAccess] . $path; 01243 01244 eZDir::mkdir( eZDir::dirpath( $destinationPath ), false, true ); 01245 if ( !eZFileHandler::copy( $sourcePath, $destinationPath ) ) 01246 return false; 01247 01248 // eZDebug::writeNotice( 'Copied: "' . $sourcePath . '" to: "' . $destinationPath . '"', __METHOD__ ); 01249 } 01250 return true; 01251 } 01252 01253 /*! 01254 \private 01255 01256 Install overrides 01257 01258 \param override list 01259 \param install parameters 01260 */ 01261 function installOverrides( $overrideListNode, &$parameters ) 01262 { 01263 if ( !$overrideListNode ) 01264 { 01265 return true; 01266 } 01267 01268 $overrideINIArray = array(); 01269 foreach( $overrideListNode->getElementsByTagName( 'block' ) as $blockNode ) 01270 { 01271 if ( isset( $parameters['site_access_map'][$blockNode->getAttribute( 'site-access' )] ) ) 01272 { 01273 $newSiteAccess = $parameters['site_access_map'][$blockNode->getAttribute( 'site-access' )]; 01274 } 01275 else 01276 { 01277 $newSiteAccess = $parameters['site_access_map']['*']; 01278 } 01279 01280 if ( !$newSiteAccess ) 01281 { 01282 eZDebug::writeError( 'SiteAccess map for : ' . $blockNode->getAttribute( 'site-access' ) . ' not set.', __METHOD__ ); 01283 continue; 01284 } 01285 01286 if ( !isset( $overrideINIArray[$newSiteAccess] ) ) 01287 { 01288 $overrideINIArray[$newSiteAccess] = eZINI::instance( 'override.ini.append.php', "settings/siteaccess/$newSiteAccess", null, null, true ); 01289 } 01290 01291 $blockArray = array(); 01292 $blockName = $blockNode->getAttribute( 'name' ); 01293 $blockArray[$blockName] = eZContentObjectPackageHandler::createArrayFromDOMNode( $blockNode->getElementsByTagName( $blockName )->item( 0 ) ); 01294 01295 if ( isset( $blockArray[$blockName][$this->OverrideObjectRemoteID] ) ) 01296 { 01297 $contentObject = eZContentObject::fetchByRemoteID( $blockArray[$blockName][$this->OverrideObjectRemoteID] ); 01298 $blockArray[$blockName]['Match']['object'] = $contentObject->attribute( 'id' ); 01299 unset( $blockArray[$blockName][$this->OverrideObjectRemoteID] ); 01300 // eZDebug::writeNotice( 'Found object id: "' . $blockArray[$blockName]['Match']['object'] . '" for matchblock "[' . $blockName . '][Match][object]"', __METHOD__ ); 01301 } 01302 if ( isset( $blockArray[$blockName][$this->OverrideNodeRemoteID] ) ) 01303 { 01304 $contentNode = eZContentObjectTreeNode::fetchByRemoteID( $blockArray[$blockName][$this->OverrideNodeRemoteID] ); 01305 $blockArray[$blockName]['Match']['node'] = $contentNode->attribute( 'node_id' ); 01306 unset( $blockArray[$blockName][$this->OverrideNodeRemoteID] ); 01307 // eZDebug::writeNotice( 'Found node id: "' . $blockArray[$blockName]['Match']['node'] . '" for matchblock "[' . $blockName . '][Match][node]"', __METHOD__ ); 01308 } 01309 if ( isset( $blockArray[$blockName][$this->OverrideParentNodeRemoteID] ) ) 01310 { 01311 $parentContentNode = eZContentObjectTreeNode::fetchByRemoteID( $blockArray[$blockName][$this->OverrideParentNodeRemoteID] ); 01312 $blockArray[$blockName]['Match']['parent_node'] = $parentContentNode->attribute( 'node_id' ); 01313 unset( $blockArray[$blockName][$this->OverrideParentNodeRemoteID] ); 01314 // eZDebug::writeNotice( 'Found parent node id: "' . $blockArray[$blockName]['Match']['parent_node'] . '" for matchblock "[' . $blockName . '][Match][parent_node]"', __METHOD__ ); 01315 } 01316 if ( isset( $blockArray[$blockName][$this->OverrideClassRemoteID] ) ) 01317 { 01318 $contentClass = eZContentClass::fetchByRemoteID( $blockArray[$blockName][$this->OverrideClassRemoteID] ); 01319 if ( !$contentClass ) 01320 { 01321 eZDebug::writeError( 'No content class found for RemoteID: ' . $blockArray[$blockName][$this->OverrideClassRemoteID], __METHOD__ ); 01322 continue; 01323 } 01324 $blockArray[$blockName]['Match']['class'] = $contentClass->attribute( 'id' ); 01325 unset( $blockArray[$blockName][$this->OverrideClassRemoteID] ); 01326 // eZDebug::writeNotice( 'Found class id: "' . $blockArray[$blockName]['Match']['class'] . '" for matchblock "[' . $blockName . '][Match][class]"', __METHOD__ ); 01327 } 01328 01329 $overrideINIArray[$newSiteAccess]->setVariables( $blockArray ); 01330 } 01331 01332 foreach( $overrideINIArray as $siteAccess => $iniArray ) 01333 { 01334 $overrideINIArray[$siteAccess]->save(); 01335 } 01336 01337 return true; 01338 } 01339 01340 /*! 01341 \private 01342 01343 Install fetch alias overrides 01344 01345 \param fetch alias list 01346 \param install parameters 01347 */ 01348 function installFetchAliases( $fetchAliasListNode, &$parameters ) 01349 { 01350 if ( !$fetchAliasListNode ) 01351 { 01352 return true; 01353 } 01354 01355 $fetchAliasINIArray = array(); 01356 foreach( $fetchAliasListNode->getElementsByTagName( 'fetch-alias' ) as $blockNode ) 01357 { 01358 if ( isset( $parameters['site_access_map'][$blockNode->getAttribute( 'site-access' )] ) ) 01359 { 01360 $newSiteAccess = $parameters['site_access_map'][$blockNode->getAttribute( 'site-access' )]; 01361 } 01362 else 01363 { 01364 $newSiteAccess = $parameters['site_access_map']['*']; 01365 } 01366 01367 if ( !isset( $fetchAliasINIArray[$newSiteAccess] ) ) 01368 { 01369 $fetchAliasINIArray[$newSiteAccess] = eZINI::instance( 'fetchalias.ini.append.php', "settings/siteaccess/$newSiteAccess", null, null, true ); 01370 } 01371 01372 $blockArray = array(); 01373 $blockName = $blockNode->getAttribute( 'name' ); 01374 $blockArray[$blockName] = eZContentObjectPackageHandler::createArrayFromDOMNode( $blockNode->getElementsByTagName( $blockName )->item( 0 ) ); 01375 01376 //$blockArray[$blockName] = $blockArray[$blockName][0]; 01377 01378 if ( isset( $blockArray[$blockName]['Constant'] ) && is_array( $blockArray[$blockName]['Constant'] ) && count( $blockArray[$blockName]['Constant'] ) > 0 ) 01379 { 01380 foreach( $blockArray[$blockName]['Constant'] as $matchKey => $value ) 01381 { 01382 if ( strpos( $matchKey, 'class_' ) === 0 && 01383 is_int( $value ) ) 01384 { 01385 $contentClass = eZContentClass::fetchByRemoteID( $blockArray[$blockName]['Constant']['class_remote_id'] ); 01386 $blockArray[$blockName]['Constant'][$matchKey] = $contentClass->attribute( 'id' ); 01387 unset( $blockArray[$blockName]['Constant']['class_remote_id'] ); 01388 } 01389 if( strpos( $matchKey, 'node_' ) === 0 && 01390 is_int( $value ) ) 01391 { 01392 $contentTreeNode = eZContentObjectTreeNode::fetchByRemoteID( $blockArray[$blockName]['Constant']['node_remote_id'] ); 01393 $blockArray[$blockName]['Constant'][$matchKey] = $contentTreeNode->attribute( 'node_id' ); 01394 unset( $blockArray[$blockName]['Constant']['node_remote_id'] ); 01395 } 01396 if( strpos( $matchKey, 'parent_node_' ) === 0 && 01397 is_int( $value ) ) 01398 { 01399 $contentTreeNode = eZContentObjectTreeNode::fetchByRemoteID( $blockArray[$blockName]['Constant']['parent_node_remote_id'] ); 01400 $blockArray[$blockName]['Constant'][$matchKey] = $contentTreeNode->attribute( 'node_id' ); 01401 unset( $blockArray[$blockName]['Constant']['parent_node_remote_id'] ); 01402 } 01403 if( strpos( $matchKey, 'object_' ) === 0 && 01404 is_int( $value ) ) 01405 { 01406 $contentObject = eZContentObject::fetchByRemoteID( $blockArray[$blockName]['Constant']['object_remote_id'] ); 01407 $blockArray[$blockName]['Constant'][$matchKey] = $contentTreeNode->attribute( 'id' ); 01408 unset( $blockArray[$blockName]['Constant']['object_remote_id'] ); 01409 } 01410 } 01411 } 01412 01413 $fetchAliasINIArray[$newSiteAccess]->setVariables( $blockArray ); 01414 } 01415 01416 foreach( $fetchAliasINIArray as $siteAccess => $iniFetchAlias ) 01417 { 01418 $fetchAliasINIArray[$siteAccess]->save(); 01419 } 01420 01421 return true; 01422 } 01423 01424 function add( $packageType, $package, $cli, $parameters ) 01425 { 01426 $options = array(); 01427 foreach ( $parameters['node-list'] as $nodeItem ) 01428 { 01429 $nodeIDList = $nodeItem['node-id-list']; 01430 foreach ( $nodeIDList as $nodeIDItem ) 01431 { 01432 $this->addNode( $nodeIDItem['id'], $nodeIDItem['subtree'] ); 01433 unset( $node ); 01434 $node = false; 01435 if ( isset( $nodeIDItem['node'] ) ) 01436 { 01437 $node = $nodeIDItem['node']; 01438 } 01439 else 01440 { 01441 $node = eZContentObjectTreeNode::fetch( $nodeIDItem['id'] ); 01442 } 01443 $cli->notice( "Adding node /" . $node->pathWithNames() . " to package" ); 01444 } 01445 } 01446 $options['include_classes'] = $parameters['include-classes']; 01447 $options['include_templates'] = $parameters['include-templates']; 01448 $options['node_assignment'] = $parameters['node-assignment-type']; 01449 $options['site_access_array'] = $parameters['siteaccess-list']; 01450 $options['language_array'] = $parameters['language-list']; 01451 $options['versions'] = $parameters['version-type']; 01452 $options['related_objects'] = $parameters['related-type']; 01453 $options['embed_objects'] = $parameters['embed-type']; 01454 $options['minimal_template_set'] = $parameters['minimal-template-set']; 01455 $this->generatePackage( $package, $options ); 01456 } 01457 01458 function handleAddParameters( $packageType, $package, $cli, $arguments ) 01459 { 01460 return $this->handleParameters( $packageType, $package, $cli, 'add', $arguments ); 01461 } 01462 01463 /*! 01464 \private 01465 */ 01466 function handleParameters( $packageType, $package, $cli, $type, $arguments ) 01467 { 01468 $nodeList = array(); 01469 $includeClasses = true; 01470 $includeTemplates = true; 01471 $siteAccessList = array(); 01472 $nodeAssignmentType = 'main'; 01473 $relatedObjectType = 'selected'; 01474 $embedObjectType = 'selected'; 01475 $versionType = 'current'; 01476 $languageList = array(); 01477 $minimalTemplateSet = false; 01478 $nodeItem = array( 'node-id-list' => array() ); 01479 $longOptions = array( 'include-classes' => 'include-classes', 01480 'include-templates' => 'include-templates', 01481 'exclude-classes' => 'exclude-classes', 01482 'exclude-templates' => 'exclude-templates', 01483 'language' => 'language', 01484 'current-version' => 'current-version', 01485 'all-versions' => 'all-versions', 01486 'node-main' => 'node-main', 01487 'node-selected' => 'node-selected', 01488 'siteaccess' => 'siteaccess', 01489 'minimal-template-set' => 'minimal-template-set' ); 01490 $shortOptions = array(); 01491 $error = false; 01492 foreach ( $arguments as $argument ) 01493 { 01494 if ( $argument[0] == '-' ) 01495 { 01496 if ( strlen( $argument ) > 1 and 01497 $argument[1] == '-' ) 01498 { 01499 $option = substr( $argument, 2 ); 01500 $valuePos = strpos( $option, '=' ); 01501 $optionValue = false; 01502 if ( $valuePos !== false ) 01503 { 01504 $optionValue = substr( $option, $valuePos + 1 ); 01505 $option = substr( $option, 0, $valuePos ); 01506 } 01507 if ( isset( $longOptions[$option] ) ) 01508 $optionName = $longOptions[$option]; 01509 else 01510 $optionName = false; 01511 } 01512 else 01513 { 01514 $option = substr( $argument, 1 ); 01515 if ( isset( $shortOptions[$option] ) ) 01516 $optionName = $shortOptions[$option]; 01517 else 01518 $optionName = false; 01519 } 01520 if ( $optionName == 'include-classes' or $optionName == 'exclude-classes' ) 01521 { 01522 if ( count( $nodeItem['node-id-list'] ) > 0 ) 01523 { 01524 $nodeList[] = $nodeItem; 01525 $nodeItem['node-id-list'] = array(); 01526 } 01527 $includeClasses = ( $optionName == 'include-classes' ); 01528 } 01529 else if ( $optionName == 'include-templates' or $optionName == 'exclude-templates' ) 01530 { 01531 if ( count( $nodeItem['node-id-list'] ) > 0 ) 01532 { 01533 $nodeList[] = $nodeItem; 01534 $nodeItem['node-id-list'] = array(); 01535 } 01536 $includeTemplates = ( $optionName == 'include-templates' ); 01537 } 01538 else if ( $optionName == 'node-main' ) 01539 { 01540 $nodeAssignmentType = 'main'; 01541 } 01542 else if ( $optionName == 'node-selected' ) 01543 { 01544 $nodeAssignmentType = 'selected'; 01545 } 01546 else if ( $optionName == 'siteaccess' ) 01547 { 01548 $siteAccessList = explode( ',', $optionValue ); 01549 } 01550 else if ( $optionName == 'language' ) 01551 { 01552 $languageList = explode( ',', $optionValue ); 01553 } 01554 else if ( $optionName == 'current-version' ) 01555 { 01556 $versionType = 'current'; 01557 } 01558 else if ( $optionName == 'all-versions' ) 01559 { 01560 $versionType = 'all'; 01561 } 01562 else if ( $optionName == 'minimal-template-set' ) 01563 { 01564 $minimalTemplateSet = true; 01565 } 01566 } 01567 else 01568 { 01569 $nodeID = false; 01570 $subtree = false; 01571 if ( is_numeric( $argument ) ) 01572 { 01573 $nodeID = (int)$argument; 01574 $node = eZContentObjectTreeNode::fetch( $nodeID ); 01575 if ( !is_object( $node ) ) 01576 { 01577 $error = true; 01578 $nodeID = false; 01579 $cli->notice( "Could not find content-node using ID " . $cli->stylize( 'emphasize', $nodeID ) ); 01580 } 01581 } 01582 else 01583 { 01584 $path = $argument; 01585 if ( preg_match( "#(.+)/\*$#", $path, $matches ) ) 01586 { 01587 $path = $matches[1]; 01588 $subtree = true; 01589 } 01590 $node = eZContentObjectTreeNode::fetchByURLPath( $path ); 01591 if ( is_object( $node ) ) 01592 { 01593 $nodeID = $node->attribute( 'node_id' ); 01594 } 01595 else 01596 { 01597 $cli->notice( "Could not find content-node using path " . $cli->stylize( 'emphasize', $path ) ); 01598 $error = true; 01599 } 01600 } 01601 if ( $nodeID ) 01602 { 01603 $nodeItem['node-id-list'][] = array( 'id' => $nodeID, 01604 'subtree' => $subtree, 01605 'node' => &$node ); 01606 } 01607 if ( $error ) 01608 return false; 01609 } 01610 } 01611 if ( count( $nodeItem['node-id-list'] ) > 0 ) 01612 { 01613 $nodeList[] = $nodeItem; 01614 } 01615 if ( count( $nodeList ) == 0 ) 01616 { 01617 $cli->error( "No objects chosen" ); 01618 return false; 01619 } 01620 if ( count( $languageList ) == 0 ) 01621 { 01622 // The default is to fetch all languages 01623 $languageList = eZContentLanguage::fetchLocaleList(); 01624 } 01625 if ( count( $siteAccessList ) == 0 ) 01626 { 01627 $ini = eZINI::instance(); 01628 $siteAccessList[] = $ini->variable( 'SiteSettings', 'DefaultAccess' ); 01629 } 01630 return array( 'node-list' => $nodeList, 01631 'include-classes' => $includeClasses, 01632 'include-templates' => $includeTemplates, 01633 'siteaccess-list' => $siteAccessList, 01634 'language-list' => $languageList, 01635 'node-assignment-type' => $nodeAssignmentType, 01636 'related-type' => $relatedObjectType, 01637 'embed-type' => $embedObjectType, 01638 'version-type' => $versionType, 01639 'minimal-template-set' => $minimalTemplateSet, 01640 ); 01641 } 01642 01643 function contentObjectDirectory() 01644 { 01645 return 'ezcontentobject'; 01646 } 01647 01648 /*! 01649 \static 01650 Creates DOMNodeElement recursivly from recursive array 01651 */ 01652 static function createElementNodeFromArray( $name, $array ) 01653 { 01654 $dom = new DOMDocument( '1.0', 'utf-8' ); 01655 $node = $dom->createElement( $name ); 01656 $dom->appendChild( $node ); 01657 01658 foreach ( $array as $arrayKey => $value ) 01659 { 01660 if ( is_array( $value ) and 01661 count( $valueKeys = array_keys( $value ) ) > 0 ) 01662 { 01663 if ( is_int( $valueKeys[0] ) ) 01664 { 01665 foreach( $value as $child ) 01666 { 01667 unset( $childNode ); 01668 unset( $importedChildNode ); 01669 $childNode = eZContentObjectPackageHandler::createElementNodeFromArray( $arrayKey, $child ); 01670 $importedChildNode = $dom->importNode( $childNode, true ); 01671 $node->appendChild( $importedChildNode ); 01672 } 01673 } 01674 else 01675 { 01676 unset( $valueNode ); 01677 unset( $importedValueNode ); 01678 $valueNode = eZContentObjectPackageHandler::createElementNodeFromArray( $arrayKey, $value ); 01679 $importedValueNode = $dom->importNode( $valueNode, true ); 01680 $node->appendChild( $importedValueNode ); 01681 } 01682 } 01683 else 01684 { 01685 $node->setAttribute( $arrayKey, $value ); 01686 } 01687 } 01688 return $node; 01689 } 01690 01691 /*! 01692 \static 01693 Creates recursive array from DOMNodeElement 01694 */ 01695 static function createArrayFromDOMNode( $domNode ) 01696 { 01697 if ( !$domNode ) 01698 { 01699 return null; 01700 } 01701 01702 $retArray = array(); 01703 foreach ( $domNode->childNodes as $childNode ) 01704 { 01705 if ( $childNode->nodeType != XML_ELEMENT_NODE ) 01706 { 01707 continue; 01708 } 01709 01710 if ( !isset( $retArray[$childNode->localName] ) ) 01711 { 01712 $retArray[$childNode->localName] = array(); 01713 } 01714 01715 // If the node has children we create an array for this element 01716 // and append to it, if not we assign it directly 01717 if ( $childNode->hasChildNodes() ) 01718 { 01719 $retArray[$childNode->localName][] = eZContentObjectPackageHandler::createArrayFromDOMNode( $childNode ); 01720 } 01721 else 01722 { 01723 $retArray[$childNode->localName] = eZContentObjectPackageHandler::createArrayFromDOMNode( $childNode ); 01724 } 01725 } 01726 foreach( $domNode->attributes as $attributeNode ) 01727 { 01728 $retArray[$attributeNode->name] = $attributeNode->value; 01729 } 01730 01731 return $retArray; 01732 } 01733 01734 public $NodeIDArray = array(); 01735 public $RootNodeIDArray = array(); 01736 public $NodeObjectArray = array(); 01737 public $ObjectArray = array(); 01738 public $RootNodeObjectArray = array(); 01739 public $OverrideSettingsArray = array(); 01740 public $TemplateFileArray = array(); 01741 public $Package = null; 01742 01743 // Static class variables - replacing match values in override.ini 01744 public $OverrideObjectRemoteID = 'content_object_remote_id'; 01745 public $OverrideNodeRemoteID = 'content_node_remote_id'; 01746 public $OverrideParentNodeRemoteID = 'parent_content_node_remote_id'; 01747 public $OverrideClassRemoteID = 'content_class_remote_id'; 01748 } 01749 01750 ?>