oxutilsobject.php

Go to the documentation of this file.
00001 <?php
00002 
00009 class oxUtilsObject
00010 {
00011 
00015     const CACHE_FILE_PREFIX = "config";
00016 
00022     protected $_aClassNameCache = array();
00023 
00029     protected static $_aLoadedArticles = array();
00030 
00036     protected static $_aInstanceCache = array();
00037 
00043     protected static $_aModuleVars = array();
00044 
00050     protected static $_aClassInstances = array();
00051 
00057     private static $_instance = null;
00058 
00064     public static function getInstance()
00065     {
00066         // disable caching for test modules
00067         if (defined('OXID_PHP_UNIT')) {
00068             self::$_instance = null;
00069         }
00070 
00071         if (!self::$_instance instanceof oxUtilsObject) {
00072 
00073             // allow modules
00074             $oUtilsObject = new oxUtilsObject();
00075             self::$_instance = $oUtilsObject->oxNew('oxUtilsObject');
00076         }
00077 
00078         return self::$_instance;
00079     }
00080 
00088     public static function setClassInstance($sClassName, $oInstance)
00089     {
00090         $sClassName = strtolower($sClassName);
00091         self::$_aClassInstances[$sClassName] = $oInstance;
00092     }
00093 
00097     public static function resetClassInstances()
00098     {
00099         self::$_aClassInstances = array();
00100     }
00101 
00107     public static function resetModuleVars()
00108     {
00109         self::$_aModuleVars = array();
00110 
00111         $sMask = oxRegistry::get("oxConfigFile")->getVar("sCompileDir") . "/" . self::CACHE_FILE_PREFIX . ".*.txt";
00112         $aFiles = glob($sMask);
00113         if (is_array($aFiles)) {
00114             foreach ($aFiles as $sFile) {
00115                 if (is_file($sFile)) {
00116                     @unlink($sFile);
00117                 }
00118             }
00119         }
00120     }
00121 
00132     public function oxNew($sClassName)
00133     {
00134         $aArgs = func_get_args();
00135         array_shift($aArgs);
00136         $iArgCnt = count($aArgs);
00137         $blCacheObj = $iArgCnt < 2;
00138         $sClassName = strtolower($sClassName);
00139 
00140         if (isset(self::$_aClassInstances[$sClassName])) {
00141             return self::$_aClassInstances[$sClassName];
00142         }
00143         if (!defined('OXID_PHP_UNIT') && $blCacheObj) {
00144             $sCacheKey = ($iArgCnt) ? $sClassName . md5(serialize($aArgs)) : $sClassName;
00145             if (isset(self::$_aInstanceCache[$sCacheKey])) {
00146                 return clone self::$_aInstanceCache[$sCacheKey];
00147             }
00148         }
00149 
00150         // performance
00151         if (!defined('OXID_PHP_UNIT') && isset($this->_aClassNameCache[$sClassName])) {
00152             $sActionClassName = $this->_aClassNameCache[$sClassName];
00153         } else {
00154             $sActionClassName = $this->getClassName($sClassName);
00155             //expect __autoload() (oxfunctions.php) to do its job when class_exists() is called
00156             if (!class_exists($sActionClassName)) {
00158                 $oEx = oxNew("oxSystemComponentException");
00159                 $oEx->setMessage('EXCEPTION_SYSTEMCOMPONENT_CLASSNOTFOUND');
00160                 $oEx->setComponent($sClassName);
00161                 $oEx->debugOut();
00162                 throw $oEx;
00163             }
00164             // performance
00165             $this->_aClassNameCache[$sClassName] = $sActionClassName;
00166         }
00167 
00168         $oActionObject = $this->_getObject($sActionClassName, $iArgCnt, $aArgs);
00169         if ($blCacheObj && $oActionObject instanceof oxBase) {
00170             self::$_aInstanceCache[$sCacheKey] = clone $oActionObject;
00171         }
00172 
00173         return $oActionObject;
00174     }
00175 
00188     protected function _getObject($sClassName, $iArgCnt, $aParams)
00189     {
00190         // dynamic creation (if parameter count < 4) gives more performance for regular objects
00191         switch ($iArgCnt) {
00192             case 0:
00193                 $oObj = new $sClassName();
00194                 break;
00195             case 1:
00196                 $oObj = new $sClassName($aParams[0]);
00197                 break;
00198             case 2:
00199                 $oObj = new $sClassName($aParams[0], $aParams[1]);
00200                 break;
00201             case 3:
00202                 $oObj = new $sClassName($aParams[0], $aParams[1], $aParams[2]);
00203                 break;
00204             default:
00205                 try {
00206                     // unlimited constructor arguments support
00207                     $oRo = new ReflectionClass($sClassName);
00208                     $oObj = $oRo->newInstanceArgs($aParams);
00209                 } catch (ReflectionException $oRefExcp) {
00210                     // something went wrong?
00212                     $oEx = oxNew("oxSystemComponentException");
00213                     $oEx->setMessage($oRefExcp->getMessage());
00214                     $oEx->setComponent($sClassName);
00215                     $oEx->debugOut();
00216                     throw $oEx;
00217                 }
00218         }
00219 
00220         return $oObj;
00221     }
00222 
00230     public function resetInstanceCache($sClassName = null)
00231     {
00232         if ($sClassName && isset(self::$_aInstanceCache[$sClassName])) {
00233             unset(self::$_aInstanceCache[$sClassName]);
00234 
00235             return;
00236         }
00237 
00238         //looping due to possible memory "leak".
00239         if (is_array(self::$_aInstanceCache)) {
00240             foreach (self::$_aInstanceCache as $sKey => $oInstance) {
00241                 unset(self::$_aInstanceCache[$sKey]);
00242             }
00243         }
00244 
00245         self::$_aInstanceCache = array();
00246     }
00247 
00253     public function generateUId()
00254     {
00255         return /*substr( $this->getSession()->getId(), 0, 3 ) . */
00256             substr(md5(uniqid('', true) . '|' . microtime()), 0, 32);
00257     }
00258 
00259 
00260 
00268     public function getClassName($sClassName)
00269     {
00270         //$aModules = $this->getConfig()->getConfigParam( 'aModules' );
00271         $aModules = $this->getModuleVar('aModules');
00272         $aClassChain = array();
00273 
00274 
00275         if (is_array($aModules)) {
00276 
00277             $aModules = array_change_key_case($aModules);
00278 
00279             if (array_key_exists($sClassName, $aModules)) {
00280                 //multiple inheritance implementation
00281                 //in case we have multiple modules:
00282                 //like oxoutput => sub/suboutput1&sub/suboutput2&sub/suboutput3
00283                 $aClassChain = explode("&", $aModules[$sClassName]);
00284                 $aClassChain = $this->_getActiveModuleChain($aClassChain);
00285             }
00286 
00287             if (count($aClassChain)) {
00288                 $sParent = $sClassName;
00289 
00290                 //security: just preventing string termination
00291                 $sParent = str_replace(chr(0), '', $sParent);
00292 
00293                 //building middle classes if needed
00294                 $sClassName = $this->_makeSafeModuleClassParents($aClassChain, $sParent);
00295             }
00296         }
00297 
00298         // check if there is a path, if yes, remove it
00299         $sClassName = basename($sClassName);
00300 
00301         return $sClassName;
00302     }
00303 
00311     protected function _getActiveModuleChain($aClassChain)
00312     {
00313         $aDisabledModules = $this->getModuleVar('aDisabledModules');
00314         $aModulePaths = $this->getModuleVar('aModulePaths');
00315 
00316         if (is_array($aDisabledModules) && count($aDisabledModules) > 0) {
00317             foreach ($aDisabledModules as $sId) {
00318                 $sPath = $sId;
00319                 if (is_array($aModulePaths) && array_key_exists($sId, $aModulePaths)) {
00320                     $sPath = $aModulePaths[$sId];
00321                     if (!isset($sPath)) {
00322                         $sPath = $sId;
00323                     }
00324                 }
00325                 foreach ($aClassChain as $sKey => $sModuleClass) {
00326                     if (strpos($sModuleClass, $sPath . "/") === 0) {
00327                         unset($aClassChain[$sKey]);
00328                     } elseif (strpos($sPath, ".")) {
00329                         // If module consists of one file without own dir (getting module.php as id, instead of module)
00330                         if (strpos($sPath, strtolower($sModuleClass)) === 0) {
00331                             unset($aClassChain[$sKey]);
00332                         }
00333                     }
00334                 }
00335             }
00336         }
00337 
00338         return $aClassChain;
00339     }
00340 
00346     protected function _disableModule($sModule)
00347     {
00349         $oModule = oxNew("oxModule");
00350         $sModuleId = $oModule->getIdByPath($sModule);
00351         $oModule->load($sModuleId);
00352 
00354         $oModuleCache = oxNew('oxModuleCache', $oModule);
00356         $oModuleInstaller = oxNew('oxModuleInstaller', $oModuleCache);
00357 
00358         $oModuleInstaller->deactivate($oModule);
00359 
00360     }
00361 
00372     protected function _makeSafeModuleClassParents($aClassChain, $sBaseModule)
00373     {
00374         $sParent = $sBaseModule;
00375         $sClassName = $sBaseModule;
00376 
00377         //building middle classes if needed
00378         foreach ($aClassChain as $sModule) {
00379             //creating middle classes
00380             //e.g. class suboutput1_parent extends oxoutput {}
00381             //     class suboutput2_parent extends suboutput1 {}
00382             //$sModuleClass = $this->getClassName($sModule);
00383 
00384             //security: just preventing string termination
00385             $sModule = str_replace(chr(0), '', $sModule);
00386 
00387             //get parent and module class names from sub/suboutput2
00388             $sModuleClass = basename($sModule);
00389 
00390             if (!class_exists($sModuleClass, false)) {
00391                 $sParentClass = basename($sParent);
00392                 $sModuleParentClass = $sModuleClass . "_parent";
00393 
00394                 //initializing middle class
00395                 if (!class_exists($sModuleParentClass, false)) {
00396                     // If possible using alias instead if eval (since php 5.3).
00397                     if (function_exists('class_alias')) {
00398                         class_alias($sParentClass, $sModuleParentClass);
00399                     } else {
00400                         eval("abstract class $sModuleParentClass extends $sParentClass {}");
00401                     }
00402                 }
00403                 $sParentPath = oxRegistry::get("oxConfigFile")->getVar("sShopDir") . "/modules/" . $sModule . ".php";
00404 
00405                 //including original file
00406                 if (file_exists($sParentPath)) {
00407                     include_once $sParentPath;
00408                 } elseif (!class_exists($sModuleClass)) {
00409                     // special case is when oxconfig class is extended: we cant call "_disableModule" as it requires valid config object
00410                     // but we can't create it as module class extending it does not exist. So we will use orginal oxConfig object instead.
00411                     if ($sParentClass == "oxconfig") {
00412                         $oConfig = $this->_getObject("oxconfig", 0, null);
00413                         oxRegistry::set("oxconfig", $oConfig);
00414                     }
00415 
00416                     // disable module if extended class is not found
00417                     $blDisableModuleOnError = !oxRegistry::get("oxConfigFile")->getVar("blDoNotDisableModuleOnError");
00418                     if ($blDisableModuleOnError) {
00419                         $this->_disableModule($sModule);
00420                     } else {
00421                         //to avoid problems with unitest and only throw a exception if class does not exists MAFI
00423                         $oEx = oxNew("oxSystemComponentException");
00424                         $oEx->setMessage("EXCEPTION_SYSTEMCOMPONENT_CLASSNOTFOUND");
00425                         $oEx->setComponent($sModuleClass);
00426                         throw $oEx;
00427                     }
00428                     continue;
00429                 }
00430             }
00431             $sParent = $sModule;
00432             $sClassName = $sModule;
00433         }
00434 
00435         //returning the last module from the chain
00436         return $sClassName;
00437     }
00438 
00444     public function getShopId()
00445     {
00446         return 'oxbaseshop';
00447     }
00448 
00458     public function getModuleVar($sModuleVarName)
00459     {
00460         //static cache
00461         if (isset(self::$_aModuleVars[$sModuleVarName])) {
00462             return self::$_aModuleVars[$sModuleVarName];
00463         }
00464 
00465         //first try to get it from cache
00466         //we do not use any of our cache APIs, as we want to prevent any class dependencies here
00467         $aValue = $this->_getFromCache($sModuleVarName);
00468 
00469         if (is_null($aValue)) {
00470             $aValue = $this->_getModuleVarFromDB($sModuleVarName);
00471             $this->_setToCache($sModuleVarName, $aValue);
00472         }
00473 
00474         //static cache
00475         self::$_aModuleVars[$sModuleVarName] = $aValue;
00476 
00477         return $aValue;
00478     }
00479 
00486     public function setModuleVar($sModuleVarName, $aValues)
00487     {
00488         if (is_null($aValues)) {
00489             self::$_aModuleVars = null;
00490         } else {
00491             self::$_aModuleVars[$sModuleVarName] = $aValues;
00492         }
00493 
00494         $this->_setToCache($sModuleVarName, $aValues);
00495     }
00496 
00502     protected function _getConfKey()
00503     {
00504         $sFileName = dirname(__FILE__) . "/oxconfk.php";
00505         $sCfgFile = new oxConfigFile($sFileName);
00506 
00507         return $sCfgFile->getVar("sConfigKey");
00508     }
00509 
00515     protected function _getShopUrlMap()
00516     {
00517 
00518         //get from static cache
00519         if (isset(self::$_aModuleVars["urlMap"])) {
00520             return self::$_aModuleVars["urlMap"];
00521         }
00522 
00523         //get from file cache
00524         $aMap = $this->_getFromCache("urlMap", false);
00525         if (!is_null($aMap)) {
00526             self::$_aModuleVars["urlMap"] = $aMap;
00527 
00528             return $aMap;
00529         }
00530 
00531         $aMap = array();
00532 
00533         $oDb = oxDb::getDb();
00534         $sConfKey = $this->_getConfKey();
00535 
00536         $sSelect = "SELECT oxshopid, oxvarname, DECODE( oxvarvalue , " . $oDb->quote($sConfKey) . " ) as oxvarvalue " .
00537                    "FROM oxconfig WHERE oxvarname in ('aLanguageURLs','sMallShopURL','sMallSSLShopURL')";
00538 
00539         $oRs = $oDb->select($sSelect, false, false);
00540 
00541         if ($oRs && $oRs->recordCount() > 0) {
00542             while (!$oRs->EOF) {
00543                 $iShp = (int) $oRs->fields[0];
00544                 $sVar = $oRs->fields[1];
00545                 $sURL = $oRs->fields[2];
00546 
00547                 if ($sVar == 'aLanguageURLs') {
00548                     $aUrls = unserialize($sURL);
00549                     if (is_array($aUrls) && count($aUrls)) {
00550                         $aUrls = array_filter($aUrls);
00551                         $aUrls = array_fill_keys($aUrls, $iShp);
00552                         $aMap = array_merge($aMap, $aUrls);
00553                     }
00554                 } elseif ($sURL) {
00555                     $aMap[$sURL] = $iShp;
00556                 }
00557 
00558                 $oRs->moveNext();
00559             }
00560         }
00561 
00562         //save to cache
00563         $this->_setToCache("urlMap", $aMap, false);
00564         self::$_aModuleVars["urlMap"] = $aMap;
00565 
00566         return $aMap;
00567     }
00568 
00574     protected function _getCacheDir()
00575     {
00576         $sDir = oxRegistry::get("oxConfigFile")->getVar("sCompileDir");
00577 
00578         return $sDir;
00579     }
00580 
00589     protected function _getCacheFileName($sModuleVarName, $sShopId = null)
00590     {
00591         if (is_null($sShopId)) {
00592             $sShopId = $this->getShopId();
00593         }
00594 
00595         $sDir = $this->_getCacheDir();
00596         $sVar = strtolower(basename($sModuleVarName));
00597         $sShop = strtolower(basename($sShopId));
00598 
00599         $sFileName = $sDir . "/" . self::CACHE_FILE_PREFIX . "." . $sShop . '.' . $sVar . ".txt";
00600 
00601         return $sFileName;
00602     }
00603 
00611     protected function _getModuleVarFromDB($sModuleVarName)
00612     {
00613         $oDb = oxDb::getDb();
00614 
00615         $sShopId = $this->getShopId();
00616         $sConfKey = $this->_getConfKey();
00617 
00618         $sSelect = "SELECT DECODE( oxvarvalue , " . $oDb->quote($sConfKey) . " ) FROM oxconfig " .
00619                    "WHERE oxvarname = " . $oDb->quote($sModuleVarName) . " AND oxshopid = " . $oDb->quote($sShopId);
00620 
00621         $sModuleVarName = $oDb->getOne($sSelect, false, false);
00622 
00623         $sModuleVarName = unserialize($sModuleVarName);
00624 
00625         return $sModuleVarName;
00626     }
00627 
00637     protected function _getFromCache($sModuleVarName, $blSubshopSpecific = true)
00638     {
00639         $sShopId = null;
00640         if (!$blSubshopSpecific) {
00641             $sShopId = "all";
00642         }
00643 
00644         $sFileName = $this->_getCacheFileName($sModuleVarName, $sShopId);
00645         $sValue = null;
00646         if (is_readable($sFileName)) {
00647             $sValue = file_get_contents($sFileName);
00648             if ($sValue == serialize(false)) {
00649                 return false;
00650             }
00651 
00652             $sValue = unserialize($sValue);
00653             if ($sValue === false) {
00654                 $sValue = null;
00655             }
00656         }
00657 
00658         return $sValue;
00659     }
00660 
00668     protected function _setToCache($sVarName, $sValue, $blSubshopSpecific = true)
00669     {
00670         $sShopId = null;
00671         if (!$blSubshopSpecific) {
00672             $sShopId = "all";
00673         }
00674 
00675         $sFileName = $this->_getCacheFileName($sVarName, $sShopId);
00676         file_put_contents($sFileName, serialize($sValue), LOCK_EX);
00677     }
00678 }