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 
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         $aDisabledModules = $this->getModuleVar( 'aDisabledModules' );
00344         $aModulePaths     = $this->getModuleVar( 'aModulePaths' );
00345 
00346         if (is_array( $aDisabledModules ) && count($aDisabledModules) > 0) {
00347             foreach ($aDisabledModules as $sId) {
00348                 $sPath = $aModulePaths[$sId];
00349                 if (!isset($sPath)) {
00350                     $sPath = $sId;
00351                 }
00352                 foreach ( $aClassChain as $sKey => $sModuleClass ) {
00353                     if ( strpos($sModuleClass, $sPath."/" ) === 0 ) {
00354                         unset( $aClassChain[$sKey] );
00355                     }
00356                     // If module consists of one file without own dir (getting module.php as id, instead of module)
00357                     elseif ( strpos( $sPath, "."  ) ) {
00358                         if ( strpos( $sPath, strtolower( $sModuleClass ) ) === 0 ) {
00359                             unset( $aClassChain[$sKey] );
00360                         }
00361                     }
00362                 }
00363             }
00364         }
00365 
00366         return $aClassChain;
00367     }
00368 
00376     protected function _disableModule( $sModule )
00377     {
00381         $oModule = oxNew("oxModule");
00382         $sModuleId = $oModule->getIdByPath($sModule);
00383         $oModule->deactivate($sModuleId);
00384     }
00385 
00396     protected function _makeSafeModuleClassParents( $aClassChain, $sBaseModule )
00397     {
00398         $sParent = $sBaseModule;
00399         $sClassName = $sBaseModule;
00400 
00401         //building middle classes if needed
00402         foreach ($aClassChain as $sModule) {
00403             //creating middle classes
00404             //e.g. class suboutput1_parent extends oxoutput {}
00405             //     class suboutput2_parent extends suboutput1 {}
00406             //$sModuleClass = $this->getClassName($sModule);
00407 
00408             //security: just preventing string termination
00409             $sModule = str_replace(chr(0), '', $sModule);
00410 
00411             //get parent and module class names from sub/suboutput2
00412             $sModuleClass = basename($sModule);
00413 
00414             if ( !class_exists( $sModuleClass, false ) ) {
00415                 $sParentClass       = basename($sParent);
00416                 $sModuleParentClass = $sModuleClass."_parent";
00417 
00418                 //initializing middle class
00419                 if (!class_exists($sModuleParentClass, false)) {
00420                     // If possible using alias instead if eval (since php 5.3).
00421                     if (function_exists('class_alias')) {
00422                         class_alias($sParentClass, $sModuleParentClass);
00423                     } else {
00424                         eval("abstract class $sModuleParentClass extends $sParentClass {}");
00425                     }
00426                 }
00427                 $sParentPath = oxRegistry::get( "oxConfigFile" )->getVar( "sShopDir" ) . "/modules/".$sModule.".php";
00428 
00429                 //including original file
00430                 if ( file_exists( $sParentPath ) ) {
00431                     include_once $sParentPath;
00432                 } elseif ( !class_exists( $sModuleClass ) ) {
00433                     // special case is when oxconfig class is extended: we cant call "_disableModule" as it requires valid config object
00434                     // but we can't create it as module class extending it does not exist. So we will use orginal oxConfig object instead.
00435                     if ( $sParentClass == "oxconfig" ) {
00436                         $oConfig = $this->_getObject( "oxconfig", 0, null );
00437                         oxRegistry::set( "oxconfig", $oConfig );
00438                     }
00439 
00440                     // disable module if extended class is not found
00441                     $this->_disableModule( $sModule );
00442 
00443                     //to avoid problems with unitest and only throw a exception if class does not exists MAFI
00444                     $oEx = oxNew( "oxSystemComponentException" );
00445                     $oEx->setMessage('EXCEPTION_SYSTEMCOMPONENT_CLASSNOTFOUND');
00446                     $oEx->setComponent($sModuleClass);
00447                     continue;
00448                 }
00449             }
00450             $sParent = $sModule;
00451             $sClassName = $sModule;
00452         }
00453 
00454         //returning the last module from the chain
00455         return $sClassName;
00456     }
00457 
00463     public function getShopId()
00464     {
00465             return 'oxbaseshop';
00466     }
00467 
00477     public function getModuleVar( $sModuleVarName )
00478     {
00479         //static cache
00480         if ( isset(self::$_aModuleVars[$sModuleVarName]) ) {
00481             return self::$_aModuleVars[$sModuleVarName];
00482         }
00483 
00484         //first try to get it from cache
00485         //we do not use any of our cache APIs, as we want to prevent any class dependencies here
00486         $aValue = $this->_getFromCache( $sModuleVarName );
00487 
00488         if ( is_null( $aValue ) ) {
00489             $aValue = $this->_getModuleVarFromDB($sModuleVarName);
00490             $this->_setToCache( $sModuleVarName, $aValue);
00491         }
00492 
00493         //static cache
00494         self::$_aModuleVars[$sModuleVarName] = $aValue;
00495 
00496         return $aValue;
00497     }
00498 
00507     public function setModuleVar( $sModuleVarName, $aValues )
00508     {
00509         if ( is_null( $aValues) ) {
00510             unset( self::$_aModuleVars );
00511         } else {
00512             self::$_aModuleVars[$sModuleVarName] = $aValues ;
00513         }
00514 
00515         $this->_setToCache($sModuleVarName, $aValues);
00516     }
00517 
00523     protected function _getConfKey()
00524     {
00525         $sFileName = dirname( __FILE__ ) . "/oxconfk.php";
00526         $sCfgFile = new oxConfigFile( $sFileName );
00527         return $sCfgFile->getVar("sConfigKey");
00528     }
00529 
00535     protected function _getShopUrlMap( )
00536     {
00537 
00538         //get from static cache
00539         if (isset( self::$_aModuleVars["urlMap"] )) {
00540             return self::$_aModuleVars["urlMap"];
00541         }
00542 
00543         //get from file cache
00544         $aMap = $this->_getFromCache("urlMap", false);
00545         if (!is_null($aMap)) {
00546             self::$_aModuleVars["urlMap"] = $aMap;
00547             return $aMap;
00548         }
00549 
00550         $aMap = array();
00551 
00552         $oDb = oxDb::getDb();
00553         $sConfKey = $this->_getConfKey();
00554 
00555         $sSelect = "SELECT oxshopid, oxvarname, DECODE( oxvarvalue , ".$oDb->quote($sConfKey)." ) as oxvarvalue ".
00556                    "FROM oxconfig WHERE oxvarname in ('aLanguageURLs','sMallShopURL','sMallSSLShopURL')";
00557 
00558         $oRs = $oDb->select($sSelect, false, false);
00559 
00560         if ( $oRs && $oRs->recordCount() > 0) {
00561             while ( !$oRs->EOF ) {
00562                 $iShp = (int) $oRs->fields[0];
00563                 $sVar = $oRs->fields[1];
00564                 $sURL = $oRs->fields[2];
00565 
00566                 if ($sVar == 'aLanguageURLs') {
00567                     $aUrls = unserialize($sURL);
00568                     if (is_array($aUrls) && count($aUrls)) {
00569                         $aUrls = array_filter($aUrls);
00570                         $aUrls = array_fill_keys($aUrls, $iShp);
00571                         $aMap  = array_merge($aMap, $aUrls);
00572                     }
00573                 } elseif ($sURL) {
00574                     $aMap[$sURL] = $iShp;
00575                 }
00576 
00577                 $oRs->moveNext();
00578             }
00579         }
00580 
00581         //save to cache
00582         $this->_setToCache("urlMap", $aMap, false);
00583         self::$_aModuleVars["urlMap"] = $aMap;
00584 
00585         return $aMap;
00586     }
00587 
00593     protected function _getCacheDir()
00594     {
00595         $sDir = oxRegistry::get("oxConfigFile")->getVar("sCompileDir");
00596         return $sDir;
00597     }
00598 
00607     protected function _getCacheFileName($sModuleVarName, $sShopId = null)
00608     {
00609         if (is_null($sShopId)) {
00610             $sShopId = $this->getShopId();
00611         }
00612 
00613         $sDir = $this->_getCacheDir();
00614         $sVar  = strtolower( basename ($sModuleVarName) );
00615         $sShop = strtolower( basename ($sShopId) );
00616 
00617         $sFileName = $sDir . "/" . self::CACHE_FILE_PREFIX . "." . $sShop . '.' . $sVar . ".txt";
00618 
00619         return $sFileName;
00620     }
00621 
00629     protected function _getModuleVarFromDB( $sModuleVarName )
00630     {
00631         $oDb = oxDb::getDb();
00632 
00633         $sShopId  = $this->getShopId();
00634         $sConfKey = $this->_getConfKey();
00635 
00636         $sSelect = "SELECT DECODE( oxvarvalue , ".$oDb->quote($sConfKey)." ) FROM oxconfig ".
00637                    "WHERE oxvarname = ".$oDb->quote( $sModuleVarName )." AND oxshopid = ".$oDb->quote($sShopId);
00638 
00639         $sModuleVarName = $oDb->getOne($sSelect, false, false);
00640 
00641         $sModuleVarName = unserialize( $sModuleVarName );
00642 
00643         return $sModuleVarName;
00644     }
00645 
00655     protected function _getFromCache( $sModuleVarName, $blSubshopSpecific = true )
00656     {
00657         $sShopId = null;
00658         if ( !$blSubshopSpecific ) {
00659             $sShopId = "all";
00660         }
00661 
00662         $sFileName = $this->_getCacheFileName($sModuleVarName, $sShopId);
00663         $sValue = null;
00664         if ( is_readable( $sFileName ) ) {
00665             $sValue = file_get_contents( $sFileName );
00666             $sValue = unserialize( $sValue );
00667         }
00668 
00669         return $sValue ;
00670     }
00671 
00681     protected function _setToCache( $sVarName, $sValue,  $blSubshopSpecific = true )
00682     {
00683         $sShopId = null;
00684         if ( !$blSubshopSpecific ) {
00685             $sShopId = "all";
00686         }
00687 
00688         $sFileName = $this->_getCacheFileName($sVarName, $sShopId);
00689         file_put_contents( $sFileName, serialize($sValue) );
00690     }
00691 
00692 }