oxutilsobject.php

Go to the documentation of this file.
00001 <?php
00002 
00006 class oxUtilsObject
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 
00086     public static function setClassInstance( $sClassName, $oInstance )
00087     {
00088         $sClassName = strtolower( $sClassName );
00089         self::$_aClassInstances[$sClassName] = $oInstance;
00090     }
00091 
00097     public static function resetClassInstances()
00098     {
00099         self::$_aClassInstances = array();
00100     }
00101 
00109     public static function resetModuleVars()
00110     {
00111         self::$_aModuleVars = array();
00112 
00113         $sMask = oxRegistry::get("oxConfigFile")->getVar("sCompileDir") . "/" . self::CACHE_FILE_PREFIX . ".*.txt" ;
00114         $aFiles = glob( $sMask );
00115         if ( is_array( $aFiles ) ) {
00116             foreach ( $aFiles as $sFile ) {
00117                 if (is_file($sFile)) {
00118                     @unlink($sFile);
00119                 }
00120             }
00121         }
00122     }
00123 
00134     public function oxNew( $sClassName )
00135     {
00136         $aArgs = func_get_args();
00137         array_shift( $aArgs );
00138         $iArgCnt = count( $aArgs );
00139         $blCacheObj = $iArgCnt < 2;
00140         $sClassName = strtolower( $sClassName );
00141 
00142         if ( isset( self::$_aClassInstances[$sClassName] ) ) {
00143             return self::$_aClassInstances[$sClassName];
00144         }
00145         if ( !defined( 'OXID_PHP_UNIT' ) && $blCacheObj ) {
00146             $sCacheKey  = ( $iArgCnt )?$sClassName.md5( serialize( $aArgs ) ):$sClassName;
00147             if ( isset( self::$_aInstanceCache[$sCacheKey] ) ) {
00148                 return clone self::$_aInstanceCache[$sCacheKey];
00149             }
00150         }
00151 
00152         // performance
00153         if ( !defined( 'OXID_PHP_UNIT' ) && isset( $this->_aClassNameCache[$sClassName] ) ) {
00154             $sActionClassName = $this->_aClassNameCache[$sClassName];
00155         } else {
00156             $sActionClassName = $this->getClassName( $sClassName );
00157             //expect __autoload() (oxfunctions.php) to do its job when class_exists() is called
00158             if ( !class_exists( $sActionClassName ) ) {
00159                 $oEx = oxNew( "oxSystemComponentException" );
00160                 $oEx->setMessage('EXCEPTION_SYSTEMCOMPONENT_CLASSNOTFOUND');
00161                 $oEx->setComponent($sClassName);
00162                 $oEx->debugOut();
00163                 throw $oEx;
00164             }
00165             // performance
00166             $this->_aClassNameCache[$sClassName] = $sActionClassName;
00167         }
00168 
00169         $oActionObject = $this->_getObject( $sActionClassName, $iArgCnt, $aArgs );
00170         if ( $blCacheObj && $oActionObject instanceof oxBase ) {
00171             self::$_aInstanceCache[$sCacheKey] = clone $oActionObject;
00172         }
00173 
00174         return $oActionObject;
00175     }
00176 
00189     protected function _getObject( $sClassName, $iArgCnt, $aParams )
00190     {
00191         // dynamic creation (if parameter count < 4) gives more performance for regular objects
00192         switch( $iArgCnt ) {
00193             case 0:
00194                 $oObj = new $sClassName();
00195                 break;
00196             case 1:
00197                 $oObj = new $sClassName( $aParams[0] );
00198                 break;
00199             case 2:
00200                 $oObj = new $sClassName( $aParams[0], $aParams[1] );
00201                 break;
00202             case 3:
00203                 $oObj = new $sClassName( $aParams[0], $aParams[1], $aParams[2] );
00204                 break;
00205             default:
00206                 try {
00207                     // unlimited constructor arguments support
00208                     $oRo = new ReflectionClass( $sClassName );
00209                     $oObj = $oRo->newInstanceArgs( $aParams );
00210                 } catch ( ReflectionException $oRefExcp ) {
00211                     // 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 
00233     public function oxNewArticle( $sOxID, $aProperties = array())
00234     {
00235         if ( $sOxID && isset( self::$_aLoadedArticles[$sOxID] ) ) {
00236             return self::$_aLoadedArticles[$sOxID];
00237         }
00238 
00239         $oActionObject = $this->oxNew( 'oxarticle' );
00240 
00241         // adding object prioperties
00242         foreach ( $aProperties as $sPropertyName => $sPropertyVal ) {
00243             $oActionObject->$sPropertyName = $sPropertyVal;
00244         }
00245 
00246         $oActionObject->load( $sOxID );
00247 
00248         self::$_aLoadedArticles[$sOxID] = $oActionObject;
00249         return $oActionObject;
00250     }
00251 
00259     public function resetInstanceCache($sClassName = null)
00260     {
00261         if ($sClassName && isset(self::$_aInstanceCache[$sClassName])) {
00262             unset(self::$_aInstanceCache[$sClassName]);
00263             return;
00264         }
00265 
00266         //looping due to possible memory "leak".
00267         if (is_array(self::$_aInstanceCache)) {
00268             foreach (self::$_aInstanceCache as $sKey => $oInstance) {
00269                 unset(self::$_aInstanceCache[$sKey]);
00270             }
00271         }
00272 
00273         self::$_aInstanceCache = array();
00274     }
00275 
00281     public function generateUId()
00282     {
00283         return /*substr( $this->getSession()->getId(), 0, 3 ) . */ substr( md5( uniqid( '', true ).'|'.microtime() ), 0, 32 );
00284     }
00285 
00286 
00287 
00295     public function getClassName( $sClassName )
00296     {
00297         //$aModules = $this->getConfig()->getConfigParam( 'aModules' );
00298         $aModules = $this->getModuleVar('aModules');
00299         $aClassChain = array();
00300 
00301 
00302         if (is_array( $aModules )) {
00303 
00304             $aModules = array_change_key_case( $aModules );
00305 
00306             if ( array_key_exists( $sClassName, $aModules ) ) {
00307                 //multiple inheritance implementation
00308                 //in case we have multiple modules:
00309                 //like oxoutput => sub/suboutput1&sub/suboutput2&sub/suboutput3
00310                 $aClassChain = explode( "&", $aModules[$sClassName] );
00311                 $aClassChain = $this->_getActiveModuleChain( $aClassChain );
00312             }
00313 
00314             if (count($aClassChain)) {
00315                 $sParent = $sClassName;
00316 
00317                 //security: just preventing string termination
00318                 $sParent = str_replace(chr(0), '', $sParent);
00319 
00320                 //building middle classes if needed
00321                 $sClassName = $this->_makeSafeModuleClassParents( $aClassChain, $sParent );
00322             }
00323         }
00324 
00325         // check if there is a path, if yes, remove it
00326         $sClassName = basename( $sClassName );
00327 
00328         return $sClassName;
00329     }
00330 
00338     protected function _getActiveModuleChain( $aClassChain )
00339     {
00340         $aDisabledModules = $this->getModuleVar( 'aDisabledModules' );
00341         $aModulePaths     = $this->getModuleVar( 'aModulePaths' );
00342 
00343         if (is_array( $aDisabledModules ) && count($aDisabledModules) > 0) {
00344             foreach ($aDisabledModules as $sId) {
00345                 $sPath = $aModulePaths[$sId];
00346                 if (!isset($sPath)) {
00347                     $sPath = $sId;
00348                 }
00349                 foreach ( $aClassChain as $sKey => $sModuleClass ) {
00350                     if ( strpos($sModuleClass, $sPath."/" ) === 0 ) {
00351                         unset( $aClassChain[$sKey] );
00352                     }
00353                     // If module consists of one file without own dir (getting module.php as id, instead of module)
00354                     elseif ( strpos( $sPath, "."  ) ) {
00355                         if ( strpos( $sPath, strtolower( $sModuleClass ) ) === 0 ) {
00356                             unset( $aClassChain[$sKey] );
00357                         }
00358                     }
00359                 }
00360             }
00361         }
00362 
00363         return $aClassChain;
00364     }
00365 
00373     protected function _disableModule( $sModule )
00374     {
00378         $oModule = oxNew("oxModule");
00379         $sModuleId = $oModule->getIdByPath($sModule);
00380         $oModule->deactivate($sModuleId);
00381     }
00382 
00393     protected function _makeSafeModuleClassParents( $aClassChain, $sBaseModule )
00394     {
00395         $sParent = $sBaseModule;
00396         $sClassName = $sBaseModule;
00397 
00398         //building middle classes if needed
00399         foreach ($aClassChain as $sModule) {
00400             //creating middle classes
00401             //e.g. class suboutput1_parent extends oxoutput {}
00402             //     class suboutput2_parent extends suboutput1 {}
00403             //$sModuleClass = $this->getClassName($sModule);
00404 
00405             //security: just preventing string termination
00406             $sModule = str_replace(chr(0), '', $sModule);
00407 
00408             //get parent and module class names from sub/suboutput2
00409             $sModuleClass = basename($sModule);
00410 
00411             if ( !class_exists( $sModuleClass, false ) ) {
00412                 $sParentClass       = basename($sParent);
00413                 $sModuleParentClass = $sModuleClass."_parent";
00414 
00415                 //initializing middle class
00416                 if (!class_exists($sModuleParentClass, false)) {
00417                     // If possible using alias instead if eval (since php 5.3).
00418                     if (function_exists('class_alias')) {
00419                         class_alias($sParentClass, $sModuleParentClass);
00420                     } else {
00421                         eval("abstract class $sModuleParentClass extends $sParentClass {}");
00422                     }
00423                 }
00424                 $sParentPath = oxRegistry::get( "oxConfigFile" )->getVar( "sShopDir" ) . "/modules/".$sModule.".php";
00425 
00426                 //including original file
00427                 if ( file_exists( $sParentPath ) ) {
00428                     include_once $sParentPath;
00429                 } elseif ( !class_exists( $sModuleClass ) ) {
00430                     // special case is when oxconfig class is extended: we cant call "_disableModule" as it requires valid config object
00431                     // but we can't create it as module class extending it does not exist. So we will use orginal oxConfig object instead.
00432                     if ( $sParentClass == "oxconfig" ) {
00433                         $oConfig = $this->_getObject( "oxconfig", 0, null );
00434                         oxRegistry::set( "oxconfig", $oConfig );
00435                     }
00436 
00437                     // disable module if extended class is not found
00438                     $this->_disableModule( $sModule );
00439 
00440                     //to avoid problems with unitest and only throw a exception if class does not exists MAFI
00441                     $oEx = oxNew( "oxSystemComponentException" );
00442                     $oEx->setMessage('EXCEPTION_SYSTEMCOMPONENT_CLASSNOTFOUND');
00443                     $oEx->setComponent($sModuleClass);
00444                     continue;
00445                 }
00446             }
00447             $sParent = $sModule;
00448             $sClassName = $sModule;
00449         }
00450 
00451         //returning the last module from the chain
00452         return $sClassName;
00453     }
00454 
00460     public function getShopId()
00461     {
00462             return 'oxbaseshop';
00463     }
00464 
00474     public function getModuleVar( $sModuleVarName )
00475     {
00476         //static cache
00477         if ( isset(self::$_aModuleVars[$sModuleVarName]) ) {
00478             return self::$_aModuleVars[$sModuleVarName];
00479         }
00480 
00481         //first try to get it from cache
00482         //we do not use any of our cache APIs, as we want to prevent any class dependencies here
00483         $aValue = $this->_getFromCache( $sModuleVarName );
00484 
00485         if ( is_null( $aValue ) ) {
00486             $aValue = $this->_getModuleVarFromDB($sModuleVarName);
00487             $this->_setToCache( $sModuleVarName, $aValue);
00488         }
00489 
00490         //static cache
00491         self::$_aModuleVars[$sModuleVarName] = $aValue;
00492 
00493         return $aValue;
00494     }
00495 
00504     public function setModuleVar( $sModuleVarName, $aValues )
00505     {
00506         if ( is_null( $aValues) ) {
00507             unset( self::$_aModuleVars );
00508         } else {
00509             self::$_aModuleVars[$sModuleVarName] = $aValues ;
00510         }
00511 
00512         $this->_setToCache($sModuleVarName, $aValues);
00513     }
00514 
00520     protected function _getConfKey()
00521     {
00522         $sFileName = dirname( __FILE__ ) . "/oxconfk.php";
00523         $sCfgFile = new oxConfigFile( $sFileName );
00524         return $sCfgFile->getVar("sConfigKey");
00525     }
00526 
00532     protected function _getShopUrlMap( )
00533     {
00534 
00535         //get from static cache
00536         if (isset( self::$_aModuleVars["urlMap"] )) {
00537             return self::$_aModuleVars["urlMap"];
00538         }
00539 
00540         //get from file cache
00541         $aMap = $this->_getFromCache("urlMap", false);
00542         if (!is_null($aMap)) {
00543             self::$_aModuleVars["urlMap"] = $aMap;
00544             return $aMap;
00545         }
00546 
00547         $aMap = array();
00548 
00549         $oDb = oxDb::getDb();
00550         $sConfKey = $this->_getConfKey();
00551 
00552         $sSelect = "SELECT oxshopid, oxvarname, DECODE( oxvarvalue , ".$oDb->quote($sConfKey)." ) as oxvarvalue ".
00553                    "FROM oxconfig WHERE oxvarname in ('aLanguageURLs','sMallShopURL','sMallSSLShopURL')";
00554 
00555         $oRs = $oDb->select($sSelect, false, false);
00556 
00557         if ( $oRs && $oRs->recordCount() > 0) {
00558             while ( !$oRs->EOF ) {
00559                 $iShp = (int) $oRs->fields[0];
00560                 $sVar = $oRs->fields[1];
00561                 $sURL = $oRs->fields[2];
00562 
00563                 if ($sVar == 'aLanguageURLs') {
00564                     $aUrls = unserialize($sURL);
00565                     if (is_array($aUrls) && count($aUrls)) {
00566                         $aUrls = array_filter($aUrls);
00567                         $aUrls = array_fill_keys($aUrls, $iShp);
00568                         $aMap  = array_merge($aMap, $aUrls);
00569                     }
00570                 } elseif ($sURL) {
00571                     $aMap[$sURL] = $iShp;
00572                 }
00573 
00574                 $oRs->moveNext();
00575             }
00576         }
00577 
00578         //save to cache
00579         $this->_setToCache("urlMap", $aMap, false);
00580         self::$_aModuleVars["urlMap"] = $aMap;
00581 
00582         return $aMap;
00583     }
00584 
00590     protected function _getCacheDir()
00591     {
00592         $sDir = oxRegistry::get("oxConfigFile")->getVar("sCompileDir");
00593         return $sDir;
00594     }
00595 
00604     protected function _getCacheFileName($sModuleVarName, $sShopId = null)
00605     {
00606         if (is_null($sShopId)) {
00607             $sShopId = $this->getShopId();
00608         }
00609 
00610         $sDir = $this->_getCacheDir();
00611         $sVar  = strtolower( basename ($sModuleVarName) );
00612         $sShop = strtolower( basename ($sShopId) );
00613 
00614         $sFileName = $sDir . "/" . self::CACHE_FILE_PREFIX . "." . $sShop . '.' . $sVar . ".txt";
00615 
00616         return $sFileName;
00617     }
00618 
00626     protected function _getModuleVarFromDB( $sModuleVarName )
00627     {
00628         $oDb = oxDb::getDb();
00629 
00630         $sShopId  = $this->getShopId();
00631         $sConfKey = $this->_getConfKey();
00632 
00633         $sSelect = "SELECT DECODE( oxvarvalue , ".$oDb->quote($sConfKey)." ) FROM oxconfig ".
00634                    "WHERE oxvarname = ".$oDb->quote( $sModuleVarName )." AND oxshopid = ".$oDb->quote($sShopId);
00635 
00636         $sModuleVarName = $oDb->getOne($sSelect, false, false);
00637 
00638         $sModuleVarName = unserialize( $sModuleVarName );
00639 
00640         return $sModuleVarName;
00641     }
00642 
00652     protected function _getFromCache( $sModuleVarName, $blSubshopSpecific = true )
00653     {
00654         $sShopId = null;
00655         if ( !$blSubshopSpecific ) {
00656             $sShopId = "all";
00657         }
00658 
00659         $sFileName = $this->_getCacheFileName($sModuleVarName, $sShopId);
00660         $sValue = null;
00661         if ( is_readable( $sFileName ) ) {
00662             $sValue = file_get_contents( $sFileName );
00663             $sValue = unserialize( $sValue );
00664         }
00665 
00666         return $sValue ;
00667     }
00668 
00678     protected function _setToCache( $sVarName, $sValue,  $blSubshopSpecific = true )
00679     {
00680         $sShopId = null;
00681         if ( !$blSubshopSpecific ) {
00682             $sShopId = "all";
00683         }
00684 
00685         $sFileName = $this->_getCacheFileName($sVarName, $sShopId);
00686         file_put_contents( $sFileName, serialize($sValue) );
00687     }
00688 
00689 }