eZ Publish  [trunk]
ezcontentobjectpackagehandler.php
Go to the documentation of this file.
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 ?>