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