/**
  * Builds nodes for optional packages, whereas each package exists within
  * one node with the same parent node, seperated by sequence no (which does
  * not really matter at this point).
  */
 protected function buildOptionalNodes()
 {
     $packages = array();
     $optionalPackages = $this->installation->getArchive()->getOptionals();
     foreach ($optionalPackages as $package) {
         // check if already installed
         if (Package::isAlreadyInstalled($package['name'])) {
             continue;
         }
         // extract package
         $index = $this->installation->getArchive()->getTar()->getIndexByFilename($package['file']);
         if ($index === false) {
             throw new SystemException("Unable to find required package '" . $package['file'] . "' within archive.");
         }
         $fileName = FileUtil::getTemporaryFilename('package_', preg_replace('!^.*(?=\\.(?:tar\\.gz|tgz|tar)$)!i', '', basename($package['file'])));
         $this->installation->getArchive()->getTar()->extract($index, $fileName);
         // get archive data
         $archive = new PackageArchive($fileName);
         $archive->openArchive();
         // check if all requirements are met
         $isInstallable = true;
         foreach ($archive->getOpenRequirements() as $packageName => $package) {
             if (!isset($package['file'])) {
                 // requirement is neither installed nor shipped, check if it is about to be installed
                 if (!isset(self::$pendingPackages[$packageName])) {
                     $isInstallable = false;
                     break;
                 }
             }
         }
         // check for exclusions
         $excludedPackages = $archive->getConflictedExcludedPackages();
         if (!empty($excludedPackages)) {
             $isInstallable = false;
         }
         $excludingPackages = $archive->getConflictedExcludingPackages();
         if (!empty($excludingPackages)) {
             $isInstallable = false;
         }
         $packages[] = array('archive' => $fileName, 'isInstallable' => $isInstallable, 'package' => $archive->getPackageInfo('name'), 'packageName' => $archive->getLocalizedPackageInfo('packageName'), 'packageDescription' => $archive->getLocalizedPackageInfo('packageDescription'), 'selected' => 0);
         self::$pendingPackages[$archive->getPackageInfo('name')] = $archive->getPackageInfo('version');
     }
     if (!empty($packages)) {
         $this->parentNode = $this->node;
         $this->node = $this->getToken();
         $this->sequenceNo = 0;
         $sql = "INSERT INTO\twcf" . WCF_N . "_package_installation_node\n\t\t\t\t\t\t(queueID, processNo, sequenceNo, node, parentNode, nodeType, nodeData)\n\t\t\t\tVALUES\t\t(?, ?, ?, ?, ?, ?, ?)";
         $statement = WCF::getDB()->prepareStatement($sql);
         $statement->execute(array($this->installation->queue->queueID, $this->installation->queue->processNo, $this->sequenceNo, $this->node, $this->parentNode, 'optionalPackages', serialize($packages)));
     }
 }