oxutilsobject.php

Go to the documentation of this file.
00001 <?php
00002 
00006 class oxUtilsObject extends oxSuperCfg
00007 {
00013     protected $_aClassNameCache = array();
00014 
00020     protected static $_aLoadedArticles = array();
00021 
00027     protected static $_aInstanceCache = array();
00028 
00034     private static $_instance = null;
00035 
00041     public static function getInstance()
00042     {
00043         // disable caching for test modules
00044         if ( defined( 'OXID_PHP_UNIT' ) ) {
00045             self::$_instance = modInstances::getMod( __CLASS__ );
00046         }
00047 
00048         if ( !self::$_instance instanceof oxUtilsObject ) {
00049 
00050             // allow modules
00051             $oUtilsObject = new oxUtilsObject();
00052             self::$_instance = $oUtilsObject->oxNew( 'oxUtilsObject' );
00053 
00054             if ( defined( 'OXID_PHP_UNIT' ) ) {
00055                 modInstances::addMod( __CLASS__, self::$_instance);
00056             }
00057         }
00058         return self::$_instance;
00059     }
00060 
00071     public function oxNew( $sClassName )
00072     {
00073         $aArgs = func_get_args();
00074         array_shift( $aArgs );
00075         $iArgCnt = count( $aArgs );
00076         $blCacheObj = $iArgCnt < 2;
00077         $sClassName = strtolower( $sClassName );
00078 
00079         if ( !defined( 'OXID_PHP_UNIT' ) && $blCacheObj ) {
00080             $sCacheKey  = ( $iArgCnt )?$sClassName.md5( serialize( $aArgs ) ):$sClassName;
00081             if ( isset( self::$_aInstanceCache[$sCacheKey] ) ) {
00082                 return clone self::$_aInstanceCache[$sCacheKey];
00083             }
00084         }
00085 
00086         // performance
00087         if ( isset( $this->_aClassNameCache[$sClassName] ) ) {
00088             $sActionClassName = $this->_aClassNameCache[$sClassName];
00089         } else {
00090             $sActionClassName = $this->getClassName( $sClassName );
00091             //expect __autoload() (oxfunctions.php) to do its job when class_exists() is called
00092             if ( !class_exists( $sActionClassName ) ) {
00093                 $oEx = oxNew( "oxSystemComponentException" );
00094                 $oEx->setMessage('EXCEPTION_SYSTEMCOMPONENT_CLASSNOTFOUND');
00095                 $oEx->setComponent($sClassName);
00096                 $oEx->debugOut();
00097                 throw $oEx;
00098             }
00099             // performance
00100             $this->_aClassNameCache[$sClassName] = $sActionClassName;
00101         }
00102 
00103         $oActionObject = $this->_getObject( $sActionClassName, $iArgCnt, $aArgs );
00104         if ( $blCacheObj && $oActionObject instanceof oxBase ) {
00105             self::$_aInstanceCache[$sCacheKey] = clone $oActionObject;
00106         }
00107 
00108         return $oActionObject;
00109     }
00110 
00123     protected function _getObject( $sClassName, $iArgCnt, $aParams )
00124     {
00125         // dynamic creation (if parameter count < 4) gives more performance for regular objects
00126         switch( $iArgCnt ) {
00127             case 0:
00128                 $oObj = new $sClassName();
00129                 break;
00130             case 1:
00131                 $oObj = new $sClassName( $aParams[0] );
00132                 break;
00133             case 2:
00134                 $oObj = new $sClassName( $aParams[0], $aParams[1] );
00135                 break;
00136             case 3:
00137                 $oObj = new $sClassName( $aParams[0], $aParams[1], $aParams[2] );
00138                 break;
00139             default:
00140                 try {
00141                     // unlimited constructor arguments support
00142                     $oRo = new ReflectionClass( $sClassName );
00143                     $oObj = $oRo->newInstanceArgs( $aParams );
00144                 } catch ( ReflectionException $oRefExcp ) {
00145                     // something went wrong?
00146                     $oEx = oxNew( "oxSystemComponentException" );
00147                     $oEx->setMessage( $oRefExcp->getMessage() );
00148                     $oEx->setComponent( $sClassName );
00149                     $oEx->debugOut();
00150                     throw $oEx;
00151                 }
00152         }
00153 
00154         return $oObj;
00155     }
00156 
00165     public function oxNewArticle( $sOxID, $aProperties = array())
00166     {
00167         if ( $sOxID && isset( self::$_aLoadedArticles[$sOxID] ) ) {
00168             return self::$_aLoadedArticles[$sOxID];
00169         }
00170 
00171         $oActionObject = $this->oxNew( 'oxarticle' );
00172 
00173         // adding object prioperties
00174         foreach ( $aProperties as $sPropertyName => $sPropertyVal ) {
00175             $oActionObject->$sPropertyName = $sPropertyVal;
00176         }
00177 
00178         $oActionObject->load( $sOxID );
00179 
00180         self::$_aLoadedArticles[$sOxID] = $oActionObject;
00181         return $oActionObject;
00182     }
00183 
00191     public function resetInstanceCache($sClassName = null)
00192     {
00193         if ($sClassName && isset(self::$_aInstanceCache[$sClassName])) {
00194             unset(self::$_aInstanceCache[$sClassName]);
00195             return;
00196         }
00197 
00198         //looping due to possible memory "leak".
00199         if (is_array(self::$_aInstanceCache)) {
00200             foreach (self::$_aInstanceCache as $sKey => $oInstance) {
00201                 unset(self::$_aInstanceCache[$sKey]);
00202             }
00203         }
00204 
00205         self::$_aInstanceCache = array();
00206     }
00207 
00213     public function generateUId()
00214     {
00215         return substr( $this->getSession()->getId(), 0, 3 ) . substr( md5( uniqid( '', true ).'|'.microtime() ), 0, 29 );
00216     }
00217 
00218 
00219 
00227     public function getClassName( $sClassName )
00228     {
00229         $aModules = $this->getConfig()->getConfigParam( 'aModules' );
00230         $aClassChain = array();
00231 
00232 
00233         if (is_array( $aModules )) {
00234 
00235             $aModules = array_change_key_case( $aModules );
00236 
00237             if ( array_key_exists( $sClassName, $aModules ) ) {
00238                 //multiple inheritance implementation
00239                 //in case we have multiple modules:
00240                 //like oxoutput => sub/suboutput1&sub/suboutput2&sub/suboutput3
00241                 $aClassChain = explode( "&", $aModules[$sClassName] );
00242                 $aClassChain = $this->_getActiveModuleChain($aClassChain);
00243             }
00244 
00245             if (count($aClassChain)) {
00246                 $sParent = $sClassName;
00247 
00248                 //security: just preventing string termination
00249                 $sParent = str_replace(chr(0), '', $sParent);
00250 
00251                 //building middle classes if needed
00252                 $sClassName = $this->_makeSafeModuleClassParents( $aClassChain, $sParent );
00253             }
00254         }
00255 
00256         // check if there is a path, if yes, remove it
00257         $sClassName = basename( $sClassName );
00258 
00259         return $sClassName;
00260     }
00261 
00272     public function isModuleActive( $sClassName, $sModuleName )
00273     {
00274         $aModules = $this->getConfig()->getConfigParam( 'aModules' );
00275         if ( is_array( $aModules ) && array_key_exists( $sClassName, $aModules ) ) {
00276             $aClassChain = explode( "&", $aModules[$sClassName] );
00277 
00278             // Exclude disabled modules from chain unfortunatelly can not use oxmodule::getActiveModuleInfo()
00279             // If you call onNew in oxNew, you will get infinit recursion...
00280             $aClassChain = $this->_getActiveModuleChain($aClassChain);
00281 
00282             foreach ($aClassChain as $sModule) {
00283                 if ( basename($sModule) == $sModuleName ) {
00284                     return true;
00285                 }
00286             }
00287         }
00288         return false;
00289     }
00290 
00298     protected function _getActiveModuleChain( $aClassChain )
00299     {
00300         $myConfig = $this->getConfig();
00301 
00302         $aDisabledModules = $myConfig->getConfigParam( 'aDisabledModules' );
00303         $aModulePaths     = $myConfig->getConfigParam( 'aModulePaths' );
00304         if (is_array( $aDisabledModules ) && count($aDisabledModules) > 0) {
00305             foreach ($aDisabledModules as $sId) {
00306                 $sPath = $aModulePaths[$sId];
00307                 if (!isset($sPath)) {
00308                     $sPath = $sId;
00309                 }
00310                 foreach ( $aClassChain as $sKey => $sModuleClass ) {
00311                     if (strpos($sModuleClass, $sPath."/") === 0 ) {
00312                         unset($aClassChain[$sKey]);
00313                     }
00314                 }
00315             }
00316         }
00317 
00318         return $aClassChain;
00319     }
00320 
00328     protected function _disableModule( $sModule )
00329     {
00330         $oModule = oxNew("oxModule");
00331         $sModuleId = $oModule->getIdByPath($sModule);
00332         $oModule->deactivate($sModuleId);
00333     }
00334 
00345     private function _makeSafeModuleClassParents( $aClassChain, $sBaseModule )
00346     {
00347         $myConfig = $this->getConfig();
00348         $sParent = $sBaseModule;
00349         $sClassName = $sBaseModule;
00350 
00351         //building middle classes if needed
00352         foreach ($aClassChain as $sModule) {
00353             //creating middle classes
00354             //e.g. class suboutput1_parent extends oxoutput {}
00355             //     class suboutput2_parent extends suboutput1 {}
00356             //$sModuleClass = $this->getClassName($sModule);
00357 
00358             //security: just preventing string termination
00359             $sModule = str_replace(chr(0), '', $sModule);
00360 
00361             //get parent and module class names from sub/suboutput2
00362             $sModuleClass = basename($sModule);
00363 
00364             if ( !class_exists( $sModuleClass, false ) ) {
00365                 $sParentClass = basename($sParent);
00366                 //P
00367                 //$sInitClass = "class ".$sModuleClass."_parent extends $sParentClass { function ".$sModuleClass."_parent(){ return ".$sParentClass."::".$sParentClass."();} }";
00368                 $sInitClass = "class ".$sModuleClass."_parent extends $sParentClass {}";
00369 
00370                 //initializing middle class
00371                 if (!class_exists($sModuleClass."_parent", false)) {
00372                     eval($sInitClass);
00373                 }
00374                 $sParentPath = $myConfig->getConfigParam( 'sShopDir' )."/modules/".$sModule.".php";
00375 
00376                 //including original file
00377                 if ( file_exists( $sParentPath ) ) {
00378                     include_once $sParentPath;
00379                 } elseif ( !class_exists( $sModuleClass ) ) {
00380                     // disable module if extendet class is not found
00381                     $this->_disableModule( $sModule );
00382                     //to avoid problems with unitest and only throw a exception if class does not exists MAFI
00383                     $oEx = oxNew( "oxSystemComponentException" );
00384                     $oEx->setMessage('EXCEPTION_SYSTEMCOMPONENT_CLASSNOTFOUND');
00385                     $oEx->setComponent($sModule);
00386                     continue;
00387                 }
00388             }
00389             $sParent = $sModule;
00390             $sClassName = $sModule;
00391         }
00392 
00393         //returning the last module from the chain
00394         return $sClassName;
00395     }
00396 }