oxutilsobject.php

Go to the documentation of this file.
00001 <?php
00002 
00006 class oxUtilsObject /*extends oxSuperCfg*/
00007 {
00008 
00012     const CACHE_FILE_PREFIX = "config";
00013 
00019     protected $_aClassNameCache = array();
00020 
00026     protected static $_aLoadedArticles = array();
00027 
00033     protected static $_aInstanceCache = array();
00034 
00040     protected static $_aModuleVars = array();
00041 
00047     protected static $_aClassInstances = array();
00048 
00054     private static $_instance = null;
00055 
00061     public static function getInstance()
00062     {
00063         // disable caching for test modules
00064         if ( defined( 'OXID_PHP_UNIT' ) ) {
00065             self::$_instance = null;
00066         }
00067 
00068         if ( !self::$_instance instanceof oxUtilsObject ) {
00069 
00070             // allow modules
00071             $oUtilsObject = new oxUtilsObject();
00072             self::$_instance = $oUtilsObject->oxNew( 'oxUtilsObject' );
00073         }
00074         return self::$_instance;
00075     }
00076 
00088     public static function setClassInstance( $sClassName, $oInstance )
00089     {
00090         $sClassName = strtolower( $sClassName );
00091         self::$_aClassInstances[$sClassName] = $oInstance;
00092     }
00093 
00101     public static function resetClassInstances()
00102     {
00103         self::$_aClassInstances = array();
00104     }
00105 
00113     public static function resetModuleVars()
00114     {
00115         self::$_aModuleVars = array();
00116 
00117         $sMask = oxRegistry::get("oxConfigFile")->getVar("sCompileDir") . "/" . self::CACHE_FILE_PREFIX . ".*.txt" ;
00118         $aFiles = glob( $sMask );
00119         if ( is_array( $aFiles ) ) {
00120             foreach ( $aFiles as $sFile ) {
00121                 if (is_file($sFile)) {
00122                     @unlink($sFile);
00123                 }
00124             }
00125         }
00126     }
00127 
00138     public function oxNew( $sClassName )
00139     {
00140         $aArgs = func_get_args();
00141         array_shift( $aArgs );
00142         $iArgCnt = count( $aArgs );
00143         $blCacheObj = $iArgCnt < 2;
00144         $sClassName = strtolower( $sClassName );
00145 
00146         if ( isset( self::$_aClassInstances[$sClassName] ) ) {
00147             return self::$_aClassInstances[$sClassName];
00148         }
00149 
00150         if ( !defined( 'OXID_PHP_UNIT' ) && $blCacheObj ) {
00151             $sCacheKey  = ( $iArgCnt )?$sClassName.md5( serialize( $aArgs ) ):$sClassName;
00152             if ( isset( self::$_aInstanceCache[$sCacheKey] ) ) {
00153                 return clone self::$_aInstanceCache[$sCacheKey];
00154             }
00155         }
00156 
00157         // performance
00158         if ( !defined( 'OXID_PHP_UNIT' ) && isset( $this->_aClassNameCache[$sClassName] ) ) {
00159             $sActionClassName = $this->_aClassNameCache[$sClassName];
00160         } else {
00161             $sActionClassName = $this->getClassName( $sClassName );
00162             //expect __autoload() (oxfunctions.php) to do its job when class_exists() is called
00163             if ( !class_exists( $sActionClassName ) ) {
00164                 $oEx = oxNew( "oxSystemComponentException" );
00165                 $oEx->setMessage('EXCEPTION_SYSTEMCOMPONENT_CLASSNOTFOUND');
00166                 $oEx->setComponent($sClassName);
00167                 $oEx->debugOut();
00168                 throw $oEx;
00169             }
00170             // performance
00171             $this->_aClassNameCache[$sClassName] = $sActionClassName;
00172         }
00173 
00174         $oActionObject = $this->_getObject( $sActionClassName, $iArgCnt, $aArgs );
00175         if ( $blCacheObj && $oActionObject instanceof oxBase ) {
00176             self::$_aInstanceCache[$sCacheKey] = clone $oActionObject;
00177         }
00178 
00179         return $oActionObject;
00180     }
00181 
00194     protected function _getObject( $sClassName, $iArgCnt, $aParams )
00195     {
00196         // dynamic creation (if parameter count < 4) gives more performance for regular objects
00197         switch( $iArgCnt ) {
00198             case 0:
00199                 $oObj = new $sClassName();
00200                 break;
00201             case 1:
00202                 $oObj = new $sClassName( $aParams[0] );
00203                 break;
00204             case 2:
00205                 $oObj = new $sClassName( $aParams[0], $aParams[1] );
00206                 break;
00207             case 3:
00208                 $oObj = new $sClassName( $aParams[0], $aParams[1], $aParams[2] );
00209                 break;
00210             default:
00211                 try {
00212                     // unlimited constructor arguments support
00213                     $oRo = new ReflectionClass( $sClassName );
00214                     $oObj = $oRo->newInstanceArgs( $aParams );
00215                 } catch ( ReflectionException $oRefExcp ) {
00216                     // something went wrong?
00217                     $oEx = oxNew( "oxSystemComponentException" );
00218                     $oEx->setMessage( $oRefExcp->getMessage() );
00219                     $oEx->setComponent( $sClassName );
00220                     $oEx->debugOut();
00221                     throw $oEx;
00222                 }
00223         }
00224 
00225         return $oObj;
00226     }
00227 
00236     public function oxNewArticle( $sOxID, $aProperties = array())
00237     {
00238         if ( $sOxID && isset( self::$_aLoadedArticles[$sOxID] ) ) {
00239             return self::$_aLoadedArticles[$sOxID];
00240         }
00241 
00242         $oActionObject = $this->oxNew( 'oxarticle' );
00243 
00244         // adding object prioperties
00245         foreach ( $aProperties as $sPropertyName => $sPropertyVal ) {
00246             $oActionObject->$sPropertyName = $sPropertyVal;
00247         }
00248 
00249         $oActionObject->load( $sOxID );
00250 
00251         self::$_aLoadedArticles[$sOxID] = $oActionObject;
00252         return $oActionObject;
00253     }
00254 
00262     public function resetInstanceCache($sClassName = null)
00263     {
00264         if ($sClassName && isset(self::$_aInstanceCache[$sClassName])) {
00265             unset(self::$_aInstanceCache[$sClassName]);
00266             return;
00267         }
00268 
00269         //looping due to possible memory "leak".
00270         if (is_array(self::$_aInstanceCache)) {
00271             foreach (self::$_aInstanceCache as $sKey => $oInstance) {
00272                 unset(self::$_aInstanceCache[$sKey]);
00273             }
00274         }
00275 
00276         self::$_aInstanceCache = array();
00277     }
00278 
00284     public function generateUId()
00285     {
00286         return /*substr( $this->getSession()->getId(), 0, 3 ) . */ substr( md5( uniqid( '', true ).'|'.microtime() ), 0, 32 );
00287     }
00288 
00289 
00290 
00298     public function getClassName( $sClassName )
00299     {
00300         //$aModules = $this->getConfig()->getConfigParam( 'aModules' );
00301         $aModules = $this->getModuleVar('aModules');
00302         $aClassChain = array();
00303 
00304 
00305         if (is_array( $aModules )) {
00306 
00307             $aModules = array_change_key_case( $aModules );
00308 
00309             if ( array_key_exists( $sClassName, $aModules ) ) {
00310                 //multiple inheritance implementation
00311                 //in case we have multiple modules:
00312                 //like oxoutput => sub/suboutput1&sub/suboutput2&sub/suboutput3
00313                 $aClassChain = explode( "&", $aModules[$sClassName] );
00314                 $aClassChain = $this->_getActiveModuleChain( $aClassChain );
00315             }
00316 
00317             if (count($aClassChain)) {
00318                 $sParent = $sClassName;
00319 
00320                 //security: just preventing string termination
00321                 $sParent = str_replace(chr(0), '', $sParent);
00322 
00323                 //building middle classes if needed
00324                 $sClassName = $this->_makeSafeModuleClassParents( $aClassChain, $sParent );
00325             }
00326         }
00327 
00328         // check if there is a path, if yes, remove it
00329         $sClassName = basename( $sClassName );
00330 
00331         return $sClassName;
00332     }
00333 
00341     protected function _getActiveModuleChain( $aClassChain )
00342     {
00343         //$myConfig = $this->getConfig();
00344 
00345         $aDisabledModules = $this->getModuleVar( 'aDisabledModules' ); //array();//$myConfig->getConfigParam( 'aDisabledModules' );
00346         $aModulePaths     = $this->getModuleVar( 'aModulePaths' );//array();//$myConfig->getConfigParam( 'aModulePaths' );
00347 
00348         if (is_array( $aDisabledModules ) && count($aDisabledModules) > 0) {
00349             foreach ($aDisabledModules as $sId) {
00350                 $sPath = $aModulePaths[$sId];
00351                 if (!isset($sPath)) {
00352                     $sPath = $sId;
00353                 }
00354                 foreach ( $aClassChain as $sKey => $sModuleClass ) {
00355                     if ( strpos($sModuleClass, $sPath."/" ) === 0 ) {
00356                         unset( $aClassChain[$sKey] );
00357                     }
00358                     // If module consists of one file without own dir (getting module.php as id, instead of module)
00359                     elseif ( strpos( $sPath, "."  ) ) {
00360                         if ( strpos( $sPath, strtolower( $sModuleClass ) ) === 0 ) {
00361                             unset( $aClassChain[$sKey] );
00362                         }
00363                     }
00364                 }
00365             }
00366         }
00367 
00368         return $aClassChain;
00369     }
00370 
00378     protected function _disableModule( $sModule )
00379     {
00383         $oModule = oxNew("oxModule");
00384         $sModuleId = $oModule->getIdByPath($sModule);
00385         $oModule->deactivate($sModuleId);
00386     }
00387 
00398     private function _makeSafeModuleClassParents( $aClassChain, $sBaseModule )
00399     {
00400         //$myConfig = $this->getConfig();
00401 
00402 
00403         $sParent = $sBaseModule;
00404         $sClassName = $sBaseModule;
00405 
00406         //building middle classes if needed
00407         foreach ($aClassChain as $sModule) {
00408             //creating middle classes
00409             //e.g. class suboutput1_parent extends oxoutput {}
00410             //     class suboutput2_parent extends suboutput1 {}
00411             //$sModuleClass = $this->getClassName($sModule);
00412 
00413             //security: just preventing string termination
00414             $sModule = str_replace(chr(0), '', $sModule);
00415 
00416             //get parent and module class names from sub/suboutput2
00417             $sModuleClass = basename($sModule);
00418 
00419             if ( !class_exists( $sModuleClass, false ) ) {
00420                 $sParentClass       = basename($sParent);
00421                 $sModuleParentClass = $sModuleClass."_parent";
00422 
00423                 //initializing middle class
00424                 if (!class_exists($sModuleParentClass, false)) {
00425                     // If possible using alias instead if eval (since php 5.3).
00426                     if (function_exists('class_alias')) {
00427                         class_alias($sParentClass, $sModuleParentClass);
00428                     } else {
00429                         eval("abstract class $sModuleParentClass extends $sParentClass {}");
00430                     }
00431                 }
00432                 $sParentPath = oxRegistry::get( "oxConfigFile" )->getVar( "sShopDir" ) . "/modules/".$sModule.".php";
00433 
00434                 //including original file
00435                 if ( file_exists( $sParentPath ) ) {
00436                     include_once $sParentPath;
00437                 } elseif ( !class_exists( $sModuleClass ) ) {
00438                     // special case is when oxconfig class is extended: we cant call "_disableModule" as it requires valid config object
00439                     // but we can't create it as module class extending it does not exist. So we will use orginal oxConfig object instead.
00440                     if ( $sParentClass == "oxconfig" ) {
00441                         $oConfig = $this->_getObject( "oxconfig", 0, null );
00442                         oxRegistry::set( "oxconfig", $oConfig );
00443                     }
00444 
00445                     // disable module if extended class is not found
00446                     $this->_disableModule( $sModule );
00447 
00448                     //to avoid problems with unitest and only throw a exception if class does not exists MAFI
00449                     $oEx = oxNew( "oxSystemComponentException" );
00450                     $oEx->setMessage('EXCEPTION_SYSTEMCOMPONENT_CLASSNOTFOUND');
00451                     $oEx->setComponent($sModuleClass);
00452                     continue;
00453                 }
00454             }
00455             $sParent = $sModule;
00456             $sClassName = $sModule;
00457         }
00458 
00459         //returning the last module from the chain
00460         return $sClassName;
00461     }
00462 
00468     public function getShopId()
00469     {
00470             return 'oxbaseshop';
00471     }
00472 
00482     public function getModuleVar( $sModuleVarName )
00483     {
00484         //static cache
00485         if ( isset(self::$_aModuleVars[$sModuleVarName]) ) {
00486             return self::$_aModuleVars[$sModuleVarName];
00487         }
00488 
00489         //first try to get it from cache
00490         //we do not use any of our cache APIs, as we want to prevent any class dependencies here
00491         $aValue = $this->_getFromCache( $sModuleVarName );
00492 
00493         if ( is_null( $aValue ) ) {
00494             $aValue = $this->_getModuleVarFromDB($sModuleVarName);
00495             $this->_setToCache( $sModuleVarName, $aValue);
00496         }
00497 
00498         //static cache
00499         self::$_aModuleVars[$sModuleVarName] = $aValue;
00500 
00501         return $aValue;
00502     }
00503 
00512     public function setModuleVar( $sModuleVarName, $aValues )
00513     {
00514         if ( is_null( $aValues) ) {
00515             unset( self::$_aModuleVars );
00516         } else {
00517             self::$_aModuleVars[$sModuleVarName] = $aValues ;
00518         }
00519 
00520         $this->_setToCache($sModuleVarName, $aValues);
00521     }
00522 
00528     protected function _getConfKey()
00529     {
00530         $sFileName = dirname( __FILE__ ) . "/oxconfk.php";
00531         $sCfgFile = new oxConfigFile( $sFileName );
00532         return $sCfgFile->getVar("sConfigKey");
00533     }
00534 
00540     protected function _getShopUrlMap( )
00541     {
00542 
00543         //get from static cache
00544         if (isset( self::$_aModuleVars["urlMap"] )) {
00545             return self::$_aModuleVars["urlMap"];
00546         }
00547 
00548         //get from file cache
00549         $aMap = $this->_getFromCache("urlMap", false);
00550         if (!is_null($aMap)) {
00551             self::$_aModuleVars["urlMap"] = $aMap;
00552             return $aMap;
00553         }
00554 
00555         $aMap = array();
00556 
00557         $oDb = oxDb::getDb();
00558         $sConfKey = $this->_getConfKey();
00559 
00560         $sSelect = "SELECT oxshopid, oxvarname, DECODE( oxvarvalue , ".$oDb->quote($sConfKey)." ) as oxvarvalue ".
00561                    "FROM oxconfig WHERE oxvarname in ('aLanguageURLs','sMallShopURL','sMallSSLShopURL')";
00562 
00563         $oRs = $oDb->select($sSelect, false, false);
00564 
00565         if ( $oRs && $oRs->recordCount() > 0) {
00566             while ( !$oRs->EOF ) {
00567                 $iShp = (int) $oRs->fields[0];
00568                 $sVar = $oRs->fields[1];
00569                 $sURL = $oRs->fields[2];
00570 
00571                 if ($sVar == 'aLanguageURLs') {
00572                     $aUrls = unserialize($sURL);
00573                     if (is_array($aUrls) && count($aUrls)) {
00574                         $aUrls = array_filter($aUrls);
00575                         $aUrls = array_fill_keys($aUrls, $iShp);
00576                         $aMap  = array_merge($aMap, $aUrls);
00577                     }
00578                 } elseif ($sURL) {
00579                     $aMap[$sURL] = $iShp;
00580                 }
00581 
00582                 $oRs->moveNext();
00583             }
00584         }
00585 
00586         //save to cache
00587         $this->_setToCache("urlMap", $aMap, false);
00588         self::$_aModuleVars["urlMap"] = $aMap;
00589 
00590         return $aMap;
00591     }
00592 
00598     protected function _getCacheDir()
00599     {
00600         $sDir = oxRegistry::get("oxConfigFile")->getVar("sCompileDir");
00601         return $sDir;
00602     }
00603 
00612     protected function _getCacheFileName($sModuleVarName, $sShopId = null)
00613     {
00614         if (is_null($sShopId)) {
00615             $sShopId = $this->getShopId();
00616         }
00617 
00618         $sDir = $this->_getCacheDir();
00619         $sVar  = strtolower( basename ($sModuleVarName) );
00620         $sShop = strtolower( basename ($sShopId) );
00621 
00622         $sFileName = $sDir . "/" . self::CACHE_FILE_PREFIX . "." . $sShop . '.' . $sVar . ".txt";
00623 
00624         return $sFileName;
00625     }
00626 
00634     protected function _getModuleVarFromDB( $sModuleVarName )
00635     {
00636         $oDb = oxDb::getDb();
00637 
00638         $sShopId  = $this->getShopId();
00639         $sConfKey = $this->_getConfKey();
00640 
00641         $sSelect = "SELECT DECODE( oxvarvalue , ".$oDb->quote($sConfKey)." ) FROM oxconfig ".
00642                    "WHERE oxvarname = ".$oDb->quote( $sModuleVarName )." AND oxshopid = ".$oDb->quote($sShopId);
00643 
00644         $sModuleVarName = $oDb->getOne($sSelect, false, false);
00645 
00646         $sModuleVarName = unserialize( $sModuleVarName );
00647 
00648         return $sModuleVarName;
00649     }
00650 
00660     protected function _getFromCache( $sModuleVarName, $blSubshopSpecific = true )
00661     {
00662         $sShopId = null;
00663         if ( !$blSubshopSpecific ) {
00664             $sShopId = "all";
00665         }
00666 
00667         $sFileName = $this->_getCacheFileName($sModuleVarName, $sShopId);
00668         $sValue = null;
00669         if ( is_readable( $sFileName ) ) {
00670             $sValue = file_get_contents( $sFileName );
00671             $sValue = unserialize( $sValue );
00672         }
00673 
00674         return $sValue ;
00675     }
00676 
00686     protected function _setToCache( $sVarName, $sValue,  $blSubshopSpecific = true )
00687     {
00688         $sShopId = null;
00689         if ( !$blSubshopSpecific ) {
00690             $sShopId = "all";
00691         }
00692 
00693         $sFileName = $this->_getCacheFileName($sVarName, $sShopId);
00694         file_put_contents( $sFileName, serialize($sValue) );
00695     }
00696 
00697 }