eZ Publish  [trunk]
ezpackage.php
Go to the documentation of this file.
00001 <?php
00002 /**
00003  * File containing the eZPackage 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   \defgroup package The package manager system
00013   \ingroup package
00014   \class eZPackage ezpackagehandler.php
00015   \brief Maintains eZ Publish packages
00016 
00017 */
00018 
00019 class eZPackage
00020 {
00021     const VERSION = '3.5.2';
00022     const DEVELOPMENT = false;
00023     const USE_CACHE = true;
00024     const CACHE_CODE_DATE = 1069339607;
00025 
00026     const STATUS_ALREADY_EXISTS = 1;
00027     const STATUS_INVALID_NAME = 2;
00028 
00029     const NON_INTERACTIVE = -1;
00030 
00031     /*!
00032      Constructor
00033     */
00034     function eZPackage( $parameters = array(), $repositoryPath = false )
00035     {
00036         $this->setParameters( $parameters );
00037         if ( !$repositoryPath )
00038             $repositoryPath = eZPackage::repositoryPath();
00039         $this->RepositoryPath = $repositoryPath;
00040         $this->RepositoryInformation = null;
00041     }
00042 
00043     /**
00044      * Removes the package directory and all it's subfiles/directories.
00045      */
00046     function remove()
00047     {
00048         $path = $this->path();
00049         if ( file_exists( $path ) )
00050         {
00051             eZDir::recursiveDelete( $path );
00052         }
00053         $this->setInstalled( false );
00054     }
00055 
00056     /*!
00057      \private
00058     */
00059     function setParameters( $parameters = array() )
00060     {
00061         $timestamp = time();
00062         if ( isset( $_SERVER['HOSTNAME'] ) )
00063             $host = $_SERVER['HOSTNAME'];
00064         else if ( isset( $_SERVER['HTTP_HOST'] ) )
00065             $host = $_SERVER['HTTP_HOST'];
00066         else
00067             $host = 'localhost';
00068         $packaging = array( 'timestamp' => $timestamp,
00069                             'host' => $host,
00070                             'packager' => false );
00071         $ezpublishVersion = eZPublishSDK::version( true );
00072         $ezpublishNamedVersion = eZPublishSDK::version( false, false, true );
00073         $ezpublish = array( 'version' => $ezpublishVersion,
00074                             'named-version' => $ezpublishNamedVersion );
00075         $defaults = array( 'name' => false,
00076                            'development' => eZPackage::DEVELOPMENT,
00077                            'summary' => false,
00078                            'description' => false,
00079                            'vendor' => false,
00080                            'vendor-dir' => false,
00081                            'priority' => false,
00082                            'type' => false,
00083                            'extension' => false,
00084                            'install_type' => 'install',
00085                            'ezpublish' => $ezpublish,
00086                            'maintainers' => array(),
00087                            'packaging' => $packaging,
00088                            'source' => false,
00089                            'documents' => array(),
00090                            'groups' => array(),
00091                            'changelog' => array(),
00092                            'file-list' => array(),
00093                            'simple-file-list' => array(),
00094                            'version-number' => false,
00095                            'release-number' => false,
00096                            'release-timestamp' => false,
00097                            'licence' => false,
00098                            'state' => false,
00099                            'dependencies' => array( 'provides' => array(),
00100                                                     'requires' => array(),
00101                                                     'obsoletes' => array(),
00102                                                     'conflicts' => array() ),
00103                            'install' => array(),
00104                            'uninstall' => array() );
00105         $this->PolicyCache = array();
00106         $this->InstallData = array();
00107         $this->Parameters = array_merge( $defaults, $parameters );
00108     }
00109 
00110     /*!
00111      \static
00112      \return An associative array with the possible types for a package.
00113              Each entry contains an \c id and a \c name key.
00114     */
00115     static function typeList()
00116     {
00117         $typeList =& $GLOBALS['eZPackageTypeList'];
00118         if ( !isset( $typeList ) )
00119         {
00120             $typeList = array();
00121             $ini = eZINI::instance( 'package.ini' );
00122             $types = $ini->variable( 'PackageSettings', 'TypeList' );
00123             foreach ( $types as $typeID => $typeName )
00124             {
00125                 $typeList[] = array( 'name' => $typeName,
00126                                      'id' => $typeID );
00127             }
00128         }
00129         return $typeList;
00130     }
00131 
00132     /*!
00133      \static
00134      \return An associative array with the possible states for a package.
00135              Each entry contains an \c id and a \c name key.
00136     */
00137     static function stateList()
00138     {
00139         $stateList =& $GLOBALS['eZPackageStateList'];
00140         if ( !isset( $stateList ) )
00141         {
00142             $stateList = array();
00143             $ini = eZINI::instance( 'package.ini' );
00144             $states = $ini->variable( 'PackageSettings', 'StateList' );
00145             foreach ( $states as $stateID => $stateName )
00146             {
00147                 $stateList[] = array( 'name' => $stateName,
00148                                       'id' => $stateID);
00149             }
00150         }
00151         return $stateList;
00152     }
00153 
00154     /*!
00155      \param $repositoryID The id (string) of the repository to create the package in.
00156                           If \c false it will use the \c local repository.
00157     */
00158     static function create( $name, $parameters = array(), $repositoryPath = false, $repositoryID = false )
00159     {
00160         $parameters['name'] = $name;
00161         $handler = new eZPackage( $parameters, $repositoryPath );
00162 
00163         // New packages always use local repository
00164         if ( $repositoryID === false )
00165             $repositoryID = 'local';
00166         $repositoryInformation = $handler->repositoryInformation( $repositoryID );
00167         if ( $repositoryPath !== false )
00168             $repositoryInformation['path'] = $repositoryPath;
00169         $handler->setCurrentRepositoryInformation( $repositoryInformation );
00170         return $handler;
00171     }
00172 
00173     /*!
00174      \return the attributes for this package.
00175     */
00176     function attributes()
00177     {
00178         return array( 'is_local',
00179                       'development',
00180                       'name', 'summary', 'description',
00181                       'vendor', 'vendor-dir', 'priority', 'type',
00182                       'extension', 'source',
00183                       'version-number', 'release-number', 'release-timestamp',
00184                       'maintainers', 'documents', 'groups',
00185                       'simple-file-list', 'file-list', 'file-count',
00186                       'can_read', 'can_export', 'can_import', 'can_install',
00187                       'changelog', 'dependencies',
00188                       'is_installed',
00189                       'install_type',
00190                       'thumbnail-list',
00191                       'install', 'uninstall',
00192                       'licence', 'state',
00193                       'ezpublish-version', 'ezpublish-named-version', 'packaging-timestamp',
00194                       'packaging-host', 'packaging-packager' );
00195     }
00196 
00197     /*!
00198      Sets the attribute named \a $attributeName to have the value \a $attributeValue.
00199     */
00200     function setAttribute( $attributeName, $attributeValue )
00201     {
00202         if ( !in_array( $attributeName,
00203                         array( 'development',
00204                                'name', 'summary', 'description',
00205                                'vendor', 'vendor-dir', 'priority', 'type',
00206                                'install_type',
00207                                'extension', 'source',
00208                                'licence', 'state' ) ) )
00209             return false;
00210         if ( array_key_exists( $attributeName, $this->Parameters ) and
00211              !is_array( $this->Parameters[$attributeName] ))
00212         {
00213             $this->Parameters[$attributeName] = $attributeValue;
00214             return true;
00215         }
00216         return false;
00217     }
00218 
00219     /*!
00220      \return \c true if the attribute named \a $attributeName exists.
00221     */
00222     function hasAttribute( $attributeName /*, $attributeList = false*/ )
00223     {
00224         return in_array( $attributeName, $this->attributes() );
00225     }
00226 
00227     /*!
00228      \return the value of the attribute named \a $attributeName.
00229     */
00230     function attribute( $attributeName /*, $attributeList = false*/ )
00231     {
00232         if ( in_array( $attributeName,
00233                        array( 'development',
00234                               'name', 'summary', 'description',
00235                               'vendor', 'vendor-dir', 'priority', 'type',
00236                               'extension', 'source',
00237                               'version-number', 'release-number', 'release-timestamp',
00238                               'maintainers', 'documents', 'groups',
00239                               'simple-file-list', 'file-list',
00240                               'changelog', 'dependencies',
00241                               'install', 'uninstall',
00242                               'install_type',
00243                               'licence', 'state', 'settings-files' ) ) )
00244             return $this->Parameters[$attributeName];
00245         else if ( $attributeName == 'is_installed' )
00246             return $this->isInstalled;
00247         else if ( $attributeName == 'ezpublish-version' )
00248             return $this->Parameters['ezpublish']['version'];
00249         else if ( $attributeName == 'ezpublish-named-version' )
00250             return $this->Parameters['ezpublish']['named-version'];
00251         else if ( $attributeName == 'packaging-timestamp' )
00252             return $this->Parameters['packaging']['timestamp'];
00253         else if ( $attributeName == 'packaging-host' )
00254             return $this->Parameters['packaging']['host'];
00255         else if ( $attributeName == 'packaging-packager' )
00256             return $this->Parameters['packaging']['packager'];
00257         else if ( $attributeName == 'can_read' )
00258         {
00259             return $this->canRead();
00260         }
00261         else if ( $attributeName == 'can_export' )
00262         {
00263             return $this->canExport();
00264         }
00265         else if ( $attributeName == 'can_import' )
00266         {
00267             return $this->canImport();
00268         }
00269         else if ( $attributeName == 'can_install' )
00270         {
00271             return $this->canInstall();
00272         }
00273         else if ( $attributeName == 'file-count' )
00274         {
00275             return $this->fileCount();
00276         }
00277         else if ( $attributeName == 'thumbnail-list' )
00278         {
00279             return $this->thumbnailList( 'default' );
00280         }
00281         else if ( $attributeName == 'is_local' )
00282         {
00283             $repositoryInformation = $this->currentRepositoryInformation();
00284             return ( $repositoryInformation['type'] == 'local' );
00285         }
00286 
00287         eZDebug::writeError( "No such attribute: $attributeName for eZPackage", __METHOD__ );
00288         return null;
00289     }
00290 
00291     static function canUsePolicyFunction( $functionName )
00292     {
00293         $currentUser = eZUser::currentUser();
00294         $accessResult = $currentUser->hasAccessTo( 'package', $functionName );
00295         if ( in_array( $accessResult['accessWord'], array( 'yes', 'limited' ) ) )
00296         {
00297             return true;
00298         }
00299         return false;
00300     }
00301 
00302     function canRead()
00303     {
00304         return $this->canUsePackagePolicyFunction( 'read' );
00305     }
00306 
00307     function canExport()
00308     {
00309         return $this->canUsePackagePolicyFunction( 'export' );
00310     }
00311 
00312     function canImport()
00313     {
00314         return $this->canUsePackagePolicyFunction( 'import' );
00315     }
00316 
00317     function canInstall()
00318     {
00319         return $this->canUsePackagePolicyFunction( 'install' );
00320     }
00321 
00322     function canUsePackagePolicyFunction( $functionName )
00323     {
00324         if ( !isset( $this->PolicyCache[$functionName] ) )
00325         {
00326             $currentUser = eZUser::currentUser();
00327             $accessResult = $currentUser->hasAccessTo( 'package', $functionName );
00328             $limitationList = array();
00329             $canUse = false;
00330             if ( $accessResult['accessWord'] == 'yes' )
00331             {
00332                 $this->PolicyCache[$functionName] = true;
00333             }
00334             else if ( $accessResult['accessWord'] == 'limited' )
00335             {
00336                 $allRoles = array();
00337                 $limitationList = $accessResult['policies'];
00338                 $typeList = false;
00339                 foreach( $limitationList as $limitationArray )
00340                 {
00341                     foreach ( $limitationArray as $key => $limitation )
00342                     {
00343                         if ( $key == 'Type' )
00344                         {
00345                             if ( !is_array( $typeList ) )
00346                                 $typeList = array();
00347                             $typeList = array_merge( $typeList, $limitation );
00348                         }
00349                     }
00350                 }
00351                 if ( $typeList === false )
00352                 {
00353                     $this->PolicyCache[$functionName] = true;
00354                 }
00355                 else
00356                 {
00357                     $this->PolicyCache[$functionName] = in_array( $this->attribute( 'type' ), $typeList );
00358                 }
00359             }
00360         }
00361         return $this->PolicyCache[$functionName];
00362     }
00363 
00364     static function fetchMaintainerRoleIDList( $packageType = false, $checkRoles = false )
00365     {
00366         $allRoles = false;
00367         if ( $checkRoles )
00368         {
00369             $currentUser = eZUser::currentUser();
00370             $accessResult = $currentUser->hasAccessTo( 'package', 'create' );
00371             $limitationList = array();
00372             if ( $accessResult['accessWord'] == 'limited' )
00373             {
00374                 $allRoles = array();
00375                 $limitationList = $accessResult['policies'];
00376                 foreach( $limitationList as $limitationArray )
00377                 {
00378                     $allowedType = true;
00379                     $allowedRoles = false;
00380                     foreach ( $limitationArray as $key => $limitation )
00381                     {
00382                         if ( $key == 'Role' )
00383                         {
00384                             $allowedRoles = $limitation;
00385                         }
00386                         else if ( $key == 'Type' )
00387                         {
00388                             $typeList = $limitation;
00389                             if ( $packageType === false )
00390                             {
00391                                 $allowedType = in_array( $packageType, $typeList );
00392                             }
00393                         }
00394                     }
00395                     if ( $allowedType and
00396                          count( $allowedRoles ) > 0 )
00397                     {
00398                         $allRoles = array_merge( $allRoles, $allowedRoles );
00399                     }
00400                 }
00401             }
00402         }
00403         if ( is_array( $allRoles ) and count( $allRoles ) == 0 )
00404             return array();
00405         $ini = eZINI::instance( 'package.ini' );
00406         $roleList = $ini->variable( 'MaintainerSettings', 'RoleList' );
00407         if ( $allRoles !== false )
00408         {
00409             $roleList = array_intersect( $roleList, $allRoles );
00410         }
00411         return $roleList;
00412     }
00413 
00414     static function fetchMaintainerRoleList( $packageType = false, $checkRoles = false )
00415     {
00416         $roleList = eZPackage::fetchMaintainerRoleIDList( $packageType, $checkRoles );
00417         $roleNameList = array();
00418         foreach ( $roleList as $roleID )
00419         {
00420             $roleName = eZPackage::maintainerRoleName( $roleID );
00421             $roleNameList[] = array( 'name' => $roleName,
00422                                      'id' => $roleID );
00423         }
00424         return $roleNameList;
00425     }
00426 
00427     static function maintainerRoleListForRoles()
00428     {
00429         $ini = eZINI::instance( 'package.ini' );
00430         $roleList = $ini->variable( 'MaintainerSettings', 'RoleList' );
00431         $roleNameList = array();
00432         foreach ( $roleList as $roleID )
00433         {
00434             $roleName = eZPackage::maintainerRoleName( $roleID );
00435             $roleNameList[] = array( 'name' => $roleName,
00436                                      'id' => $roleID );
00437         }
00438         return $roleNameList;
00439     }
00440 
00441     static function maintainerRoleName( $roleID )
00442     {
00443         $nameMap = array( 'lead' => ezpI18n::tr( 'kernel/package', 'Lead' ),
00444                           'developer' => ezpI18n::tr( 'kernel/package', 'Developer' ),
00445                           'designer' => ezpI18n::tr( 'kernel/package', 'Designer' ),
00446                           'contributor' => ezpI18n::tr( 'kernel/package', 'Contributor' ),
00447                           'tester' => ezpI18n::tr( 'kernel/package', 'Tester' ) );
00448         if ( isset( $nameMap[$roleID] ) )
00449             return $nameMap[$roleID];
00450         return false;
00451     }
00452 
00453     function appendMaintainer( $name, $email, $role = false )
00454     {
00455         $this->Parameters['maintainers'][] = array( 'name' => $name,
00456                                                     'email' => $email,
00457                                                     'role' => $role );
00458     }
00459 
00460     function appendDocument( $name, $mimeType = false, $os = false, $audience = false,
00461                              $create = false, $data = false )
00462     {
00463         if ( !$mimeType )
00464             $mimeType = 'text/plain';
00465         $this->Parameters['documents'][] = array( 'name' => $name,
00466                                                   'mime-type' => $mimeType,
00467                                                   'os' => $os,
00468                                   //                'create-document' => $create,
00469                                                   'data' => $data,
00470                                                   'audience' => $audience );
00471         if ( $create )
00472         {
00473             eZFile::create( $name, $this->path() . '/' . eZPackage::documentDirectory(),
00474                             $data );
00475         }
00476     }
00477 
00478     function appendGroup( $name )
00479     {
00480         $index = count( $this->Parameters['groups'] );
00481         $this->Parameters['groups'][$index] = array( 'name' => $name );
00482     }
00483 
00484     function appendChange( $person, $email, $changes,
00485                            $release = false, $timestamp = null )
00486     {
00487         if ( $timestamp === null )
00488             $timestamp = time();
00489         if ( !is_array( $changes ) )
00490             $changes = array( $changes );
00491         if ( !$release )
00492             $release = $this->Parameters['release-number'];
00493         if ( !$release )
00494             $release = 1;
00495         $this->Parameters['changelog'][] = array( 'timestamp' => $timestamp,
00496                                                   'person' => $person,
00497                                                   'email' => $email,
00498                                                   'changes' => $changes,
00499                                                   'release' => $release );
00500     }
00501 
00502     static function md5sum( $file )
00503     {
00504         if ( function_exists( 'md5_file' ) )
00505         {
00506             if ( is_file( $file ) )
00507             {
00508                 return md5_file( $file );
00509             }
00510             else
00511             {
00512                 eZDebug::writeError( "Could not open file $file for md5sum calculation" );
00513             }
00514         }
00515         else
00516         {
00517             $fd = @fopen( $file, 'rb' );
00518             if ( $fd )
00519             {
00520                 $data = '';
00521                 while ( !@feof( $fd ) )
00522                 {
00523                     $data .= @fread( $fd, 4096 );
00524                 }
00525                 @fclose( $fd );
00526                 return md5( $data );
00527             }
00528         }
00529         return false;
00530     }
00531 
00532     function fileStorePath( $fileItem, $collectionName, $path = false, $installVariables = array() )
00533     {
00534         $type = $fileItem['type'];
00535         $variableName = $fileItem['variable-name'];
00536         if ( $type == 'file' )
00537         {
00538             $pathArray = array( $path, $fileItem['subdirectory'] );
00539             $pathArray[] = $fileItem['name'];
00540             $path = eZDir::path( $pathArray );
00541         }
00542         else if ( $type == 'design' )
00543         {
00544             $roleFileName = false;
00545             $design = $fileItem['design'];
00546             switch ( $fileItem['role'] )
00547             {
00548                 case 'template':
00549                 {
00550                     $roleFileName = 'templates';
00551                 } break;
00552                 case 'image':
00553                 {
00554                     $roleFileName = 'images';
00555                 } break;
00556                 case 'stylesheet':
00557                 {
00558                     $roleFileName = 'stylesheets';
00559                 } break;
00560                 case 'font':
00561                 {
00562                     $roleFileName = 'fonts';
00563                 } break;
00564             }
00565             if ( $variableName and
00566                  isset( $installVariables[$variableName] ) )
00567                 $design = $installVariables[$variableName];
00568             $pathArray = array( $path, 'design', $design, $roleFileName, $fileItem['subdirectory'] );
00569             if ( $fileItem['file-type'] != 'dir' )
00570                 $pathArray[] = $fileItem['name'];
00571             $path = eZDir::path( $pathArray );
00572         }
00573         else if ( $type == 'ini' )
00574         {
00575             $roleValue = false;
00576             $roleFileName = false;
00577             switch ( $fileItem['role'] )
00578             {
00579                 case 'override':
00580                 {
00581                     $roleFileName = 'override';
00582                 } break;
00583                 case 'siteaccess':
00584                 {
00585                     $roleFileName = 'siteaccess';
00586                     $roleValue = $fileItem['role-value'];
00587                     if ( $variableName and
00588                          isset( $installVariables[$variableName] ) )
00589                         $roleValue = $installVariables[$variableName];
00590                 } break;
00591                 case 'standard':
00592                 default:
00593                 {
00594                     $roleFileName = '';
00595                 } break;
00596             }
00597             $pathArray = array( $path, 'settings', $roleFileName, $roleValue, $fileItem['subdirectory'] );
00598             if ( $fileItem['file-type'] != 'dir' )
00599                 $pathArray[] = $fileItem['name'];
00600             $path = eZDir::path( $pathArray );
00601         }
00602         return $path;
00603     }
00604 
00605     function fileItemPath( $fileItem, $collectionName, $path = false )
00606     {
00607         if ( !$path )
00608         {
00609             $repositoryInformation = $this->currentRepositoryInformation();
00610             $path = $repositoryInformation['path'];
00611         }
00612         $typeDir = $fileItem['type'];
00613         if ( $fileItem['type'] == 'design' )
00614             $typeDir .= '.' . $fileItem['design'];
00615         if ( isset( $fileItem['role'] ) && $fileItem['role'] )
00616         {
00617             $typeDir .= '.' . $fileItem['role'];
00618             if ( $fileItem['role-value'] )
00619                 $typeDir .= '-' . $fileItem['role-value'];
00620         }
00621         $path .= '/' . $this->attribute( 'name' ) . '/' . eZPackage::filesDirectory() . '/' . $collectionName . '/' . $typeDir;
00622         if ( isset( $fileItem['subdirectory'] ) && $fileItem['subdirectory'] )
00623             $path .= '/' . $fileItem['subdirectory'];
00624         $path .= '/' . $fileItem['name'];
00625         return $path;
00626     }
00627 
00628     function fileList( $collectionName )
00629     {
00630         $fileCollections = $this->Parameters['file-list'];
00631         if ( isset( $fileCollections[$collectionName] ) )
00632             return $fileCollections[$collectionName];
00633         return false;
00634     }
00635 
00636     function thumbnailList( $collectionName )
00637     {
00638         $thumbnails = array();
00639         $fileList = $this->fileList( $collectionName );
00640         if ( !is_array( $fileList ) )
00641             return $thumbnails;
00642 
00643         foreach ( $fileList as $fileItem )
00644         {
00645             if ( $fileItem['type'] == 'thumbnail' )
00646             {
00647                 $thumbnails[] = $fileItem;
00648             }
00649         }
00650         return $thumbnails;
00651     }
00652 
00653     function fileCount()
00654     {
00655         $count = 0;
00656         foreach ( $this->Parameters['file-list'] as $collection )
00657         {
00658             $count += count( $collection );
00659         }
00660         return $count;
00661     }
00662 
00663     function appendFile( $file, $type, $role,
00664                          $design, $filePath, $collection,
00665                          $subDirectory = null, $md5 = null,
00666                          $copyFile = false, $modified = null, $fileType = false,
00667                          $roleValue = false, $variableName = false,
00668                          $packagePath = false )
00669     {
00670         if ( !$collection )
00671             $collection = 'default';
00672         if ( $subDirectory === null )
00673         {
00674             $subDirectory = false;
00675             if ( preg_match( '#^(.+)/([^/]+)$#', $file, $matches ) )
00676             {
00677                 $subDirectory = $matches[1];
00678                 $file = $matches[2];
00679             }
00680         }
00681         if ( $packagePath )
00682             $subDirectory = $packagePath;
00683 
00684         $fileItem = array( 'name' => $file,
00685                            'subdirectory' => $subDirectory,
00686                            'type' => $type,
00687                            'role' => $role,
00688                            'role-value' => $roleValue,
00689                            'variable-name' => $variableName,
00690                            'path' => $filePath,
00691                            'file-type' => $fileType,
00692                            'design' => $design );
00693         if ( $md5 === null )
00694         {
00695             $md5 = $this->md5sum( $filePath );
00696         }
00697         $fileItem['md5'] = $md5;
00698         $this->Parameters['file-list'][$collection][] = $fileItem;
00699 
00700         if ( $copyFile )
00701         {
00702             // copying file
00703             $typeDir = $type;
00704             if ( $type == 'design' )
00705                 $typeDir .= '.' . $fileItem['design'];
00706             if ( $role )
00707             {
00708                 $typeDir .= '.' . $role;
00709                 if ( $roleValue )
00710                     $typeDir .= '-' . $roleValue;
00711             }
00712             $path = $this->path() . '/' . eZPackage::filesDirectory() . '/' . $collection . '/' . $typeDir;
00713             if ( $subDirectory )
00714                 $path .= '/' . $subDirectory;
00715             if ( !file_exists( $path ) )
00716                 eZDir::mkdir( $path, false, true );
00717 
00718             if ( is_dir( $fileItem['path'] ) )
00719             {
00720                 eZDir::copy( $fileItem['path'], $path,
00721                              $fileItem['name'] != false, true, false, eZDir::temporaryFileRegexp() );
00722             }
00723             else
00724             {
00725                 eZFileHandler::copy( $fileItem['path'], $path . '/' . $fileItem['name'] );
00726             }
00727         }
00728     }
00729 
00730     /*!
00731      Appends a new \c provides dependency.
00732      \note This function is only a convenience function to the general appendDependency() function.
00733     */
00734     function appendProvides( $type, $name, $value, $parameters = false )
00735     {
00736         $dependencyParameters = array( 'type'  => $type,
00737                                        'name'  => $name,
00738                                        'value' => $value );
00739 
00740         if ( $parameters !== false )
00741             $dependencyParameters = array_merge( $dependencyParameters, $parameters );
00742 
00743         $this->appendDependency( 'provides', $dependencyParameters );
00744     }
00745 
00746     /*!
00747      Appends a new dependency item to the section \a $dependencySection.
00748      \param $dependencySection Can be one of \c provides, \c requires, \c obsoletes, \c conflicts
00749      \param $parameters A list of data specific to the dependency type.
00750     */
00751     function appendDependency( $dependencySection, $parameters )
00752     {
00753         if ( !in_array( $dependencySection,
00754                         array( 'provides', 'requires',
00755                                'obsoletes', 'conflicts' ) ) )
00756             return false;
00757 
00758         $this->Parameters['dependencies'][$dependencySection][] = $parameters;
00759     }
00760 
00761     function dependencyOperatorText( $dependencyItem )
00762     {
00763         return '=';
00764     }
00765 
00766     function createDependencyText( $cli, $dependencyItem, $dependencySection )
00767     {
00768         $text = ( $cli->stylize( 'emphasize', $dependencyItem['type'] ) .
00769                   '(' .
00770                   $cli->stylize( 'emphasize', $dependencyItem['name'] ) .
00771                   ')' );
00772         if ( $dependencyItem['value'] )
00773             $text .= ' ' . $this->dependencyOperatorText( $dependencyItem ) .' ' . $cli->stylize( 'symbol', $dependencyItem['value'] );
00774         $handler = $this->packageHandler( $dependencyItem['type'] );
00775         if ( $handler )
00776         {
00777             $specialText = $handler->createDependencyText( $this, $dependencyItem, $dependencySection );
00778             if ( $specialText )
00779                 $text .= ' ( ' . $specialText . ' ) ';
00780         }
00781         return $text;
00782     }
00783 
00784     function groupDependencyItemsByType( $dependencyItems )
00785     {
00786         $types = array();
00787         foreach ( $dependencyItems as $dependencyItem )
00788         {
00789             if ( !isset( $types[$dependencyItem['type']] ) )
00790                 $types[$dependencyItem['type']] = array();
00791             $types[$dependencyItem['type']][] = $dependencyItem;
00792         }
00793         return $types;
00794     }
00795 
00796     /*!
00797      \return an array with dependency items which match the specified criterias.
00798     */
00799     function dependencyItems( $dependencySection, $parameters = false )
00800     {
00801         if ( !in_array( $dependencySection,
00802                         array( 'provides', 'requires',
00803                                'obsoletes', 'conflicts' ) ) )
00804             return false;
00805 
00806         if ( $parameters === false )
00807         {
00808             return $this->Parameters['dependencies'][$dependencySection];
00809         }
00810 
00811         $matches = array();
00812         $dependencyItems = $this->Parameters['dependencies'][$dependencySection];
00813         foreach ( $dependencyItems as $dependencyItem )
00814         {
00815             $found = true;
00816 
00817             foreach ( $parameters as $paramName => $paramValue )
00818             {
00819                 if ( !isset( $dependencyItem[$paramName] ) ||
00820                      $dependencyItem[$paramName] != $paramValue )
00821                 {
00822                     $found = false;
00823                     break;
00824                 }
00825             }
00826 
00827             if ( $found )
00828                 $matches[] = $dependencyItem;
00829         }
00830 
00831         return $matches;
00832     }
00833 
00834     /*!
00835      \return an array with install items which match the specified criterias.
00836     */
00837     function installItemsList( $type = false, $os = false, $name = false, $isInstall = true )
00838     {
00839         $installName = 'install';
00840         if ( !$isInstall )
00841             $installName = 'uninstall';
00842         if ( !$name and !$type and !$os )
00843         {
00844             return $this->Parameters[$installName];
00845         }
00846         else
00847         {
00848             $matches = array();
00849             $installItems = $this->Parameters[$installName];
00850             foreach ( $installItems as $installItem )
00851             {
00852                 $found = false;
00853                 if ( $name and $installItem['name'] == $name )
00854                     $found = true;
00855                 if ( !$found and $type and $installItem['type'] == $type )
00856                     $found = true;
00857                 if ( !$found )
00858                 {
00859                     if ( $os )
00860                     {
00861                         if ( !$installItem['os'] )
00862                             $found = true;
00863                         else if ( $os and $installItem['os'] == $os )
00864                             $found = true;
00865                     }
00866                     else
00867                         $found = true;
00868                 }
00869                 if ( $found )
00870                     $matches[] = $installItem;
00871             }
00872             return $matches;
00873         }
00874     }
00875 
00876     function appendInstall( $type, $name, $os = false, $isInstall = true,
00877                             $filename = false, $subdirectory = false,
00878                             $parameters = false )
00879     {
00880         $installEntry = $parameters;
00881         $installEntry['type'] = $type;
00882         $installEntry['name'] = $name;
00883         $installEntry['os'] = $os;
00884         $installEntry['filename'] = $filename;
00885         $installEntry['sub-directory'] = $subdirectory;
00886         if ( $installEntry['filename'] )
00887         {
00888             $content = false;
00889             if ( isset( $installEntry['content'] ) )
00890                 $content = $installEntry['content'];
00891             if ( $content instanceof DOMElement )
00892             {
00893                 $path = $this->path();
00894                 if ( $installEntry['sub-directory'] )
00895                 {
00896                     $path .= '/' . $installEntry['sub-directory'];
00897                 }
00898                 $filePath = $path . '/' . $installEntry['filename'] . '.xml';
00899                 if ( !file_exists( $path ) )
00900                 {
00901                     eZDir::mkdir( $path, false, true );
00902                 }
00903                 $partDOM = new DOMDocument( '1.0', 'utf-8' );
00904                 $partDOM->formatOutput = true;
00905                 $contentImport = $partDOM->importNode( $content, true );
00906                 $partDOM->appendChild( $contentImport );
00907                 $this->storeDOM( $filePath, $partDOM );
00908                 $installEntry['content'] = false;
00909             }
00910         }
00911         $installName = 'install';
00912         if ( !$isInstall )
00913             $installName = 'uninstall';
00914         $this->Parameters[$installName][] = $installEntry;
00915     }
00916 
00917     /*!
00918      Sets the packager of this release.
00919     */
00920     function setPackager( $timestamp = false, $host = false, $packager = false )
00921     {
00922         if ( $timestamp )
00923             $this->Parameters['packaging']['timestamp'] = $timestamp;
00924         if ( $host )
00925             $this->Parameters['packaging']['host'] = $host;
00926         if ( $packager )
00927             $this->Parameters['packaging']['packager'] = $packager;
00928     }
00929 
00930     /*!
00931      Sets various release information. If the value is set to \c false it is not updated.
00932      \param $version The version number, eg. 1.0, 2.3.5
00933      \param $release The release number, usually starts at 1 and increments for updates on the same version
00934      \param $timestamp The timestamp of the release
00935      \param $licence The licence of the package, eg. GPL, LGPL etc.
00936      \param $state The sate of the release, e.g alpha, beta, stable etc.
00937     */
00938     function setRelease( $version = false, $release = false, $timestamp = false,
00939                          $licence = false, $state = false )
00940     {
00941         if ( $version !== false )
00942         {
00943             $this->Parameters['version-number'] = $version;
00944         }
00945         if ( $release !== false )
00946         {
00947             $this->Parameters['release-number'] = $release;
00948         }
00949         if ( $timestamp !== false )
00950         {
00951             $this->Parameters['release-timestamp'] = $timestamp;
00952         }
00953         if ( $licence !== false )
00954         {
00955             $this->Parameters['licence'] = $licence;
00956         }
00957         if ( $state !== false )
00958         {
00959             $this->Parameters['state'] = $state;
00960         }
00961     }
00962 
00963     /*!
00964      \private
00965      \return the package as a string, the string is in xml format.
00966     */
00967     function toString()
00968     {
00969         $dom = $this->domStructure();
00970         $string = $dom->saveXML();
00971         return $string;
00972     }
00973 
00974     /*!
00975      \private
00976      Stores a cached version of the package in the cache directory
00977      under the repository for the package.
00978     */
00979     function storeCache( $directory = false )
00980     {
00981         if ( !file_exists( $directory ) )
00982             eZDir::mkdir( $directory, false, true );
00983         $php = new eZPHPCreator( $directory, 'package.php' );
00984         $php->addComment( "Automatically created cache file for the package format\n" .
00985                           "Do not modify this file" );
00986         $php->addSpace();
00987         $php->addVariable( 'CacheCodeDate', eZPackage::CACHE_CODE_DATE );
00988         $php->addSpace();
00989         $php->addVariable( 'Parameters', $this->Parameters, eZPHPCreator::VARIABLE_ASSIGNMENT,
00990                            array( 'full-tree' => true ) );
00991         $php->addVariable( 'InstallData', $this->InstallData, eZPHPCreator::VARIABLE_ASSIGNMENT,
00992                            array( 'full-tree' => true ) );
00993         $php->addVariable( 'RepositoryPath', $this->RepositoryPath );
00994         $php->store();
00995     }
00996 
00997     /*!
00998      Stores the current package in the repository.
00999     */
01000     function store()
01001     {
01002         $path = $this->path();
01003         return $this->storePackageFile( $path );
01004     }
01005 
01006     /*!
01007      Stores the current package definition file to the directory \a $path.
01008     */
01009     function storePackageFile( $path, $storeCache = true )
01010     {
01011         if ( !file_exists( $path ) )
01012         {
01013             eZDir::mkdir( $path, false, true );
01014         }
01015         $filePath = $path . '/' . eZPackage::definitionFilename();
01016 
01017         $packageFileString = $this->toString();
01018         $result = $this->storeString( $filePath, $packageFileString );
01019 
01020         if ( $storeCache )
01021             $this->storeCache( $path . '/' . $this->cacheDirectory() );
01022         return $result;
01023     }
01024 
01025     /*!
01026      Recursively deletes \a $path
01027     */
01028     static function removeFiles( $path )
01029     {
01030         if ( file_exists( $path ) )
01031         {
01032             eZDir::recursiveDelete( $path );
01033         }
01034     }
01035 
01036     /*!
01037      Exports the package as a gzip compressed tarball to the directory \a $archivePath
01038     */
01039     function exportToArchive( $archivePath )
01040     {
01041         $temporaryExportPath = eZPackage::temporaryExportPath();
01042         $tempPath = $temporaryExportPath . '/' . $this->attribute( 'name' );
01043         $this->removeFiles( $tempPath );
01044 
01045         // Create package temp dir and copy package's XML file there
01046         $this->storePackageFile( $tempPath, false );
01047 
01048         // Copy package's directories
01049         $directoryList = array( $this->documentDirectory(),
01050                                 $this->filesDirectory(),
01051                                 $this->simpleFilesDirectory(),
01052                                 $this->settingsDirectory() );
01053         $installItems = $this->Parameters['install'];
01054         foreach( $installItems as $installItem )
01055         {
01056             if ( !in_array( $installItem['sub-directory'], $directoryList ) )
01057                 $directoryList[] = $installItem['sub-directory'];
01058         }
01059 
01060         $path = $this->path();
01061         foreach( $directoryList as $dirName )
01062         {
01063             $destDir = $tempPath;
01064             $dir = $path . '/' . $dirName;
01065             if ( file_exists( $dir ) )
01066                 eZDir::copy( $dir, $destDir );
01067         }
01068 
01069         $tarArchivePath = $temporaryExportPath . '/archive.tmp';
01070         $tarArchive = ezcArchive::open( $tarArchivePath, ezcArchive::TAR_USTAR );
01071         $tarArchive->truncate();
01072 
01073         $prefix = $tempPath . '/';
01074         $fileList = array();
01075         eZDir::recursiveList( $tempPath, $tempPath, $fileList );
01076 
01077         foreach ( $fileList as $fileInfo )
01078         {
01079             $path = $fileInfo['type'] === 'dir' ?
01080                 $fileInfo['path'] . '/' . $fileInfo['name'] . '/' :
01081                 $fileInfo['path'] . '/' . $fileInfo['name'];
01082             $tarArchive->append( array( $path ), $prefix );
01083         }
01084 
01085         $tarArchive->close();
01086 
01087         copy( $tarArchivePath, "compress.zlib://$archivePath" );
01088 
01089         unlink( $tarArchivePath );
01090 
01091         $this->removeFiles( $tempPath );
01092         return $archivePath;
01093     }
01094 
01095     /**
01096      * Imports a package from a gzip compressed tarball file
01097      *
01098      * @param string $archiveName Path to the archive file
01099      * @param string $packageName Package name
01100      * @param bool $dbAvailable
01101      * @param bool $repositoryID
01102      *
01103      * @return eZPackage The eZPackage object if successfull, or one of the
01104      *         STATUS_* class constants if an error occurs
01105      */
01106     static function import( $archiveName, &$packageName, $dbAvailable = true, $repositoryID = false )
01107     {
01108         if ( is_dir( $archiveName ) )
01109         {
01110             eZDebug::writeError( "Importing from directory is not supported." );
01111             $retValue = false;
01112             return $retValue;
01113         }
01114         else
01115         {
01116             $tempDirPath = eZPackage::temporaryImportPath();
01117             // make a temporary directory to extract the package file to
01118             do
01119             {
01120                 $archivePath = eZDir::path( array( $tempDirPath, mt_rand() ) );
01121             } while ( file_exists( $archivePath ) );
01122 
01123             eZDir::mkdir( $archivePath, false, true );
01124 
01125             $archiveOptions = new ezcArchiveOptions( array( 'readOnly' => true ) );
01126 
01127             // Fix for issue #15891: ezjscore - file names are cutted
01128             // Force the type of the archive as ezcArchive::TAR_GNU so that long file names are supported on Windows
01129             // The previous value for the second parameter was null which meant the type was guessed from the
01130             // archive, but on Windows it was detected as TAR_USTAR and this lead to filenames being limited
01131             // to 100 characters
01132             $archive = ezcArchive::open( "compress.zlib://$archiveName", ezcArchive::TAR_GNU, $archiveOptions );
01133 
01134             $fileList = array();
01135             $fileList[] = eZPackage::definitionFilename();
01136 
01137             // Search for the files we want to extract
01138             foreach( $archive as $entry )
01139             {
01140                 if ( in_array( $entry->getPath(), $fileList ) )
01141                 {
01142                     if ( !$archive->extractCurrent( $archivePath ) )
01143                     {
01144                         eZDebug::writeError( "Failed extracting package definition file from $archivePath" );
01145                         return false;
01146                     }
01147                 }
01148             }
01149 
01150             $definitionFileName = eZDir::path( array( $archivePath, self::definitionFilename() ) );
01151 
01152             $package = eZPackage::fetchFromFile( $definitionFileName );
01153 
01154             eZPackage::removeFiles( $archivePath );
01155 
01156             if ( $package )
01157             {
01158                 $packageName = $package->attribute( 'name' );
01159 
01160                 if ( !self::isValidName( $packageName ) )
01161                 {
01162                     return eZPackage::STATUS_INVALID_NAME;
01163                 }
01164 
01165                 if ( !$repositoryID )
01166                 {
01167                     $repositoryID = $package->attribute( 'vendor-dir' );
01168                 }
01169 
01170                 $existingPackage = eZPackage::fetch( $packageName, false, false, $dbAvailable );
01171                 if ( $existingPackage )
01172                 {
01173                     return eZPackage::STATUS_ALREADY_EXISTS;
01174                 }
01175 
01176                 unset( $package );
01177 
01178                 $fullRepositoryPath = eZPackage::repositoryPath() . '/' . $repositoryID;
01179                 $packagePath = $fullRepositoryPath . '/' . $packageName;
01180                 if ( !file_exists( $packagePath ) )
01181                 {
01182                     eZDir::mkdir( $packagePath, false, true );
01183                 }
01184                 $archive->extract( $packagePath );
01185 
01186                 $package = eZPackage::fetch( $packageName, $fullRepositoryPath, false, $dbAvailable );
01187                 if ( !$package )
01188                 {
01189                     eZDebug::writeError( "Failed loading imported package $packageName from $fullRepositoryPath" );
01190                 }
01191             }
01192             else
01193             {
01194                 eZDebug::writeError( "Failed loading temporary package $packageName" );
01195             }
01196 
01197             return $package;
01198         }
01199     }
01200 
01201     /*!
01202      \static
01203      \return the suffix for all package files.
01204     */
01205     static function suffix()
01206     {
01207         return 'ezpkg';
01208     }
01209 
01210     /*!
01211      \return the file name for an exported archive of the current package
01212     */
01213     function exportName()
01214     {
01215         return $this->attribute( 'name' ) . '-' . $this->attribute( 'version-number' ) . '-' . $this->attribute( 'release-number' ) . '.' . eZPackage::suffix();
01216     }
01217 
01218     /*!
01219      Stores the current package to the file \a $filename.
01220     */
01221     function storeToFile( $filename )
01222     {
01223         $dom = $this->domStructure();
01224         return eZPackage::storeDOM( $filename, $dom );
01225     }
01226 
01227     /*!
01228      Applies the storage file permissions specified in site.ini to the file \a $filename
01229     */
01230     static function applyStorageFilePermissions( $filename )
01231     {
01232         $siteConfig = eZINI::instance( 'site.ini' );
01233         $filePermissions = $siteConfig->variable( 'FileSettings', 'StorageFilePermissions');
01234         chmod( $filename, octdec( $filePermissions ) );
01235     }
01236 
01237     /*!
01238      Stores the DOM tree \a $dom to the file \a $filename.
01239     */
01240     static function storeDOM( $filename, $dom )
01241     {
01242         $bytes = $dom->save( $filename );
01243 
01244         if ( $bytes !== false )
01245         {
01246             eZPackage::applyStorageFilePermissions( $filename );
01247 
01248             eZDebugSetting::writeNotice( 'kernel-ezpackage-store',
01249                                          "Stored file $filename",
01250                                          'eZPackage::storeDOM' );
01251             return true;
01252         }
01253         else
01254         {
01255             eZDebug::writeError( "Saving DOM tree to $filename failed", __METHOD__ );
01256         }
01257 
01258         return false;
01259     }
01260 
01261     /*!
01262      \private
01263      \static
01264      Stores the string data \a $data into the file \a $filename.
01265      \return \c true if successful.
01266     */
01267     static function storeString( $filename, $data )
01268     {
01269         $file = @fopen( $filename, 'w' );
01270         if ( $file )
01271         {
01272             fwrite( $file, $data );
01273             fclose( $file );
01274 
01275             eZPackage::applyStorageFilePermissions( $filename );
01276 
01277             eZDebugSetting::writeNotice( 'kernel-ezpackage-store',
01278                                          "Stored file $filename",
01279                                          'eZPackage::storeString' );
01280             return true;
01281         }
01282         else
01283         {
01284             eZDebug::writeError( "Failed to write package '$filename'" );
01285         }
01286         return false;
01287     }
01288 
01289 
01290     /*!
01291      \private
01292      Loads the contents of the file \a $filename and parses it into a DOM tree.
01293      The DOM tree is returned.
01294     */
01295     static function fetchDOMFromFile( $filename )
01296     {
01297         if ( file_exists( $filename ) )
01298         {
01299             $dom = new DOMDocument( '1.0', 'utf-8' );
01300             $dom->preserveWhiteSpace = false;
01301             $success = $dom->load( $filename );
01302 
01303             if ( !$success )
01304             {
01305                 return false;
01306             }
01307             else
01308             {
01309                 return $dom;
01310             }
01311         }
01312         return false;
01313     }
01314 
01315     /*!
01316      \static
01317      Tries to load the package definition from file \a $filename
01318      and create a package object from it.
01319      \return \c false if it could be fetched.
01320     */
01321     static function fetchFromFile( $filename )
01322     {
01323         $dom = eZPackage::fetchDOMFromFile( $filename );
01324 
01325         if ( $dom === false )
01326         {
01327             return false;
01328         }
01329 
01330         $package = new eZPackage();
01331         $parameters = $package->parseDOMTree( $dom );
01332         if ( !$parameters )
01333         {
01334             return false;
01335         }
01336 
01337         return $package;
01338     }
01339 
01340     /*!
01341      \static
01342      Tries to load the package named \a $packageName from the repository
01343      and returns the package object.
01344      \param $repositoryID Determines in which repositories the package should be searched for,
01345                           if set to \c true it means only look in local packages, \c false means
01346                           look in all repositories.
01347      \param $dbAvailable  Do we have a database to fetch additional package info, like installed state.
01348                           (false in setup wizard)
01349      \return \c false if no package could be found.
01350     */
01351     static function fetch( $packageName, $packagePath = false, $repositoryID = false, $dbAvailable = true )
01352     {
01353         $packageRepositories = eZPackage::packageRepositories( array( 'path' => $packagePath ) );
01354 
01355         if ( $repositoryID === true )
01356             $repositoryID = 'local';
01357 
01358         foreach ( $packageRepositories as $packageRepository )
01359         {
01360             if ( $repositoryID !== false and
01361                  $packageRepository['id'] != $repositoryID )
01362                 continue;
01363             $path = $packageRepository['path'];
01364 
01365             $path .= '/' . $packageName;
01366             $filePath = $path . '/' . eZPackage::definitionFilename();
01367 
01368             if ( file_exists( $filePath ) )
01369             {
01370                 $fileModification = filemtime( $filePath );
01371                 $package = false;
01372                 $cacheExpired = false;
01373 
01374                 if ( eZPackage::useCache() )
01375                 {
01376                     $package = eZPackage::fetchFromCache( $path, $fileModification, $cacheExpired );
01377                 }
01378 
01379                 if ( $package )
01380                 {
01381                     $package->setCurrentRepositoryInformation( $packageRepository );
01382                 }
01383                 else
01384                 {
01385                     $package = eZPackage::fetchFromFile( $filePath );
01386 
01387                     if ( $package )
01388                     {
01389                         $package->setCurrentRepositoryInformation( $packageRepository );
01390                         if ( $packagePath )
01391                             $package->RepositoryPath = $packagePath;
01392                         if ( $cacheExpired and
01393                              eZPackage::useCache() )
01394                         {
01395                             $package->storeCache( $path . '/' . eZPackage::cacheDirectory() );
01396                         }
01397                     }
01398                 }
01399                 if ( $dbAvailable )
01400                     $package->getInstallState();
01401 
01402                 return $package;
01403             }
01404         }
01405         return false;
01406     }
01407 
01408     static function useCache()
01409     {
01410         return eZPackage::USE_CACHE;
01411     }
01412 
01413     /*!
01414      \private
01415     */
01416     static function fetchFromCache( $packagePath, $packageModification, &$cacheExpired )
01417     {
01418         $packageCachePath = $packagePath . '/' . eZPackage::cacheDirectory() . '/package.php';
01419 
01420         if ( file_exists( $packageCachePath ) )
01421         {
01422             $cacheModification = filemtime( $packageCachePath );
01423             if ( $cacheModification >= $packageModification )
01424             {
01425                 include( $packageCachePath );
01426                 if ( !isset( $CacheCodeDate ) or
01427                      $CacheCodeDate != eZPackage::CACHE_CODE_DATE )
01428                 {
01429                     $cacheExpired = true;
01430                     return false;
01431                 }
01432                 if ( isset( $Parameters ) and
01433                      isset( $InstallData ) )
01434                 {
01435                     $cacheExpired = false;
01436                     $package = new eZPackage( $Parameters, $RepositoryPath );
01437                     $package->InstallData = $InstallData;
01438                     return $package;
01439                 }
01440             }
01441             else
01442                 $cacheExpired = true;
01443         }
01444         $cacheExpired = true;
01445         return false;
01446     }
01447 
01448     /*!
01449      \return the full path to this package.
01450     */
01451     function path()
01452     {
01453         $path = $this->currentRepositoryPath();
01454         $path .= '/' . $this->attribute( 'name' );
01455         return $path;
01456     }
01457 
01458     /*!
01459      \return the path to the current repository.
01460     */
01461     function currentRepositoryPath()
01462     {
01463         $repositoryInformation = $this->currentRepositoryInformation();
01464         if ( $repositoryInformation )
01465             return $repositoryInformation['path'];
01466         return $this->RepositoryPath;
01467     }
01468 
01469     /*!
01470      \static
01471      \return the directory name for temporary export packages, used in conjunction with eZSys::cacheDirectory().
01472     */
01473     static function temporaryExportPath()
01474     {
01475         $path = eZDir::path( array( eZSys::cacheDirectory(),
01476                                     'packages',
01477                                     'export' . eZUser::currentUserID() ) );
01478         return $path;
01479     }
01480 
01481     /*!
01482      \static
01483      \return the directory name for temporary import packages, used in conjunction with eZSys::cacheDirectory().
01484     */
01485     static function temporaryImportPath()
01486     {
01487         $path = eZDir::path( array( eZSys::cacheDirectory(),
01488                                     'packages',
01489                                     'import' ) );
01490         return $path;
01491     }
01492 
01493     /*!
01494      \static
01495      \return the path to the package repository.
01496     */
01497     static function repositoryPath()
01498     {
01499         $ini = eZINI::instance();
01500         $packageIni = eZINI::instance( 'package.ini' );
01501 
01502         return eZDir::path( array( 'var',
01503                                    $ini->variable( 'FileSettings', 'StorageDir' ),
01504                                    $packageIni->variable( 'RepositorySettings', 'RepositoryDirectory' ) ) );
01505     }
01506 
01507     /*!
01508      \static
01509      \return the name of the cache directory for cached package data.
01510     */
01511     static function cacheDirectory()
01512     {
01513         return '.cache';
01514     }
01515 
01516     /*!
01517      \static
01518      \return the name of the package definition file.
01519     */
01520     static function definitionFilename()
01521     {
01522         return 'package.xml';
01523     }
01524 
01525     /*!
01526      \static
01527      \return the name of the documents directory for cached package data.
01528     */
01529     static function documentDirectory()
01530     {
01531         return 'documents';
01532     }
01533 
01534     /*!
01535      \static
01536      \return the name of the documents directory for cached package data.
01537     */
01538     static function filesDirectory()
01539     {
01540         return 'files';
01541     }
01542 
01543     /*!
01544      \private
01545      Get local simple file path
01546     */
01547     static function simpleFilesDirectory()
01548     {
01549         return 'simplefiles';
01550     }
01551 
01552     static function settingsDirectory()
01553     {
01554         return 'settings';
01555     }
01556 
01557     /*!
01558      Locates all dependent packages in the repository and returns an array with eZPackage objects.
01559      \param $dependencyType is the name of a dependency sub-node. (ie. 'provides', 'requires' etc...)
01560     */
01561     function fetchDependentPackages( $dependencyType, &$failedList )
01562     {
01563         $packages = array();
01564         $provides = $this->Parameters['dependencies'][$dependencyType];
01565 
01566         if ( $provides != null )
01567         {
01568             foreach ( $provides as $provide )
01569             {
01570                 // fetch only dependent packages, not package items.
01571                 if ( $provide['type'] == 'ezpackage' )
01572                 {
01573                     // TODO: Add fetching from URL (not here ?)
01574                     $package = $this->fetch( $provide['name'] );
01575 
01576                     if ( !$package )
01577                     {
01578                         $failedList[] = $provide['name'];
01579                         continue;
01580                     }
01581                     $packages[] =& $package;
01582                 }
01583             }
01584         }
01585         return $packages;
01586     }
01587 
01588     /*!
01589      \static
01590      \return an array with repositories which can contain packages.
01591 
01592      Each repository entry is an array with the following keys.
01593      - path The path to the repository relative from the eZ Publish installation
01594      - id   Unique identifier for this repository
01595      - name Human readable string identifying this repository, the name is translatable
01596      - type What kind of repository, currently supports local or global.
01597     */
01598     static function packageRepositories( $parameters = array() )
01599     {
01600         if ( isset( $parameters['path'] ) and $parameters['path'] )
01601         {
01602             $path = $parameters['path'];
01603             $packageRepositories = array( array( 'path' => $path,
01604                                              'id' => 'local',
01605                                              'name' => ezpI18n::tr( 'kernel/package', 'Local' ),
01606                                              'type' => 'local' ) );
01607         }
01608         else
01609         {
01610             $repositoryPath = eZPackage::repositoryPath();
01611             $packageRepositories = array( array( 'path' => $repositoryPath . '/local',
01612                                                  'id' => 'local',
01613                                                  'name' => ezpI18n::tr( 'kernel/package', 'Local' ),
01614                                                  'type' => 'local' ) );
01615 
01616             $subdirs = eZDir::findSubitems( $repositoryPath, 'd' );
01617             foreach( $subdirs as $dir )
01618             {
01619                 if ( $dir == 'local' )
01620                     continue;
01621 
01622                 $packageRepositories[] = array( 'path' => $repositoryPath . '/' . $dir,
01623                                                 'id' => $dir,
01624                                                 'name' => $dir,
01625                                                 'type' => 'global' );
01626             }
01627         }
01628         return $packageRepositories;
01629     }
01630 
01631     /*!
01632      \static
01633      \return information on the repository with ID $repositoryID or \c false if does not exist.
01634     */
01635     static function repositoryInformation( $repositoryID )
01636     {
01637         $packageRepositories = eZPackage::packageRepositories();
01638         foreach ( $packageRepositories as $packageRepository )
01639         {
01640             if ( $packageRepository['id'] == $repositoryID )
01641                 return $packageRepository;
01642         }
01643         return false;
01644     }
01645 
01646     /*!
01647      \static
01648      \return information on the eZ system repository or \c false if does not exist.
01649     */
01650     static function systemRepositoryInformation()
01651     {
01652         $ini = eZINI::instance( 'package.ini' );
01653         $vendor = $ini->variable( 'RepositorySettings', 'Vendor' );
01654         return eZPackage::repositoryInformation( $vendor );
01655     }
01656 
01657     /*!
01658      Sets the current repository information for the package.
01659      \sa currentRepositoryInformation, packageRepositories
01660     */
01661     function setCurrentRepositoryInformation( $information )
01662     {
01663         $this->RepositoryInformation = $information;
01664     }
01665 
01666     /*!
01667      \return the current repository information for the package, this
01668              will contain information of where the package was found.
01669      See packageRepositories too see what the information will contain.
01670      \note The return information can be \c null in some cases when the package is not properly initialized.
01671     */
01672     function currentRepositoryInformation()
01673     {
01674         return $this->RepositoryInformation;
01675     }
01676 
01677     /*!
01678      Locates all packages in the repository and returns an array with eZPackage objects.
01679 
01680      \param parameters
01681      \param filterArray
01682     */
01683     static function fetchPackages( $parameters = array(), $filterArray = array() )
01684     {
01685         $packageRepositories = eZPackage::packageRepositories( $parameters );
01686 
01687         $packages = array();
01688 
01689         $requiredType = null;
01690         $requiredPriority = null;
01691         $requiredVendor = null;
01692         $requiredExtension = null;
01693         if ( isset( $filterArray['type'] ) )
01694             $requiredType = $filterArray['type'];
01695         if ( isset( $filterArray['priority'] ) )
01696             $requiredPriority = $filterArray['priority'];
01697         if ( isset( $filterArray['vendor'] ) )
01698             $requiredVendor = $filterArray['vendor'];
01699         if ( isset( $filterArray['extension'] ) )
01700             $requiredExtension = $filterArray['extension'];
01701         $repositoryID = false;
01702         if ( isset( $parameters['repository_id'] ) )
01703             $repositoryID = $parameters['repository_id'];
01704         $dbAvailable = true;
01705         if ( isset( $parameters['db_available'] ) )
01706             $dbAvailable = $parameters['db_available'];
01707 
01708         foreach ( $packageRepositories as $packageRepository )
01709         {
01710             if ( strlen( $repositoryID ) == 0 or
01711                  $repositoryID == $packageRepository['id'] )
01712             {
01713                 $path = $packageRepository['path'];
01714                 if ( file_exists( $path ) )
01715                 {
01716                     $fileList = array();
01717                     $dir = opendir( $path );
01718                     while( ( $file = readdir( $dir ) ) !== false )
01719                     {
01720                         if ( $file == '.' or
01721                              $file == '..' )
01722                             continue;
01723                         $fileList[] = $file;
01724                     }
01725                     closedir( $dir );
01726                     sort( $fileList );
01727                     foreach ( $fileList as $file )
01728                     {
01729                         $dirPath = $path . '/' . $file;
01730                         if ( !is_dir( $dirPath ) )
01731                             continue;
01732                         $filePath = $dirPath . '/' . eZPackage::definitionFilename();
01733                         if ( file_exists( $filePath ) )
01734                         {
01735                             $fileModification = filemtime( $filePath );
01736                             $name = $file;
01737                             $packageCachePath = $dirPath . '/' . eZPackage::cacheDirectory() . '/package.php';
01738                             unset( $package );
01739                             $package = false;
01740                             $cacheExpired = false;
01741                             if ( eZPackage::useCache() )
01742                             {
01743                                 $package = eZPackage::fetchFromCache( $dirPath, $fileModification, $cacheExpired );
01744                             }
01745                             if ( !$package )
01746                             {
01747                                 $package = eZPackage::fetchFromFile( $filePath );
01748                                 if ( $package and
01749                                      $cacheExpired and
01750                                      eZPackage::useCache() )
01751                                 {
01752                                     $package->storeCache( $dirPath . '/' . eZPackage::cacheDirectory() );
01753                                 }
01754                             }
01755                             if ( !$package )
01756                                 continue;
01757 
01758                             if ( $dbAvailable )
01759                                 $package->getInstallState();
01760 
01761                             if ( $requiredType !== null )
01762                             {
01763                                 $type = $package->attribute( 'type' );
01764                                 if ( $type != $requiredType )
01765                                     continue;
01766                             }
01767 
01768                             if ( $requiredPriority !== null )
01769                             {
01770                                 $priority = $package->attribute( 'priority' );
01771                                 if ( $priority != $requiredPriority )
01772                                     continue;
01773                             }
01774 
01775                             if ( $requiredExtension !== null )
01776                             {
01777                                 $extension = $package->attribute( 'extension' );
01778                                 if ( $extension != $requiredExtension )
01779                                     continue;
01780                             }
01781 
01782                             if ( $requiredVendor !== null )
01783                             {
01784                                 $vendor = $package->attribute( 'vendor' );
01785                                 if ( $vendor != $requiredVendor )
01786                                     continue;
01787                             }
01788 
01789                             $package->setCurrentRepositoryInformation( $packageRepository );
01790 
01791                             $packages[] =& $package;
01792                         }
01793                     }
01794                 }
01795             }
01796         }
01797         return $packages;
01798     }
01799 
01800     /*!
01801      Install specified install item in package
01802 
01803      \param Item index
01804      \param parameters
01805     */
01806     function installItem( $item, &$installParameters )
01807     {
01808         $type = $item['type'];
01809         $name = $item['name'];
01810         $os = $item['os'];
01811         $filename = $item['filename'];
01812         $subdirectory = $item['sub-directory'];
01813         $content = false;
01814         if ( isset( $item['content'] ) )
01815             $content = $item['content'];
01816         $handler = $this->packageHandler( $type );
01817         $installResult = false;
01818         if ( $handler )
01819         {
01820             if ( $handler->extractInstallContent() )
01821             {
01822                 if ( !$content and
01823                      $filename )
01824                 {
01825                     if ( $subdirectory )
01826                         $filepath = $subdirectory . '/' . $filename . '.xml';
01827                     else
01828                         $filepath = $filename . '.xml';
01829 
01830                     $filepath = $this->path() . '/' . $filepath;
01831 
01832                     $dom = eZPackage::fetchDOMFromFile( $filepath );
01833                     if ( $dom )
01834                     {
01835                         $content = $dom->documentElement;
01836                     }
01837                     else
01838                     {
01839                         eZDebug::writeError( "Failed fetching dom from file $filepath", __METHOD__ );
01840                     }
01841                 }
01842             }
01843             $installData =& $this->InstallData[$type];
01844             if ( !isset( $installData ) )
01845                 $installData = array();
01846             $installResult = $handler->install( $this, $type, $item,
01847                                                 $name, $os, $filename, $subdirectory,
01848                                                 $content, $installParameters,
01849                                                 $installData );
01850         }
01851         return $installResult;
01852     }
01853 
01854     /**
01855      * Installs all items in the package
01856      *
01857      * @param array $installParameters
01858      *
01859      * @return bool true if all items installed correctly, false otherwise
01860      */
01861     function install( &$installParameters )
01862     {
01863         if ( $this->Parameters['install_type'] != 'install' )
01864             return;
01865         $installItems = $this->Parameters['install'];
01866         if ( !isset( $installParameters['path'] ) )
01867             $installParameters['path'] = false;
01868         $installResult = true;
01869         foreach ( $installItems as $item )
01870         {
01871             if ( !$this->installItem( $item, $installParameters ) )
01872             {
01873                 eZDebug::writeDebug( $item, 'item which failed installing' );
01874                 $installResult = false;
01875             }
01876         }
01877         $this->setInstalled();
01878         return $installResult;
01879     }
01880 
01881     function uninstallItem( $item, &$uninstallParameters )
01882     {
01883         $type = $item['type'];
01884         $name = $item['name'];
01885         $os = $item['os'];
01886         $filename = $item['filename'];
01887         $subdirectory = $item['sub-directory'];
01888         $content = false;
01889         if ( isset( $item['content'] ) )
01890             $content = $item['content'];
01891 
01892         $handler = $this->packageHandler( $type );
01893         if ( $handler )
01894         {
01895             if ( $handler->extractInstallContent() )
01896             {
01897                 if ( !$content and
01898                      $filename )
01899                 {
01900                     if ( $subdirectory )
01901                         $filepath = $subdirectory . '/' . $filename . '.xml';
01902                     else
01903                         $filepath = $filename . '.xml';
01904 
01905                     $filepath = $this->path() . '/' . $filepath;
01906 
01907                     $dom = eZPackage::fetchDOMFromFile( $filepath );
01908                     if ( $dom )
01909                     {
01910                         $content = $dom->documentElement;
01911                     }
01912                     else
01913                     {
01914                         eZDebug::writeError( "Failed fetching dom from file $filepath", __METHOD__ );
01915                     }
01916                 }
01917             }
01918 
01919             if ( isset( $this->InstallData[$type] ) )
01920             {
01921                 $installData =& $this->InstallData[$type];
01922             }
01923             else
01924             {
01925                 unset( $installData );
01926                 $installData = array();
01927             }
01928             $uninstallResult = $handler->uninstall( $this, $type, $item,
01929                                                   $name, $os, $filename, $subdirectory,
01930                                                   $content, $uninstallParameters,
01931                                                   $installData );
01932         }
01933         return $uninstallResult;
01934     }
01935 
01936     /*!
01937      Install all install items in package
01938     */
01939     function uninstall( $uninstallParameters = array() )
01940     {
01941         if ( $this->Parameters['install_type'] != 'install' )
01942             return;
01943         if ( !$this->isInstalled() )
01944             return;
01945         $uninstallItems = $this->installItemsList();
01946         if ( !isset( $installParameters['path'] ) )
01947             $installParameters['path'] = false;
01948 
01949         $uninstallResult = true;
01950         foreach ( $uninstallItems as $item )
01951         {
01952             if ( !$this->uninstallItem( $item, $uninstallParameters ) )
01953             {
01954                 $uninstallResult = false;
01955             }
01956         }
01957 
01958         $this->InstallData = array();
01959         $this->setInstalled( false );
01960         return $uninstallResult;
01961     }
01962 
01963     /*!
01964      \private
01965     */
01966     function parseDOMTree( DOMDocument $dom )
01967     {
01968         $root = $dom->documentElement;
01969 
01970         // Read basic info
01971         $parameters = array();
01972         $parameters['name'] = $root->getElementsByTagName( 'name' )->item( 0 )->textContent;
01973         $vendorNode = $root->getElementsByTagName( 'vendor' )->item( 0 );
01974         $parameters['vendor'] = is_object( $vendorNode ) ? $vendorNode->textContent : false;
01975         $parameters['summary'] = $root->getElementsByTagName( 'summary' )->item( 0 )->textContent;
01976         $parameters['description'] = $root->getElementsByTagName( 'description' )->item( 0 )->textContent;
01977         $priorities = $root->getElementsByTagName( 'priority' );
01978         if ( $priorities->length > 0 )
01979         {
01980             $parameters['priority'] = $priorities->item( 0 )->getAttribute( 'value' );
01981         }
01982         $parameters['type'] = $root->getElementsByTagName( 'type' )->item( 0 )->getAttribute( 'value' );
01983 
01984         if ( $parameters['vendor'] )
01985         {
01986            // Creating nice vendor directory name
01987            $trans = eZCharTransform::instance();
01988            $parameters['vendor-dir'] = $trans->transformByGroup( $parameters['vendor'], 'urlalias' );
01989         }
01990         else
01991         {
01992             $parameters['vendor-dir'] = 'local';
01993         }
01994 
01995         $parameters['install_type'] = 'install';
01996         $installType = $root->getAttribute( 'install_type' );
01997         if ( $installType )
01998             $parameters['install_type'] = $installType;
01999         $sourceNodes = $root->getElementsByTagName( 'source' );
02000         if ( $sourceNodes->length > 0 )
02001         {
02002             $parameters['source'] = $sourceNodes->item( 0 )->textContent;
02003         }
02004         $parameters['development'] = $root->getAttribute( 'development' ) == 'true';
02005         $extensionNode = $root->getElementsByTagName( 'extension' )->item( 0 );
02006         if ( $extensionNode )
02007             $parameters['extension'] = $extensionNode->getAttribute( 'name' );
02008         $ezpublishNode = $root->getElementsByTagName( 'ezpublish' )->item( 0 );
02009         $parameters['ezpublish']['version'] = $ezpublishNode->getElementsByTagName( 'version' )->item( 0 )->textContent;
02010         $parameters['ezpublish']['named-version'] = $ezpublishNode->getElementsByTagName( 'named-version' )->item( 0 )->textContent;
02011         $this->setParameters( $parameters );
02012 
02013         // Read maintainers
02014         $maintainersNode = $root->getElementsByTagName( 'maintainers' )->item( 0 );
02015         if ( $maintainersNode )
02016         {
02017             $maintainerNodes = $maintainersNode->getElementsByTagName( 'maintainer' );
02018             foreach ( $maintainerNodes as $maintainerNode )
02019             {
02020                 $maintainerName = $maintainerNode->getElementsByTagName( 'name' )->item( 0 )->textContent;
02021                 $maintainerEmail = $maintainerNode->getElementsByTagName( 'email' )->item( 0 )->textContent;
02022                 $maintainerRole = $maintainerNode->getElementsByTagName( 'role' )->item( 0 )->textContent;
02023                 $this->appendMaintainer( $maintainerName, $maintainerEmail, $maintainerRole );
02024             }
02025         }
02026 
02027         // Read packaging info
02028         $packagingNode = $root->getElementsByTagName( 'packaging' )->item( 0 );
02029         $packagingTimestamp = $packagingNode->getElementsByTagName( 'timestamp' )->item( 0 )->textContent;
02030         $packagingHost = $packagingNode->getElementsByTagName( 'host' )->item( 0 )->textContent;
02031         $packagerNodes = $packagingNode->getElementsByTagName( 'packager' );
02032         if ( $packagerNodes->length > 0 )
02033         {
02034             $packagingPackager = $packagerNodes->item( 0 )->textContent;
02035         }
02036         else
02037         {
02038             $packagingPackager = false;
02039         }
02040         $this->setPackager( $packagingTimestamp, $packagingHost, $packagingPackager );
02041 
02042         // Read documents
02043         $documentsNode = $root->getElementsByTagName( 'documents' )->item( 0 );
02044         $documentNodes = $documentsNode->getElementsByTagName( 'document' );
02045 
02046         foreach ( $documentNodes as $documentNode )
02047         {
02048             $documentName = $documentNode->getAttribute( 'name' );
02049             $documentMimeType = $documentNode->getAttribute( 'mime-type' );
02050             $documentOS = $documentNode->getAttribute( 'os' );
02051             $documentAudience = $documentNode->getAttribute( 'audience' );
02052             $this->appendDocument( $documentName, $documentMimeType,
02053                                    $documentOS, $documentAudience,
02054                                    false, false );
02055         }
02056 
02057         // Read changelog
02058         $changelogNode = $root->getElementsByTagName( 'changelog' )->item( 0 );
02059         if ( $changelogNode )
02060         {
02061             $changelogEntryNodes = $changelogNode->getElementsByTagName( 'entry' );
02062             foreach ( $changelogEntryNodes as $changelogEntryNode )
02063             {
02064                 $changelogTimestamp = $changelogEntryNode->getAttribute( 'timestamp' );
02065                 $changelogPerson = $changelogEntryNode->getAttribute( 'person' );
02066                 $changelogEmail = $changelogEntryNode->getAttribute( 'email' );
02067                 $changelogRelease = $changelogEntryNode->getAttribute( 'release' );
02068                 $changelogChangeList = $changelogEntryNode->getElementsByTagName( 'change' )->item( 0 )->textContent;
02069                 $this->appendChange( $changelogPerson, $changelogEmail, $changelogChangeList,
02070                                      $changelogRelease, $changelogTimestamp );
02071             }
02072         }
02073 
02074         // Read simple files
02075         $this->Parameters['simple-file-list'] = array();
02076         $simpleFilesNode = $root->getElementsByTagName( 'simple-files' )->item( 0 );
02077         if ( $simpleFilesNode && $simpleFilesNode->hasChildNodes() )
02078         {
02079             $simpleFileNodes = $simpleFilesNode->getElementsByTagName( 'simple-file' );
02080             foreach ( $simpleFileNodes as $simpleFileNode )
02081             {
02082                 $key = $simpleFileNode->getAttribute( 'key' );
02083                 $originalPath = $simpleFileNode->getAttribute( 'original-path' );
02084                 $packagePath = $simpleFileNode->getAttribute( 'package-path' );
02085                 $this->Parameters['simple-file-list'][$key] = array( 'original-path' => $originalPath,
02086                                                                      'package-path' => $packagePath );
02087             }
02088         }
02089 
02090         // Read files
02091         $filesList = $root->getElementsByTagName( 'files' );
02092         if ( $filesList )
02093         {
02094             foreach ( $filesList as $fileCollectionNode )
02095             {
02096                 $fileCollectionName = $fileCollectionNode->getAttribute( 'name' );
02097                 $fileLists = $fileCollectionNode->getElementsByTagName( 'file-list' );
02098                 foreach ( $fileLists as $fileListNode )
02099                 {
02100                     $fileType = $fileListNode->getAttribute( 'type' );
02101                     $fileDesign = $fileListNode->getAttribute( 'design' );
02102                     $fileRole = $fileListNode->getAttribute( 'role' );
02103                     $fileVariableName = $fileListNode->getAttribute( 'variable-name' );
02104                     $fileRoleValue = $fileListNode->getAttribute( 'role-value' );
02105                     $files = $fileListNode->getElementsByTagName( 'file' );
02106                     if ( count( $files ) > 0 )
02107                     {
02108                         foreach ( $files as $fileNode )
02109                         {
02110                             $fileFileType = $fileNode->getAttribute( 'type' );
02111                             $fileName = $fileNode->getAttribute( 'name' );
02112                             if ( $fileNode->getAttribute( 'variable-name' ) )
02113                                 $fileVariableName = $fileNode->getAttribute( 'variable-name' );
02114                             $fileSubDirectory = $fileNode->getAttribute( 'sub-directory' );
02115                             $filePath = $fileNode->getAttribute( 'path' );
02116                             $fileMD5 = $fileNode->getAttribute( 'md5sum' );
02117                             $this->appendFile( $fileName, $fileType, $fileRole,
02118                                                $fileDesign, $filePath, $fileCollectionName,
02119                                                $fileSubDirectory, $fileMD5, false, null,
02120                                                $fileFileType,
02121                                                $fileRoleValue, $fileVariableName );
02122                         }
02123                     }
02124                     else
02125                     {
02126                         $this->appendFile( false, $fileType, $fileRole,
02127                                            $fileDesign, false, $fileCollectionName,
02128                                            false, false, false, null );
02129                     }
02130                     unset( $files );
02131                 }
02132             }
02133         }
02134         // Read release info
02135         $xpath = new DOMXPath( $dom );
02136         $versionNode = $xpath->query( 'version' )->item( 0 );
02137         $versionNumber = false;
02138         $versionRelease = false;
02139         if ( $versionNode )
02140         {
02141             $versionNumber = $versionNode->getElementsByTagName( 'number' )->item( 0 )->textContent;
02142             $versionRelease = $versionNode->getElementsByTagName( 'release' )->item( 0 )->textContent;
02143         }
02144         $licence = $root->getElementsByTagName( 'licence' )->item( 0 )->textContent;
02145         $state = $root->getElementsByTagName( 'state' )->item( 0 )->textContent;
02146         $this->setRelease( $versionNumber, $versionRelease, false,
02147                            $licence, $state );
02148 
02149         $dependenciesNode = $root->getElementsByTagName( 'dependencies' )->item( 0 );
02150         if ( $dependenciesNode )
02151         {
02152             $providesNode = $dependenciesNode->getElementsByTagName( 'provides' )->item( 0 );
02153             $providesList = $providesNode->getElementsByTagName( 'provide' );
02154             $requiresNode = $dependenciesNode->getElementsByTagName( 'requires' )->item( 0 );
02155             $requiresList = $requiresNode->getElementsByTagName( 'require' );
02156             $obsoletesNode = $dependenciesNode->getElementsByTagName( 'obsoletes' )->item( 0 );
02157             $obsoletesList = $obsoletesNode->getElementsByTagName( 'obsolete' );
02158             $conflictsNode = $dependenciesNode->getElementsByTagName( 'conflicts' )->item( 0 );
02159             $conflictsList = $conflictsNode->getElementsByTagName( 'conflict' );
02160             $this->parseDependencyTree( $providesList, 'provides' );
02161             $this->parseDependencyTree( $requiresList, 'requires' );
02162             $this->parseDependencyTree( $obsoletesList, 'obsoletes' );
02163             $this->parseDependencyTree( $conflictsList, 'conflicts' );
02164         }
02165 
02166         $settingsNode = $root->getElementsByTagName( 'settings' )->item( 0 );
02167 
02168         if ( $settingsNode )
02169         {
02170             $settingsFileNodes = $settingsNode->getElementsByTagName( 'settings-file' );
02171             $this->Parameters['settings-files'] = array();
02172 
02173             foreach( $settingsFileNodes as $settingsFileNode )
02174             {
02175                 $this->Parameters['settings-files'][] = $settingsFileNode->getAttribute( 'filename' );
02176             }
02177         }
02178 
02179         $installNode = $root->getElementsByTagName( 'install' )->item( 0 );
02180         $installList = $installNode->getElementsByTagName( 'item' );
02181         $uninstallNode = $root->getElementsByTagName( 'uninstall' )->item( 0 );
02182         $uninstallList = $uninstallNode->getElementsByTagName( 'item' );
02183         $this->parseInstallTree( $installList, true );
02184         $this->parseInstallTree( $uninstallList, false );
02185 
02186         $installDataList = $root->getElementsByTagName( 'install-data' );
02187         if ( $installDataList )
02188         {
02189             $this->InstallData = array();
02190             foreach( $installDataList as $installDataNode )
02191             {
02192                 if ( is_object( $installDataNode ) &&
02193                      $installDataNode->getAttribute( 'name' ) == 'data' )
02194                 {
02195                     $installDataType = $installDataNode->getAttribute( 'type' );
02196                     $installDataElements = $installDataNode->getElementsByTagName( 'data' );
02197                     $installData = array();
02198                     foreach ( $installDataElements as $installDataElement )
02199                     {
02200                         if ( $installDataElement->attribute( 'name' ) == 'element' )
02201                         {
02202                             $name = $installDataElement->getAttribute( 'name' );
02203                             $value = $installDataElement->getAttribute( 'value' );
02204                             $installData[$name] = $value;
02205                         }
02206                         else if ( $installDataElement->attribute( 'name' ) == 'array' )
02207                         {
02208                             $arrayName = $installDataElement->getAttribute( 'name' );
02209                             $installDataElementArray = $installDataElement->childNodes;
02210                             $array = array();
02211                             foreach ( $installDataElementArray as $installDataElementArrayElement )
02212                             {
02213                                 $name = $installDataElementArrayElement->getAttribute( 'name' );
02214                                 $value = $installDataElementArrayElement->getAttribute( 'value' );
02215                                 $array[$name] = $value;
02216                             }
02217                             $installData[$arrayName] = $array;
02218                         }
02219                     }
02220                     if ( count( $installData ) > 0 )
02221                         $this->InstallData[$installDataType] = $installData;
02222                 }
02223             }
02224         }
02225 
02226         $retValue = true;
02227         return $retValue;
02228     }
02229 
02230     /*!
02231      \private
02232     */
02233     function parseDependencyTree( $dependenciesList, $dependencySection )
02234     {
02235         foreach ( $dependenciesList as $dependencyNode )
02236         {
02237             $dependencyType = $dependencyNode->getAttribute( 'type' );
02238             $dependencyAttributes = $dependencyNode->attributes;
02239             $dependencyParameters = array();
02240             for ( $i = 0; $i < $dependencyAttributes->length; $i++ )
02241             {
02242                 $dependencyAttribute = $dependencyAttributes->item( $i );
02243                 $dependencyParameters[$dependencyAttribute->name] = $dependencyAttribute->value;
02244             }
02245 
02246             $additionalDependencyParameters = array();
02247             $handler = $this->packageHandler( $dependencyType );
02248             if ( $handler )
02249             {
02250                 $handler->parseDependencyNode( $this, $dependencyNode, $additionalDependencyParameters, $dependencySection );
02251             }
02252 
02253             if ( count( $additionalDependencyParameters ) > 0 )
02254                 $dependencyParameters = array_merge( $dependencyParameters, $additionalDependencyParameters );
02255 
02256             $this->appendDependency( $dependencySection, $dependencyParameters );
02257         }
02258     }
02259 
02260     /*!
02261      \private
02262     */
02263     function parseInstallTree( $installList, $isInstall )
02264     {
02265         foreach( $installList as $installNode )
02266         {
02267             $installType = $installNode->getAttribute( 'type' );
02268             $installName = $installNode->getAttribute( 'name' );
02269             $installFilename = $installNode->getAttribute( 'filename' );
02270             $installSubdirectory = $installNode->getAttribute( 'sub-directory' );
02271             $installOS = $installNode->getAttribute( 'os' );
02272 
02273             $handler = $this->packageHandler( $installType );
02274             $installParameters = array();
02275             if ( $handler )
02276             {
02277                 $handler->parseInstallNode( $this, $installNode, $installParameters, $isInstall );
02278             }
02279             if ( count( $installParameters ) == 0 )
02280                 $installParameters = false;
02281 
02282             $this->appendInstall( $installType, $installName, $installOS, $isInstall,
02283                                   $installFilename, $installSubdirectory,
02284                                   $installParameters );
02285         }
02286     }
02287 
02288     /*!
02289      \return the dom document of the package.
02290     */
02291     function &domStructure()
02292     {
02293         $dom = new DOMDocument( '1.0', 'utf-8' );
02294         $dom->formatOutput = true;
02295         $root = $dom->createElement( 'package' );
02296         $root->setAttribute( 'version', eZPackage::VERSION );
02297         $root->setAttribute( 'development', ( eZPackage::DEVELOPMENT ? 'true' : 'false' ) );
02298         $dom->appendChild( $root );
02299 
02300         if ( eZPackage::DEVELOPMENT )
02301         {
02302             $warningText = "This format was made with a development version and will not work with any release versions.\n" .
02303                            "The format of this file is also subject to change until the release version.\n" .
02304                            "Upgrades to the development format will not be supported.";
02305 
02306             $warningNode = $dom->createElement( 'warning' );
02307             $warningNode->appendChild( $dom->createTextNode( $warningText ) );
02308             $root->appendChild( $warningNode );
02309         }
02310 
02311         $name = $this->attribute( 'name' );
02312         $summary = $this->attribute( 'summary' );
02313         $description = $this->attribute( 'description' );
02314         $priority = $this->attribute( 'priority' );
02315         $type = $this->attribute( 'type' );
02316         $extension = $this->attribute( 'extension' );
02317         $installType = $this->attribute( 'install_type' );
02318         $vendorName = $this->attribute( 'vendor' );
02319         $source = $this->attribute( 'source' );
02320 
02321         $ezpublishVersion = $this->attribute( 'ezpublish-version' );
02322         $ezpublishNamedVersion = $this->attribute( 'ezpublish-named-version' );
02323 
02324         $packagingTimestamp = $this->attribute( 'packaging-timestamp' );
02325         $packagingHost = $this->attribute( 'packaging-host' );
02326         $packagingPackager = $this->attribute( 'packaging-packager' );
02327 
02328         $maintainers = $this->attribute( 'maintainers' );
02329         $documents = $this->attribute( 'documents' );
02330         $groups = $this->attribute( 'groups' );
02331 
02332         $versionNumber = $this->attribute( 'version-number' );
02333         $releaseNumber = $this->attribute( 'release-number' );
02334         $releaseTimestamp = $this->attribute( 'release-timestamp' );
02335 
02336         $licence = $this->attribute( 'licence' );
02337         $state = $this->attribute( 'state' );
02338 
02339         $simpleFileList = $this->attribute( 'simple-file-list' );
02340         $fileList = $this->attribute( 'file-list' );
02341         $dependencies = $this->attribute( 'dependencies' );
02342         $install = $this->attribute( 'install' );
02343         $uninstall = $this->attribute( 'uninstall' );
02344         $changelog = $this->attribute( 'changelog' );
02345 
02346         $rootNameTextNode = $dom->createElement( 'name' );
02347         $rootNameTextNode->appendChild( $dom->createTextNode( $name ) );
02348         $root->appendChild( $rootNameTextNode );
02349 
02350         if ( $summary )
02351         {
02352             $rootSummaryTextNode = $dom->createElement( 'summary' );
02353             $rootSummaryTextNode->appendChild( $dom->createTextNode( $summary ) );
02354             $root->appendChild( $rootSummaryTextNode );
02355         }
02356 
02357         if ( $description )
02358         {
02359             $rootDescriptionTextNode = $dom->createElement( 'description' );
02360             $rootDescriptionTextNode->appendChild( $dom->createTextNode( $description ) );
02361             $root->appendChild( $rootDescriptionTextNode );
02362         }
02363 
02364         if ( $vendorName )
02365         {
02366             $rootVendorTextNode = $dom->createElement( 'vendor' );
02367             $rootVendorTextNode->appendChild( $dom->createTextNode( $vendorName ) );
02368             $root->appendChild( $rootVendorTextNode );
02369         }
02370 
02371         if ( $priority )
02372         {
02373             $rootPriorityTextNode = $dom->createElement( 'priority' );
02374             $rootPriorityTextNode->setAttribute( 'value', $priority );
02375             $root->appendChild( $rootPriorityTextNode );
02376         }
02377 
02378         if ( $type )
02379         {
02380             $rootTypeTextNode = $dom->createElement( 'type' );
02381             $rootTypeTextNode->setAttribute( 'value', $type );
02382             $root->appendChild( $rootTypeTextNode );
02383         }
02384 
02385         if ( $extension )
02386         {
02387             $rootExtensionTextNode = $dom->createElement( 'extension' );
02388             $rootExtensionTextNode->setAttribute( 'name', $extension );
02389             $root->appendChild( $rootExtensionTextNode );
02390         }
02391 
02392         if ( $source )
02393         {
02394             $rootSourceTextNode = $dom->createElement( 'source' );
02395             $rootSourceTextNode->appendChild( $dom->createTextNode( $source ) );
02396             $root->appendChild( $rootSourceTextNode );
02397         }
02398 
02399         $root->setAttribute( 'install_type', $installType );
02400 
02401         $ezpublishNode = $dom->createElement( 'ezpublish' );
02402 
02403         $ezpublishVersionTextNode = $dom->createElement( 'version' );
02404         $ezpublishVersionTextNode->appendChild( $dom->createTextNode( $ezpublishVersion ) );
02405         $ezpublishNode->appendChild( $ezpublishVersionTextNode );
02406 
02407         $ezpublishNamedVersionTextNode = $dom->createElement( 'named-version' );
02408         $ezpublishNamedVersionTextNode->appendChild( $dom->createTextNode( $ezpublishNamedVersion ) );
02409         $ezpublishNode->appendChild( $ezpublishNamedVersionTextNode );
02410 
02411         $root->appendChild( $ezpublishNode );
02412 
02413         if ( count( $maintainers ) > 0 )
02414         {
02415             $maintainersNode = $dom->createElement( 'maintainers' );
02416             foreach ( $maintainers as $maintainer )
02417             {
02418                 unset( $maintainerNode );
02419                 $maintainerNode = $dom->createElement( 'maintainer' );
02420 
02421                 unset( $maintainerName );
02422                 $maintainerName = $dom->createElement( 'name' );
02423                 $maintainerName->appendChild( $dom->createTextNode( $maintainer['name'] ) );
02424                 $maintainerNode->appendChild( $maintainerName );
02425 
02426                 unset( $maintainerEmail );
02427                 $maintainerEmail = $dom->createElement( 'email' );
02428                 $maintainerEmail->appendChild( $dom->createTextNode( $maintainer['email'] ) );
02429                 $maintainerNode->appendChild( $maintainerEmail );
02430                 if ( $maintainer['role'] )
02431                 {
02432                     unset( $maintainerRole );
02433                     $maintainerRole = $dom->createElement( 'role' );
02434                     $maintainerRole->appendChild( $dom->createTextNode( $maintainer['role'] ) );
02435                     $maintainerNode->appendChild( $maintainerRole );
02436                 }
02437 
02438                 $maintainersNode->appendChild( $maintainerNode );
02439             }
02440             $root->appendChild( $maintainersNode );
02441         }
02442 
02443         $packagingNode = $dom->createElement( 'packaging' );
02444 
02445         $packagingTimestampNode = $dom->createElement( 'timestamp' );
02446         $packagingTimestampNode->appendChild( $dom->createTextNode( $packagingTimestamp ) );
02447         $packagingNode->appendChild( $packagingTimestampNode );
02448 
02449         $packagingHostNode = $dom->createElement( 'host' );
02450         $packagingHostNode->appendChild( $dom->createTextNode( $packagingHost ) );
02451         $packagingNode->appendChild( $packagingHostNode );
02452         if ( $packagingPackager )
02453         {
02454             $packagingPackagerNode = $dom->createElement( 'packager' );
02455             $packagingPackagerNode->appendChild( $dom->createTextNode( $packagingPackager ) );
02456             $packagingNode->appendChild( $packagingPackagerNode );
02457         }
02458 
02459         $root->appendChild( $packagingNode );
02460 
02461         if ( count( $documents ) > 0 )
02462         {
02463             $documentsNode = $dom->createElement( 'documents' );
02464             foreach ( $documents as $document )
02465             {
02466                 unset( $documentNode );
02467                 $documentNode = $dom->createElement( 'document' );
02468                 $documentNode->setAttribute( 'mime-type', $document['mime-type'] );
02469                 $documentNode->setAttribute( 'name', $document['name'] );
02470                 if ( $document['os'] )
02471                     $documentNode->setAttribute( 'os', $document['os'] );
02472 
02473                 if ( $document['audience'] )
02474                     $documentNode->setAttribute( 'audience', $document['audience'] );
02475 
02476                 $documentsNode->appendChild( $documentNode );
02477             }
02478             $root->appendChild( $documentsNode );
02479         }
02480 
02481         if ( count( $groups ) > 0 )
02482         {
02483             $groupsNode = $dom->createElement( 'groups' );
02484             foreach ( $groups as $group )
02485             {
02486                 unset( $groupNode );
02487                 $groupNode = $dom->createElement( 'group' );
02488                 $groupNode->setAttribute( 'name', $group['name'] );
02489                 $groupsNode->appendChild( $groupNode );
02490             }
02491             $root->appendChild( $groupsNode );
02492         }
02493 
02494         if ( count( $changelog ) > 0 )
02495         {
02496             $changelogNode = $dom->createElement( 'changelog' );
02497             foreach ( $changelog as $changeEntry )
02498             {
02499                 unset( $changeEntryNode );
02500                 $changeEntryNode = $dom->createElement( 'entry' );
02501                 $changeEntryNode->setAttribute( 'timestamp', $changeEntry['timestamp'] );
02502                 $changeEntryNode->setAttribute( 'person', $changeEntry['person'] );
02503                 $changeEntryNode->setAttribute( 'email', $changeEntry['email'] );
02504                 $changeEntryNode->setAttribute( 'release', $changeEntry['release'] );
02505 
02506                 foreach ( $changeEntry['changes'] as $change )
02507                 {
02508                     unset( $changeEntryChange );
02509                     $changeEntryChange = $dom->createElement( 'change' );
02510                     $changeEntryChange->appendChild( $dom->createTextNode( $change ) );
02511                     $changeEntryNode->appendChild( $changeEntryChange );
02512                 }
02513                 $changelogNode->appendChild( $changeEntryNode );
02514             }
02515             $root->appendChild( $changelogNode );
02516         }
02517 
02518         // Avoid a PHP warning if 'simple-file-list' is not an array
02519         if ( is_array( $this->Parameters['simple-file-list'] ) )
02520         {
02521             $rootSimpleFiles = $dom->createElement( 'simple-files' );
02522             foreach( $this->Parameters['simple-file-list'] as $key => $value )
02523             {
02524                 $simpleFileNode = $dom->createElement( 'simple-file' );
02525                 $simpleFileNode->setAttribute( 'key', $key );
02526                 $simpleFileNode->setAttribute( 'original-path', $value['original-path'] );
02527                 $simpleFileNode->setAttribute( 'package-path', $value['package-path'] );
02528                 $rootSimpleFiles->appendChild( $simpleFileNode );
02529                 unset( $simpleFileNode );
02530             }
02531             $root->appendChild( $rootSimpleFiles );
02532         }
02533         else
02534         {
02535             $rootSimpleFiles = $dom->createElement( 'simple-files' );
02536             $root->appendChild( $rootSimpleFiles );
02537         }
02538 
02539         // Handle files
02540         $filesNode = $dom->createElement( 'files' );
02541 
02542         $hasFileItems = false;
02543         foreach ( $fileList as $fileCollectionName => $fileCollection )
02544         {
02545             if ( count( $fileCollection ) > 0 )
02546             {
02547                 $hasFileItems = true;
02548 
02549                 unset( $fileCollectionNode );
02550                 $fileCollectionNode = $dom->createElement( 'collection' );
02551                 $fileCollectionNode->setAttribute( 'name', $fileCollectionName );
02552 
02553                 unset( $fileLists );
02554                 unset( $fileDesignLists );
02555                 unset( $fileThumbnailLists );
02556                 $fileList = array();
02557                 $fileDesignList = array();
02558                 $fileINIList = array();
02559                 $fileThumbnailList = array();
02560                 $fileListNode = null;
02561                 foreach ( $fileCollection as $fileItem )
02562                 {
02563                     if ( $fileItem['type'] == 'design' )
02564                         $fileListNode =& $fileDesignLists[$fileItem['design']][$fileItem['role']][$fileItem['role-value']][$fileItem['variable-name']];
02565                     else if ( $fileItem['type'] == 'ini' )
02566                         $fileListNode =& $fileINILists[$fileItem['role']][$fileItem['role-value']][$fileItem['variable-name']];
02567                     else if ( $fileItem['type'] == 'thumbnail' )
02568                         $fileListNode =& $fileThumbnailLists[$fileItem['role']];
02569                     else
02570                         $fileListNode =& $fileLists[$fileItem['type']][$fileItem['role']][$fileItem['role-value']][$fileItem['variable-name']];
02571 
02572                     if ( !$fileListNode ||
02573                          $fileListNode->getAttribute( 'type' ) != $fileItem['type'] ||
02574                          $fileListNode->getAttribute( 'role' ) != $fileItem['role'] ||
02575                          $fileListNode->getAttribute( 'role-value' ) != $fileItem['role-value'] ||
02576                          $fileListNode->getAttribute( 'variable-name' ) != $fileItem['variable-name'] )
02577                     {
02578                         unset( $fileListNode );
02579                         $fileListNode = $dom->createElement( 'file-list' );
02580                         $fileListNode->setAttribute( 'type', $fileItem['type'] );
02581 
02582                         if ( $fileItem['type'] == 'design' )
02583                             $fileListNode->setAttribute( 'design', $fileItem['design'] );
02584                         if ( $fileItem['role'] )
02585                             $fileListNode->setAttribute( 'role', $fileItem['role'] );
02586                         if ( $fileItem['role-value'] )
02587                             $fileListNode->setAttribute( 'role-value', $fileItem['role-value'] );
02588                         if ( $fileItem['variable-name'] )
02589                             $fileListNode->setAttribute( 'variable-name', $fileItem['variable-name'] );
02590 
02591                         $fileCollectionNode->appendChild( $fileListNode );
02592                     }
02593 
02594                     if ( $fileItem['name'] )
02595                     {
02596                         unset( $fileListFile );
02597                         $fileListFile = $dom->createElement( 'file' );
02598                         $fileListFile->setAttribute( 'path', $fileItem['path'] );
02599                         $fileListFile->setAttribute( 'name', $fileItem['name'] );
02600 
02601                         if ( $fileItem['md5'] )
02602                             $fileListFile->setAttribute( 'md5sum', $fileItem['md5'] );
02603 
02604                         if ( $fileItem['subdirectory'] )
02605                             $fileListFile->setAttribute( 'sub-directory', $fileItem['subdirectory'] );
02606 
02607                         $fileListNode->appendChild( $fileListFile );
02608                     }
02609                 }
02610                 $filesNode->appendChild( $fileCollectionNode );
02611             }
02612         }
02613         if ( $hasFileItems )
02614             $root->appendChild( $filesNode );
02615 
02616         $versionNode = $dom->createElement( 'version' );
02617         $versionNumberTextNode = $dom->createElement( 'number' );
02618         $versionNumberTextNode->appendChild( $dom->createTextNode( $versionNumber ) );
02619         $versionNode->appendChild( $versionNumberTextNode );
02620         $versionReleaseNumberTextNode = $dom->createElement( 'release' );
02621         $versionReleaseNumberTextNode->appendChild( $dom->createTextNode( $releaseNumber ) );
02622         $versionNode->appendChild( $versionReleaseNumberTextNode );
02623         $root->appendChild( $versionNode );
02624 
02625         if ( $releaseTimestamp )
02626         {
02627             $rootTimestampTextNode = $dom->createElement( 'timestamp' );
02628             $rootTimestampTextNode->appendChild( $dom->createTextNode( $releaseTimestamp ) );
02629             $root->appendChild( $rootTimestampTextNode );
02630         }
02631 
02632         if ( $licence )
02633         {
02634             $rootLicenceTextNode = $dom->createElement( 'licence' );
02635             $rootLicenceTextNode->appendChild( $dom->createTextNode( $licence ) );
02636             $root->appendChild( $rootLicenceTextNode );
02637         }
02638 
02639         if ( $state )
02640         {
02641             $rootStateTextNode = $dom->createElement( 'state' );
02642             $rootStateTextNode->appendChild( $dom->createTextNode( $state ) );
02643             $root->appendChild( $rootStateTextNode );
02644         }
02645 
02646         $dependencyNode = $dom->createElement( 'dependencies' );
02647 
02648         $providesNode = $dom->createElement( 'provides' );
02649         $dependencyNode->appendChild( $providesNode );
02650         $requiresNode = $dom->createElement( 'requires' );
02651         $dependencyNode->appendChild( $requiresNode );
02652         $obsoletesNode = $dom->createElement( 'obsoletes' );
02653         $dependencyNode->appendChild( $obsoletesNode );
02654         $conflictsNode = $dom->createElement( 'conflicts' );
02655         $dependencyNode->appendChild( $conflictsNode );
02656 
02657         $this->createDependencyTree( $providesNode, 'provide', $dependencies['provides'] );
02658         $this->createDependencyTree( $requiresNode, 'require', $dependencies['requires'] );
02659         $this->createDependencyTree( $obsoletesNode, 'obsolete', $dependencies['obsoletes'] );
02660         $this->createDependencyTree( $conflictsNode, 'conflict', $dependencies['conflicts'] );
02661 
02662         $root->appendChild( $dependencyNode );
02663 
02664         $installNode = $dom->createElement( 'install' );
02665 
02666         $uninstallNode = $dom->createElement( 'uninstall' );
02667 
02668         $this->createInstallTree( $installNode, $dom, $install, 'install' );
02669         $this->createInstallTree( $uninstallNode, $dom, $uninstall, 'uninstall' );
02670 
02671         $root->appendChild( $installNode );
02672         $root->appendChild( $uninstallNode );
02673 
02674         if ( count( $this->InstallData ) > 0 )
02675         {
02676             $installDataNode = $dom->createElement( 'install-data' );
02677             foreach ( $this->InstallData as $installDataType => $installData )
02678             {
02679                 if ( count( $installData ) > 0 )
02680                 {
02681                     unset( $dataNode );
02682                     $dataNode = $dom->createElement( 'data' );
02683                     $dataNode->setAttribute( 'type', $installDataType );
02684                     $installDataNode->appendChild( $dataNode );
02685                     foreach ( $installData as $installDataName => $installDataValue )
02686                     {
02687                         if ( is_array( $installDataValue ) )
02688                         {
02689                             unset( $dataArrayNode );
02690                             $dataArrayNode = $dom->createElement( 'array' );
02691                             $dataArrayNode->setAttribute( 'name', $installDataName );
02692                             $dataNode->appendChild( $dataArrayNode );
02693                             foreach ( $installDataValue as $installDataValueName => $installDataValueValue )
02694                             {
02695                                 unset( $dataArrayElement );
02696                                 $dataArrayElement = $dom->createElement( 'element' );
02697                                 $dataArrayElement->setAttribute( 'name', $installDataValueName );
02698                                 $dataArrayElement->setAttribute( 'value', $installDataValueValue );
02699                                 $dataArrayNode->appendChild( $dataArrayElement );
02700                             }
02701                         }
02702                         else
02703                         {
02704                             unset( $dataArrayElement );
02705                             $dataArrayElement = $dom->createElement( 'element' );
02706                             $dataArrayElement->setAttribute( 'name', $installDataName );
02707                             $dataArrayElement->setAttribute( 'value', $installDataValue );
02708                             $dataNode->appendChild( $dataArrayElement );
02709                         }
02710                     }
02711                 }
02712             }
02713             $root->appendChild( $installDataNode );
02714         }
02715 
02716         return $dom;
02717     }
02718 
02719     /*!
02720      \private
02721      Creates xml elements as children of the main node \a $installNode.
02722      The install elements are taken from \a $list.
02723      \param $installType Is either \c 'install' or \c 'uninstall'
02724     */
02725     function createInstallTree( $installNode, $dom, $list, $installType )
02726     {
02727         foreach ( $list as $installItem )
02728         {
02729             $type = $installItem['type'];
02730             unset( $installItemNode );
02731             $installItemNode = $dom->createElement( 'item' );
02732             $installItemNode->setAttribute( 'type', $type );
02733             $installNode->appendChild( $installItemNode );
02734 
02735             if ( $installItem['os'] )
02736                 $installItemNode->setAttribute( 'os', $installItem['os'] );
02737 
02738             if ( $installItem['name'] )
02739                 $installItemNode->setAttribute( 'name', $installItem['name'] );
02740 
02741             if ( $installItem['filename'] )
02742             {
02743                 $installItemNode->setAttribute( 'filename', $installItem['filename'] );
02744 
02745                 if ( $installItem['sub-directory'] )
02746                     $installItemNode->setAttribute( 'sub-directory', $installItem['sub-directory'] );
02747             }
02748             else if ( isset( $installItem['content'] ) && $installItem['content'] instanceof DOMElement )
02749             {
02750                 $importedContentNode = $installItemNode->ownerDocument->importNode( $installItem['content'], true );
02751                 $installItemNode->appendChild( $importedContentNode );
02752             }
02753 
02754             $handler = $this->packageHandler( $type );
02755             if ( $handler )
02756             {
02757                 $handler->createInstallNode( $this, $installItemNode, $installItem, $installType );
02758             }
02759         }
02760     }
02761 
02762     /*!
02763      Creates dependency xml elements as child of $dependenciesNode.
02764      The dependency elements are take from \a $list.
02765      \param $dependencyType Is either \c 'provide', \c 'require', \c 'obsolete' or \c 'conflict'
02766     */
02767     function createDependencyTree( &$dependenciesNode, $dependencyType, $list )
02768     {
02769         $dom = $dependenciesNode->ownerDocument;
02770 
02771         foreach ( $list as $dependencyItem )
02772         {
02773             unset( $dependencyNode );
02774             $dependencyNode = $dom->createElement( $dependencyType );
02775             $dependencyNode->setAttribute( 'type', $dependencyItem['type'] );
02776             $dependencyNode->setAttribute( 'name', $dependencyItem['name'] );
02777             if ( $dependencyItem['value'] )
02778                 $dependencyNode->setAttribute( 'value', $dependencyItem['value'] );
02779             $dependenciesNode->appendChild( $dependencyNode );
02780             $handler = $this->packageHandler( $dependencyItem['name'] );
02781             if ( $handler )
02782             {
02783                 $handler->createDependencyNode( $this, $dependencyNode, $dependencyItem, $dependencyType );
02784             }
02785         }
02786     }
02787 
02788     /*!
02789      \return the package handler object for the handler named \a $handlerName.
02790     */
02791     static function packageHandler( $handlerName )
02792     {
02793         if ( !isset( $GLOBALS['eZPackageHandlers'] ) )
02794         {
02795             $handlers = array();
02796         }
02797         else
02798         {
02799             $handlers = $GLOBALS['eZPackageHandlers'];
02800         }
02801         $handler = false;
02802 
02803         if( isset( $handlers[$handlerName] ) )
02804         {
02805             $handler = $handlers[$handlerName];
02806             $handler->reset();
02807         }
02808         else
02809         {
02810             $optionArray = array( 'iniFile'      => 'package.ini',
02811                                   'iniSection'   => 'PackageSettings',
02812                                   'iniVariable'  => 'HandlerAlias',
02813                                   'handlerIndex' => $handlerName );
02814 
02815             $options = new ezpExtensionOptions( $optionArray );
02816 
02817             $handler = eZExtension::getHandlerClass( $options );
02818             $handlers[$handlerName] = $handler;
02819         }
02820 
02821         $GLOBALS['eZPackageHandlers'] = $handlers;
02822         return $handler;
02823     }
02824 
02825     /*!
02826      Append File to package assosiated with key. The file will be available during installation using the same key.
02827 
02828      \param key
02829      \param file path
02830     */
02831     function appendSimpleFile( $key, $filepath )
02832     {
02833         if ( !isset( $this->Parameters['simple-file-list'] ) )
02834         {
02835             $this->Parameters['simple-file-list'] = array();
02836         }
02837 
02838         $suffix = eZFile::suffix( $filepath );
02839         //$sourcePath = $fileInfo['original-path'];
02840         $packagePath = eZPackage::simpleFilesDirectory() . '/' . substr( md5( mt_rand() ), 0, 8 ) . '.' . $suffix;
02841         $destinationPath = $this->path() . '/' . $packagePath;
02842         eZDir::mkdir( eZDir::dirpath( $destinationPath ), false, true );
02843 
02844        //SP DBfile
02845         $fileHandler = eZClusterFileHandler::instance();
02846         $fileHandler->fileFetch( $filepath );
02847 
02848         eZFileHandler::copy( $filepath, $destinationPath );
02849 
02850         $this->Parameters['simple-file-list'][$key] = array( 'original-path' => $filepath,
02851                                                              'package-path' => $packagePath );
02852     }
02853 
02854     /*!
02855      Get complete path to file by file key
02856 
02857      \param file key
02858 
02859      \return complete file path
02860     */
02861     function simpleFilePath( $fileKey )
02862     {
02863         if ( !isset( $this->Parameters['simple-file-list'] ) )
02864         {
02865             return false;
02866         }
02867         if ( !isset( $this->Parameters['simple-file-list'][$fileKey] ) )
02868         {
02869             return false;
02870         }
02871 
02872         return $this->path() . '/' . $this->Parameters['simple-file-list'][$fileKey]['package-path'];
02873     }
02874 
02875     /**
02876      * Returns package version.
02877      *
02878      * Combines package version number and release number.
02879      *
02880      * \static
02881      * \return Package version (string).
02882      */
02883     function getVersion()
02884     {
02885         return $this->Parameters['version-number'] . '-' . $this->Parameters['release-number'];
02886     }
02887 
02888     /*!
02889      Sets installed/uninstalled state of the package
02890      \param installed
02891     */
02892     function setInstalled( $installed = true )
02893     {
02894         if ( $this->Parameters['install_type'] != 'install' )
02895             return;
02896 
02897         $name = $this->Parameters['name'];
02898         $version = $this->getVersion();
02899         $db = eZDB::instance();
02900         if ( $installed )
02901         {
02902             if ( !$this->getInstallState() )
02903             {
02904                 $timestamp = time();
02905                 $db->query( "INSERT INTO ezpackage ( name, version, install_date ) VALUES ( '$name', '$version', '$timestamp' )" );
02906                 $this->isInstalled = true;
02907             }
02908         }
02909         else
02910         {
02911             $db->query( "DELETE FROM ezpackage WHERE name='$name' AND version='$version'" );
02912             $this->isInstalled = false;
02913         }
02914     }
02915 
02916     function isInstalled()
02917     {
02918         return $this->isInstalled;
02919     }
02920 
02921     function getInstallState()
02922     {
02923         // TODO installation date
02924 
02925         if ( $this->Parameters['install_type'] != 'install' )
02926             return;
02927 
02928         $name = $this->Parameters['name'];
02929         $version = $this->getVersion();
02930 
02931         $db = eZDB::instance();
02932         $result = $db->arrayQuery( "SELECT count(*) AS count FROM ezpackage WHERE name='$name' AND version='$version'" );
02933 
02934         if ( !count( $result ) )
02935             return false;
02936         $installed = $result[0]['count'] == '0' ? false : true;
02937         $this->isInstalled = $installed;
02938         return $installed;
02939     }
02940 
02941     /*!
02942      \static
02943      Fetch info about languages for packages specified in $packageNameList.
02944      Return ex:  array( 'eng-GB', 'rus-RU', ... );
02945                  if $withLanguageNames == true
02946                     array( 'eng-GB' => "English",
02947                            'rus-RU' => "Russian",
02948                            ... );
02949     */
02950     static function languageInfoFromPackageList( $packageNameList, $withLanguageNames = false )
02951     {
02952         $languageInfo = array();
02953         foreach( $packageNameList as $packageName )
02954         {
02955             $package = eZPackage::fetch( $packageName, false, false, false );
02956             if( is_object( $package ) )
02957             {
02958                 $packageLanguageInfo = $package->languageInfo( $withLanguageNames );
02959                 // merge arrays
02960                 if( $withLanguageNames )
02961                 {
02962                     // we have array like 'locale' => 'name'. can use array_merge
02963                     $languageInfo = array_merge( $languageInfo, $packageLanguageInfo );
02964                 }
02965                 else
02966                 {
02967                     foreach( $packageLanguageInfo as $languageLocale )
02968                     {
02969                         if( !in_array( $languageLocale, $languageInfo ) )
02970                         {
02971                             $languageInfo[] = $languageLocale;
02972                         }
02973                     }
02974                 }
02975             }
02976             else
02977             {
02978                 eZDebug::writeWarning( "Unable to fetch package '$packageName'", __METHOD__ );
02979             }
02980         }
02981 
02982         return $languageInfo;
02983     }
02984 
02985     /*!
02986      Fetch info about languages for package.
02987     */
02988     function languageInfo( $withLanguageNames = false )
02989     {
02990         $langaugeInfo = array();
02991 
02992         $classHandler  = eZPackage::packageHandler( 'ezcontentclass' );
02993         $objectHandler = eZPackage::packageHandler( 'ezcontentobject' );
02994 
02995         $explainClassInfo = array( 'language_info' );
02996 
02997         $packageItems = $this->installItemsList();
02998         foreach( $packageItems as $item )
02999         {
03000             $itemLanguageInfo = array();
03001 
03002             if( $item['type'] == 'ezcontentclass' )
03003             {
03004                 $classInfo = $classHandler->explainInstallItem( $this, $item, $explainClassInfo );
03005                 $itemLanguageInfo = isset( $classInfo['language_info'] ) ? $classInfo['language_info'] : array();
03006             }
03007             else if( $item['type'] == 'ezcontentobject' )
03008             {
03009                 $objectsInfo = $objectHandler->explainInstallItem( $this, $item );
03010 
03011                 // merge objects info
03012                 foreach( $objectsInfo as $objectInfo )
03013                 {
03014                     $objectLanguages = isset( $objectInfo['language_info'] ) ? $objectInfo['language_info'] : array();
03015                     foreach( $objectLanguages as $objectLanguage )
03016                     {
03017                         if( !in_array( $objectLanguage, $itemLanguageInfo ) )
03018                         {
03019                             $itemLanguageInfo[] = $objectLanguage;
03020                         }
03021                     }
03022                 }
03023             }
03024 
03025             // merge class and objects infos
03026             foreach( $itemLanguageInfo as $languageLocale )
03027             {
03028                 if( !in_array( $languageLocale, $langaugeInfo ) )
03029                 {
03030                     $langaugeInfo[] = $languageLocale;
03031                 }
03032             }
03033         }
03034 
03035         if( $withLanguageNames )
03036         {
03037             $langaugeInfoWithNames = array();
03038             foreach( $langaugeInfo as $languageLocale )
03039             {
03040                 $language = eZContentLanguage::fetchByLocale( $languageLocale );
03041                 $languageName = $language->attribute( 'name' );
03042                 $langaugeInfoWithNames[$languageLocale] = $languageName;
03043             }
03044 
03045             $langaugeInfo = $langaugeInfoWithNames;
03046         }
03047 
03048         return $langaugeInfo;
03049     }
03050 
03051     function defaultLanguageMap()
03052     {
03053         $languageMap = array();
03054         $packageLanguages = $this->languageInfo();
03055         foreach( $packageLanguages as $language )
03056         {
03057             $languageMap[$language] = $language;
03058         }
03059 
03060         return $languageMap;
03061     }
03062 
03063     /**
03064      * Checks if a package name is valid
03065      *
03066      * @param string $packageName the package name
03067      * @param string $transformedPackageName the package name, transformed to be valid
03068      * @return boolean true if the package name is valid, false if not
03069      */
03070 
03071     static function isValidName( $packageName, &$transformedPackageName = null )
03072     {
03073         $trans = eZCharTransform::instance();
03074         $transformedPackageName = $trans->transformByGroup( $packageName, 'identifier' );
03075 
03076         return $transformedPackageName === $packageName;
03077     }
03078 
03079 
03080     public $isInstalled = false;
03081     /// \privatesection
03082     /// All interal data
03083     public $Parameters;
03084     /// Controls which data has been modified
03085 }
03086 
03087 ?>