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 ) ) {
00162                 $oEx = oxNew( "oxSystemComponentException" );
00163                 $oEx->setMessage('EXCEPTION_SYSTEMCOMPONENT_CLASSNOTFOUND');
00164                 $oEx->setComponent($sClassName);
00165                 $oEx->debugOut();
00166                 throw $oEx;
00167             }
00168             // performance
00169             $this->_aClassNameCache[$sClassName] = $sActionClassName;
00170         }
00171 
00172         $oActionObject = $this->_getObject( $sActionClassName, $iArgCnt, $aArgs );
00173         if ( $blCacheObj && $oActionObject instanceof oxBase ) {
00174             self::$_aInstanceCache[$sCacheKey] = clone $oActionObject;
00175         }
00176 
00177         return $oActionObject;
00178     }
00179 
00192     protected function _getObject( $sClassName, $iArgCnt, $aParams )
00193     {
00194         // dynamic creation (if parameter count < 4) gives more performance for regular objects
00195         switch( $iArgCnt ) {
00196             case 0:
00197                 $oObj = new $sClassName();
00198                 break;
00199             case 1:
00200                 $oObj = new $sClassName( $aParams[0] );
00201                 break;
00202             case 2:
00203                 $oObj = new $sClassName( $aParams[0], $aParams[1] );
00204                 break;
00205             case 3:
00206                 $oObj = new $sClassName( $aParams[0], $aParams[1], $aParams[2] );
00207                 break;
00208             default:
00209                 try {
00210                     // unlimited constructor arguments support
00211                     $oRo = new ReflectionClass( $sClassName );
00212                     $oObj = $oRo->newInstanceArgs( $aParams );
00213                 } catch ( ReflectionException $oRefExcp ) {
00214                     // something went wrong?
00218                     $oEx = oxNew( "oxSystemComponentException" );
00219                     $oEx->setMessage( $oRefExcp->getMessage() );
00220                     $oEx->setComponent( $sClassName );
00221                     $oEx->debugOut();
00222                     throw $oEx;
00223                 }
00224         }
00225 
00226         return $oObj;
00227     }
00228 
00239     public function oxNewArticle( $sOxID, $aProperties = array())
00240     {
00241         if ( $sOxID && isset( self::$_aLoadedArticles[$sOxID] ) ) {
00242             return self::$_aLoadedArticles[$sOxID];
00243         }
00244 
00245         $oActionObject = $this->oxNew( 'oxarticle' );
00246 
00247         // adding object prioperties
00248         foreach ( $aProperties as $sPropertyName => $sPropertyVal ) {
00249             $oActionObject->$sPropertyName = $sPropertyVal;
00250         }
00251 
00252         $oActionObject->load( $sOxID );
00253 
00254         self::$_aLoadedArticles[$sOxID] = $oActionObject;
00255         return $oActionObject;
00256     }
00257 
00265     public function resetInstanceCache($sClassName = null)
00266     {
00267         if ($sClassName && isset(self::$_aInstanceCache[$sClassName])) {
00268             unset(self::$_aInstanceCache[$sClassName]);
00269             return;
00270         }
00271 
00272         //looping due to possible memory "leak".
00273         if (is_array(self::$_aInstanceCache)) {
00274             foreach (self::$_aInstanceCache as $sKey => $oInstance) {
00275                 unset(self::$_aInstanceCache[$sKey]);
00276             }
00277         }
00278 
00279         self::$_aInstanceCache = array();
00280     }
00281 
00287     public function generateUId()
00288     {
00289         return /*substr( $this->getSession()->getId(), 0, 3 ) . */ substr( md5( uniqid( '', true ).'|'.microtime() ), 0, 32 );
00290     }
00291 
00292 
00293 
00301     public function getClassName( $sClassName )
00302     {
00303         //$aModules = $this->getConfig()->getConfigParam( 'aModules' );
00304         $aModules = $this->getModuleVar('aModules');
00305         $aClassChain = array();
00306 
00307 
00308         if (is_array( $aModules )) {
00309 
00310             $aModules = array_change_key_case( $aModules );
00311 
00312             if ( array_key_exists( $sClassName, $aModules ) ) {
00313                 //multiple inheritance implementation
00314                 //in case we have multiple modules:
00315                 //like oxoutput => sub/suboutput1&sub/suboutput2&sub/suboutput3
00316                 $aClassChain = explode( "&", $aModules[$sClassName] );
00317                 $aClassChain = $this->_getActiveModuleChain( $aClassChain );
00318             }
00319 
00320             if (count($aClassChain)) {
00321                 $sParent = $sClassName;
00322 
00323                 //security: just preventing string termination
00324                 $sParent = str_replace(chr(0), '', $sParent);
00325 
00326                 //building middle classes if needed
00327                 $sClassName = $this->_makeSafeModuleClassParents( $aClassChain, $sParent );
00328             }
00329         }
00330 
00331         // check if there is a path, if yes, remove it
00332         $sClassName = basename( $sClassName );
00333 
00334         return $sClassName;
00335     }
00336 
00344     protected function _getActiveModuleChain( $aClassChain )
00345     {
00346         $aDisabledModules = $this->getModuleVar( 'aDisabledModules' );
00347         $aModulePaths     = $this->getModuleVar( 'aModulePaths' );
00348 
00349         if (is_array( $aDisabledModules ) && count($aDisabledModules) > 0) {
00350             foreach ($aDisabledModules as $sId) {
00351                 $sPath = $aModulePaths[$sId];
00352                 if (!isset($sPath)) {
00353                     $sPath = $sId;
00354                 }
00355                 foreach ( $aClassChain as $sKey => $sModuleClass ) {
00356                     if ( strpos($sModuleClass, $sPath."/" ) === 0 ) {
00357                         unset( $aClassChain[$sKey] );
00358                     }
00359                     // If module consists of one file without own dir (getting module.php as id, instead of module)
00360                     elseif ( strpos( $sPath, "."  ) ) {
00361                         if ( strpos( $sPath, strtolower( $sModuleClass ) ) === 0 ) {
00362                             unset( $aClassChain[$sKey] );
00363                         }
00364                     }
00365                 }
00366             }
00367         }
00368 
00369         return $aClassChain;
00370     }
00371 
00379     protected function _disableModule( $sModule )
00380     {
00384         $oModule = oxNew("oxModule");
00385         $sModuleId = $oModule->getIdByPath($sModule);
00386         $oModule->deactivate($sModuleId);
00387     }
00388 
00399     protected function _makeSafeModuleClassParents( $aClassChain, $sBaseModule )
00400     {
00401         $sParent = $sBaseModule;
00402         $sClassName = $sBaseModule;
00403 
00404         //building middle classes if needed
00405         foreach ($aClassChain as $sModule) {
00406             //creating middle classes
00407             //e.g. class suboutput1_parent extends oxoutput {}
00408             //     class suboutput2_parent extends suboutput1 {}
00409             //$sModuleClass = $this->getClassName($sModule);
00410 
00411             //security: just preventing string termination
00412             $sModule = str_replace(chr(0), '', $sModule);
00413 
00414             //get parent and module class names from sub/suboutput2
00415             $sModuleClass = basename($sModule);
00416 
00417             if ( !class_exists( $sModuleClass, false ) ) {
00418                 $sParentClass       = basename($sParent);
00419                 $sModuleParentClass = $sModuleClass."_parent";
00420 
00421                 //initializing middle class
00422                 if (!class_exists($sModuleParentClass, false)) {
00423                     // If possible using alias instead if eval (since php 5.3).
00424                     if (function_exists('class_alias')) {
00425                         class_alias($sParentClass, $sModuleParentClass);
00426                     } else {
00427                         eval("abstract class $sModuleParentClass extends $sParentClass {}");
00428                     }
00429                 }
00430                 $sParentPath = oxRegistry::get( "oxConfigFile" )->getVar( "sShopDir" ) . "/modules/".$sModule.".php";
00431 
00432                 //including original file
00433                 if ( file_exists( $sParentPath ) ) {
00434                     include_once $sParentPath;
00435                 } elseif ( !class_exists( $sModuleClass ) ) {
00436                     // special case is when oxconfig class is extended: we cant call "_disableModule" as it requires valid config object
00437                     // but we can't create it as module class extending it does not exist. So we will use orginal oxConfig object instead.
00438                     if ( $sParentClass == "oxconfig" ) {
00439                         $oConfig = $this->_getObject( "oxconfig", 0, null );
00440                         oxRegistry::set( "oxconfig", $oConfig );
00441                     }
00442 
00443                     // disable module if extended class is not found
00444                     $this->_disableModule( $sModule );
00445 
00446                     //to avoid problems with unitest and only throw a exception if class does not exists MAFI
00447                     $oEx = oxNew( "oxSystemComponentException" );
00448                     $oEx->setMessage('EXCEPTION_SYSTEMCOMPONENT_CLASSNOTFOUND');
00449                     $oEx->setComponent($sModuleClass);
00450                     continue;
00451                 }
00452             }
00453             $sParent = $sModule;
00454             $sClassName = $sModule;
00455         }
00456 
00457         //returning the last module from the chain
00458         return $sClassName;
00459     }
00460 
00466     public function getShopId()
00467     {
00468             return 'oxbaseshop';
00469     }
00470 
00480     public function getModuleVar( $sModuleVarName )
00481     {
00482         //static cache
00483         if ( isset(self::$_aModuleVars[$sModuleVarName]) ) {
00484             return self::$_aModuleVars[$sModuleVarName];
00485         }
00486 
00487         //first try to get it from cache
00488         //we do not use any of our cache APIs, as we want to prevent any class dependencies here
00489         $aValue = $this->_getFromCache( $sModuleVarName );
00490 
00491         if ( is_null( $aValue ) ) {
00492             $aValue = $this->_getModuleVarFromDB($sModuleVarName);
00493             $this->_setToCache( $sModuleVarName, $aValue);
00494         }
00495 
00496         //static cache
00497         self::$_aModuleVars[$sModuleVarName] = $aValue;
00498 
00499         return $aValue;
00500     }
00501 
00510     public function setModuleVar( $sModuleVarName, $aValues )
00511     {
00512         if ( is_null( $aValues) ) {
00513             unset( self::$_aModuleVars );
00514         } else {
00515             self::$_aModuleVars[$sModuleVarName] = $aValues ;
00516         }
00517 
00518         $this->_setToCache($sModuleVarName, $aValues);
00519     }
00520 
00526     protected function _getConfKey()
00527     {
00528         $sFileName = dirname( __FILE__ ) . "/oxconfk.php";
00529         $sCfgFile = new oxConfigFile( $sFileName );
00530         return $sCfgFile->getVar("sConfigKey");
00531     }
00532 
00538     protected function _getShopUrlMap( )
00539     {
00540 
00541         //get from static cache
00542         if (isset( self::$_aModuleVars["urlMap"] )) {
00543             return self::$_aModuleVars["urlMap"];
00544         }
00545 
00546         //get from file cache
00547         $aMap = $this->_getFromCache("urlMap", false);
00548         if (!is_null($aMap)) {
00549             self::$_aModuleVars["urlMap"] = $aMap;
00550             return $aMap;
00551         }
00552 
00553         $aMap = array();
00554 
00555         $oDb = oxDb::getDb();
00556         $sConfKey = $this->_getConfKey();
00557 
00558         $sSelect = "SELECT oxshopid, oxvarname, DECODE( oxvarvalue , ".$oDb->quote($sConfKey)." ) as oxvarvalue ".
00559                    "FROM oxconfig WHERE oxvarname in ('aLanguageURLs','sMallShopURL','sMallSSLShopURL')";
00560 
00561         $oRs = $oDb->select($sSelect, false, false);
00562 
00563         if ( $oRs && $oRs->recordCount() > 0) {
00564             while ( !$oRs->EOF ) {
00565                 $iShp = (int) $oRs->fields[0];
00566                 $sVar = $oRs->fields[1];
00567                 $sURL = $oRs->fields[2];
00568 
00569                 if ($sVar == 'aLanguageURLs') {
00570                     $aUrls = unserialize($sURL);
00571                     if (is_array($aUrls) && count($aUrls)) {
00572                         $aUrls = array_filter($aUrls);
00573                         $aUrls = array_fill_keys($aUrls, $iShp);
00574                         $aMap  = array_merge($aMap, $aUrls);
00575                     }
00576                 } elseif ($sURL) {
00577                     $aMap[$sURL] = $iShp;
00578                 }
00579 
00580                 $oRs->moveNext();
00581             }
00582         }
00583 
00584         //save to cache
00585         $this->_setToCache("urlMap", $aMap, false);
00586         self::$_aModuleVars["urlMap"] = $aMap;
00587 
00588         return $aMap;
00589     }
00590 
00596     protected function _getCacheDir()
00597     {
00598         $sDir = oxRegistry::get("oxConfigFile")->getVar("sCompileDir");
00599         return $sDir;
00600     }
00601 
00610     protected function _getCacheFileName($sModuleVarName, $sShopId = null)
00611     {
00612         if (is_null($sShopId)) {
00613             $sShopId = $this->getShopId();
00614         }
00615 
00616         $sDir = $this->_getCacheDir();
00617         $sVar  = strtolower( basename ($sModuleVarName) );
00618         $sShop = strtolower( basename ($sShopId) );
00619 
00620         $sFileName = $sDir . "/" . self::CACHE_FILE_PREFIX . "." . $sShop . '.' . $sVar . ".txt";
00621 
00622         return $sFileName;
00623     }
00624 
00632     protected function _getModuleVarFromDB( $sModuleVarName )
00633     {
00634         $oDb = oxDb::getDb();
00635 
00636         $sShopId  = $this->getShopId();
00637         $sConfKey = $this->_getConfKey();
00638 
00639         $sSelect = "SELECT DECODE( oxvarvalue , ".$oDb->quote($sConfKey)." ) FROM oxconfig ".
00640                    "WHERE oxvarname = ".$oDb->quote( $sModuleVarName )." AND oxshopid = ".$oDb->quote($sShopId);
00641 
00642         $sModuleVarName = $oDb->getOne($sSelect, false, false);
00643 
00644         $sModuleVarName = unserialize( $sModuleVarName );
00645 
00646         return $sModuleVarName;
00647     }
00648 
00658     protected function _getFromCache( $sModuleVarName, $blSubshopSpecific = true )
00659     {
00660         $sShopId = null;
00661         if ( !$blSubshopSpecific ) {
00662             $sShopId = "all";
00663         }
00664 
00665         $sFileName = $this->_getCacheFileName($sModuleVarName, $sShopId);
00666         $sValue = null;
00667         if ( is_readable( $sFileName ) ) {
00668             $sValue = file_get_contents( $sFileName );
00669             $sValue = unserialize( $sValue );
00670             if ( $sValue === false ) {
00671                 $sValue = null;
00672             }
00673         }
00674 
00675         return $sValue ;
00676     }
00677 
00687     protected function _setToCache( $sVarName, $sValue,  $blSubshopSpecific = true )
00688     {
00689         $sShopId = null;
00690         if ( !$blSubshopSpecific ) {
00691             $sShopId = "all";
00692         }
00693 
00694         $sFileName = $this->_getCacheFileName($sVarName, $sShopId);
00695         file_put_contents( $sFileName, serialize($sValue), LOCK_EX );
00696     }
00697 
00698 }