예제 #1
0
 /**
  * Install or upgrade the code for an extension -- and perform any
  * necessary database changes (eg replacing extension metadata).
  *
  * This only works if the extension is stored in the default container.
  *
  * @param string $tmpCodeDir
  *   Path to a local directory containing a copy of the new (inert) code.
  * @throws CRM_Extension_Exception
  */
 public function replace($tmpCodeDir)
 {
     if (!$this->defaultContainer) {
         throw new CRM_Extension_Exception("Default extension container is not configured");
     }
     $newInfo = CRM_Extension_Info::loadFromFile($tmpCodeDir . DIRECTORY_SEPARATOR . CRM_Extension_Info::FILENAME);
     $oldStatus = $this->getStatus($newInfo->key);
     // find $tgtPath, $oldInfo, $typeManager
     switch ($oldStatus) {
         case self::STATUS_UNINSTALLED:
         case self::STATUS_INSTALLED:
         case self::STATUS_DISABLED:
             // There is an old copy of the extension. Try to install in the same place -- but it must go somewhere in the default-container
             list($oldInfo, $typeManager) = $this->_getInfoTypeHandler($newInfo->key);
             // throws Exception
             $tgtPath = $this->fullContainer->getPath($newInfo->key);
             if (!CRM_Utils_File::isChildPath($this->defaultContainer->getBaseDir(), $tgtPath)) {
                 // force installation in the default-container
                 $oldPath = $tgtPath;
                 $tgtPath = $this->defaultContainer->getBaseDir() . DIRECTORY_SEPARATOR . $newInfo->key;
                 CRM_Core_Session::setStatus(ts('A copy of the extension (%1) is in a system folder (%2). The system copy will be preserved, but the new copy will be used.', array(1 => $newInfo->key, 2 => $oldPath)));
             }
             break;
         case self::STATUS_INSTALLED_MISSING:
         case self::STATUS_DISABLED_MISSING:
             // the extension does not exist in any container; we're free to put it anywhere
             $tgtPath = $this->defaultContainer->getBaseDir() . DIRECTORY_SEPARATOR . $newInfo->key;
             list($oldInfo, $typeManager) = $this->_getMissingInfoTypeHandler($newInfo->key);
             // throws Exception
             break;
         case self::STATUS_UNKNOWN:
             // the extension does not exist in any container; we're free to put it anywhere
             $tgtPath = $this->defaultContainer->getBaseDir() . DIRECTORY_SEPARATOR . $newInfo->key;
             $oldInfo = $typeManager = NULL;
             break;
         default:
             throw new CRM_Extension_Exception("Cannot install or enable extension: {$newInfo->key}");
     }
     // move the code!
     switch ($oldStatus) {
         case self::STATUS_UNINSTALLED:
         case self::STATUS_UNKNOWN:
             // There are no DB records to worry about, so we'll just put the files in place
             if (!CRM_Utils_File::replaceDir($tmpCodeDir, $tgtPath)) {
                 throw new CRM_Extension_Exception("Failed to move {$tmpCodeDir} to {$tgtPath}");
             }
             break;
         case self::STATUS_INSTALLED:
         case self::STATUS_INSTALLED_MISSING:
         case self::STATUS_DISABLED:
         case self::STATUS_DISABLED_MISSING:
             // There are DB records; coordinate the file placement with the DB updates
             $typeManager->onPreReplace($oldInfo, $newInfo);
             if (!CRM_Utils_File::replaceDir($tmpCodeDir, $tgtPath)) {
                 throw new CRM_Extension_Exception("Failed to move {$tmpCodeDir} to {$tgtPath}");
             }
             $this->_updateExtensionEntry($newInfo);
             $typeManager->onPostReplace($oldInfo, $newInfo);
             break;
         default:
             throw new CRM_Extension_Exception("Cannot install or enable extension: {$newInfo->key}");
     }
     $this->refresh();
     CRM_Core_Invoke::rebuildMenuAndCaches(TRUE);
 }