oxbase.php

Go to the documentation of this file.
00001 <?php
00002 
00006 DEFINE('ACTION_NA', 0);
00007 DEFINE('ACTION_DELETE', 1);
00008 DEFINE('ACTION_INSERT', 2);
00009 DEFINE('ACTION_UPDATE', 3);
00010 DEFINE('ACTION_UPDATE_STOCK', 4);
00011 
00016 class oxBase extends oxSuperCfg
00017 {
00022     protected $_sOXID = null;
00023 
00028     protected $_iShopId = null;
00029 
00035     protected $_blIsSimplyClonable = true;
00036 
00044     protected $_aErrors = array();
00045 
00050     protected $_sClassName = 'oxbase';
00051 
00057     protected $_sCoreTable = null;
00058 
00066     protected $_sCoreTbl = null;
00067 
00072     protected $_sViewTable  = null;
00073 
00074 
00080     protected $_aFieldNames = array('oxid' => 0);
00081 
00086     protected $_blIsNewCache = false;
00087 
00093     protected $_sCacheKey = null;
00094 
00100     protected $_blUseLazyLoading = false;
00101 
00107     protected $_aSkipSaveFields = array();
00108 
00113     protected $_sExistKey = "oxid";
00114 
00121     protected $_blIsDerived = null;
00122 
00132     protected static $_blDisableFieldCaching = array();
00133 
00139     protected $_blIsSeoObject = false;
00140 
00146     protected $_blReadOnly = false;
00147 
00153     protected $_blIsInList = false;
00154 
00160     protected $_isLoaded = false;
00161 
00167     protected $_aInnerLazyCache = null;
00168 
00174     protected $_blEmployMultilanguage = false;
00175 
00179     public function __construct()
00180     {
00181         // set active shop
00182         $myConfig = $this->getConfig();
00183         $this->_sCacheKey = $this->getViewName();
00184         if ( $this->_blUseLazyLoading ) {
00185             $this->_sCacheKey .= $myConfig->getActiveView()->getClassName();
00186         } else {
00187             $this->_sCacheKey .= "allviews";
00188         }
00189 
00190         //do not cache for admin?
00191         if ( $this->isAdmin() ) {
00192             $this->_sCacheKey = null;
00193         }
00194 
00195         $this->setShopId( $myConfig->getShopId() );
00196     }
00197 
00206     public function __set( $sName, $sValue )
00207     {
00208         $this->$sName = $sValue;
00209         if ( $this->_blUseLazyLoading && strpos( $sName, $this->_sCoreTable . "__" ) === 0 ) {
00210             $sFieldName = str_replace( $this->_sCoreTable . "__", '', $sName );
00211             if ( $sFieldName != 'oxnid' && ( !isset( $this->_aFieldNames[$sFieldName] ) || !$this->_aFieldNames[$sFieldName] ) ) {
00212                 $aAllFields = $this->_getAllFields(true);
00213                 if ( isset( $aAllFields[strtolower($sFieldName)] ) ) {
00214                     $iFieldStatus = $this->_getFieldStatus( $sFieldName );
00215                     $this->_addField( $sFieldName, $iFieldStatus );
00216                 }
00217             }
00218         }
00219     }
00220 
00228     public function __get( $sName )
00229     {
00230         switch ( $sName ) {
00231             case 'blIsDerived':
00232                 return $this->isDerived();
00233                 break;
00234             case 'sOXID':
00235                 return $this->getId();
00236                 break;
00237             case 'blReadOnly':
00238                 return $this->isReadOnly();
00239                 break;
00240         }
00241 
00242         // implementing lazy loading fields
00243         // This part of the code is slow and normally is called before field cache is built.
00244         // Make sure it is not called after first page is loaded and cache data is fully built.
00245         if ( $this->_blUseLazyLoading && stripos( $sName, $this->_sCoreTable . "__" ) === 0 ) {
00246 
00247             if ( $this->getId() ) {
00248 
00249                 //lazy load it
00250                 $sFieldName      = str_replace( $this->_sCoreTable . "__", '', $sName );
00251                 $sCacheFieldName = strtoupper( $sFieldName );
00252 
00253                 $iFieldStatus = $this->_getFieldStatus( $sFieldName );
00254                 $sViewName    = $this->getViewName();
00255                 $sId = $this->getId();
00256 
00257                 try {
00258                     if ( $this->_aInnerLazyCache === null ) {
00259 
00260                         $oDb = oxDb::getDb( oxDb::FETCH_MODE_ASSOC );
00261                         $sQ = "SELECT * FROM " . $sViewName . " WHERE `oxid` = " . $oDb->quote( $sId );
00262                         $rs = $oDb->select( $sQ );
00263                         if ( $rs && $rs->RecordCount() ) {
00264                             $this->_aInnerLazyCache = array_change_key_case( $rs->fields, CASE_UPPER );
00265                             if ( array_key_exists( $sCacheFieldName, $this->_aInnerLazyCache ) ) {
00266                                 $sFieldValue = $this->_aInnerLazyCache[$sCacheFieldName];
00267                             } else {
00268                                 return null;
00269                             }
00270                         } else {
00271                             return null;
00272                         }
00273                     } elseif ( array_key_exists( $sCacheFieldName, $this->_aInnerLazyCache ) ) {
00274                         $sFieldValue = $this->_aInnerLazyCache[$sCacheFieldName];
00275                     } else {
00276                         return null;
00277                     }
00278 
00279                     $this->_addField( $sFieldName, $iFieldStatus );
00280                     $this->_setFieldData( $sFieldName, $sFieldValue );
00281 
00282                     //save names to cache for next loading
00283                     if ($this->_sCacheKey) {
00284                         $myUtils = oxUtils::getInstance();
00285                         $sCacheKey = 'fieldnames_' . $this->_sCoreTable . "_" . $this->_sCacheKey;
00286                         $aFieldNames = $myUtils->fromFileCache( $sCacheKey );
00287                         $aFieldNames[$sFieldName] = $iFieldStatus;
00288                         $myUtils->toFileCache( $sCacheKey, $aFieldNames );
00289                     }
00290                 } catch ( Exception $e ) {
00291                     return null;
00292                 }
00293 
00294                 //do not use field cache for this page
00295                 //as if we use it for lists then objects are loaded empty instead of lazy loading.
00296                 self::$_blDisableFieldCaching[get_class( $this )] = true;
00297             }
00298 
00299             oxUtilsObject::getInstance()->resetInstanceCache(get_class($this));
00300         }
00301 
00302         //returns oxStdClass implementing __toString() method due to uknown scenario where this var should be used.
00303         if (!isset( $this->$sName ) ) {
00304             $this->$sName = null;
00305         }
00306 
00307         return $this->$sName;
00308     }
00309 
00317     public function __isset($mVar)
00318     {
00319         return isset($this->$mVar);
00320     }
00321 
00327     public function __clone()
00328     {
00329         if (!$this->_blIsSimplyClonable) {
00330             foreach ( $this->_aFieldNames as $sField => $sVal ) {
00331                 $sLongName = $this->_getFieldLongName( $sField );
00332                 if ( is_object($this->$sLongName)) {
00333                     $this->$sLongName = clone $this->$sLongName;
00334                 }
00335             }
00336         }
00337     }
00338 
00346     public function oxClone($oObject)
00347     {
00348         $aClasVars = get_object_vars( $oObject);
00349         while (list($name, $value) = each($aClasVars)) {
00350             if ( is_object( $oObject->$name ) ) {
00351                 $this->$name = clone $oObject->$name;
00352             } else {
00353                 $this->$name = $oObject->$name;
00354             }
00355         }
00356     }
00357 
00366     public function init( $sTableName = null, $blForceAllFields = false)
00367     {
00368 
00369         if ( !$sTableName ) {
00370             $sTableName = $this->_sCoreTable;
00371         } else {
00372             $this->_sCoreTable = $sTableName;
00373         }
00374 
00375         // compatibility due to parameter deprecation
00376         $this->_sCoreTbl = $sTableName;
00377 
00378         // reset view table
00379         $this->_sViewTable = false;
00380 
00381         if ( count( $this->_aFieldNames ) <= 1 ) {
00382             $this->_initDataStructure( $blForceAllFields );
00383         }
00384     }
00385 
00393     public function assign( $dbRecord )
00394     {
00395         if ( !is_array( $dbRecord ) ) {
00396             return;
00397         }
00398 
00399 
00400         reset($dbRecord );
00401         while ( list( $sName, $sValue ) = each( $dbRecord ) ) {
00402 
00403             // patch for IIS
00404             //TODO: test it on IIS do we still need it
00405             //if( is_array($value) && count( $value) == 1)
00406             //    $value = current( $value);
00407 
00408             $this->_setFieldData( $sName, $sValue );
00409         }
00410 
00411         $sOxidField = $this->_getFieldLongName( 'oxid' );
00412         $this->_sOXID = $this->$sOxidField->value;
00413 
00414     }
00415 
00421     public function getClassName()
00422     {
00423         return $this->_sClassName;
00424     }
00425 
00431     public function getCoreTableName()
00432     {
00433         return $this->_sCoreTable;
00434     }
00435 
00441     public function getId()
00442     {
00443         return $this->_sOXID;
00444     }
00445 
00453     public function setId($sOXID = null)
00454     {
00455         if ( $sOXID ) {
00456             $this->_sOXID = $sOXID;
00457         } else {
00458             $this->_sOXID = oxUtilsObject::getInstance()->generateUID();
00459         }
00460 
00461         $sIdVarName = $this->_sCoreTable . "__oxid";
00462         $this->$sIdVarName = new oxField($this->_sOXID, oxField::T_RAW);
00463 
00464         return $this->_sOXID;
00465     }
00466 
00474     public function setShopId($iShopId)
00475     {
00476         $this->_iShopId = $iShopId;
00477     }
00478 
00484     public function getShopId()
00485     {
00486         return $this->_iShopId;
00487     }
00488 
00496     public function getViewName($blForceCoreTableUsage = null)
00497     {
00498         if (!$this->_sViewTable || ($blForceCoreTableUsage !== null)) {
00499             if ( $blForceCoreTableUsage === true ) {
00500                 return $this->_sCoreTable;
00501             }
00502 
00503 
00504             if ( ( $blForceCoreTableUsage !== null ) && $blForceCoreTableUsage ) {
00505                 $iShopId = -1;
00506             } else {
00507                 $iShopId = oxConfig::getInstance()->getShopId();
00508             }
00509 
00510 
00511             $sViewName = getViewName( $this->_sCoreTable, $this->_blEmployMultilanguage == false ? -1 : $this->getLanguage(), $iShopId );
00512             if ( $blForceCoreTableUsage !== null ) {
00513                 return $sViewName;
00514             }
00515             $this->_sViewTable = $sViewName;
00516         }
00517         return $this->_sViewTable;
00518     }
00519 
00528     public function modifyCacheKey( $sCacheKey, $blOverride = false )
00529     {
00530         if ( $blOverride ) {
00531             $this->_sCacheKey = $sCacheKey;
00532         } else {
00533             $this->_sCacheKey .= $sCacheKey;
00534         }
00535     }
00536 
00542     public function disableLazyLoading()
00543     {
00544         $this->_blUseLazyLoading = false;
00545         $this->_initDataStructure(true);
00546     }
00547 
00548 
00554     public function isDerived()
00555     {
00556 
00557         return $this->_blIsDerived;
00558     }
00559 
00567     public function setIsDerived($blVal)
00568     {
00569         $this->_blIsDerived = $blVal;
00570     }
00571 
00578     public function isMultilang()
00579     {
00580         return false;
00581     }
00582 
00592     public function load( $sOXID)
00593     {
00594         /*
00595         if( !isset($oxID)){
00596             $oEx = oxNew('oxObjectException','core');
00597             $oEx->setMessage('EXCEPTION_OBJECT_OXIDNOTSET');
00598             $oEx->setObject($this);
00599             throw $oEx;
00600         }*/
00601 
00602         $blExistingOldForceCoreTable = $this->_blForceCoreTableUsage;
00603 
00604         $this->_blForceCoreTableUsage = true;
00605 
00606         //getting at least one field before lazy loading the object
00607         $this->_addField('oxid', 0);
00608         $sSelect = $this->buildSelectString( array( $this->getViewName().".oxid" => $sOXID));
00609 
00610         $this->_isLoaded = $this->assignRecord( $sSelect );
00611         $this->_blForceCoreTableUsage = $blExistingOldForceCoreTable;
00612 
00613         return $this->_isLoaded;
00614     }
00615 
00621     public function isLoaded()
00622     {
00623         return $this->_isLoaded;
00624     }
00625 
00633     public function buildSelectString( $aWhere = null)
00634     {
00635         $oDB = oxDb::getDb();
00636         $myUtils = oxUtils::getInstance();
00637 
00638         $sGet = $this->getSelectFields();
00639         $sSelect = "select $sGet from " . $this->getViewName() . " where 1 ";
00640 
00641         if ( $aWhere) {
00642             reset($aWhere);
00643             while (list($name, $value) = each($aWhere)) {
00644                 $sSelect .=  " and " . $name.' = '.$oDB->quote($value);
00645             }
00646         }
00647 
00648         // add active shop
00649 
00650         return $sSelect;
00651     }
00652 
00660     public function assignRecord( $sSelect )
00661     {
00662         $blRet = false;
00663 
00664         $rs = oxDb::getDb( oxDb::FETCH_MODE_ASSOC )->select( $sSelect );
00665 
00666         if ($rs != false && $rs->recordCount() > 0) {
00667             $blRet = true;
00668             $this->assign( $rs->fields);
00669         }
00670 
00671         return $blRet;
00672     }
00673 
00681     public function getFieldData( $sFieldName )
00682     {
00683         $sLongFieldName = $this->_getFieldLongName( $sFieldName );
00684             return $this->$sLongFieldName->value;
00685     }
00686 
00694     public function getSelectFields( $blForceCoreTableUsage = null )
00695     {
00696         $aSelectFields = array();
00697 
00698         $sViewName = $this->getViewName( $blForceCoreTableUsage );
00699 
00700         foreach ( $this->_aFieldNames as $sKey => $sField ) {
00701             $aSelectFields[] = $sViewName . '.' . $sKey;
00702         }
00703 
00704         $sSelectFields = join( ", ", $aSelectFields );
00705         return $sSelectFields;
00706     }
00707 
00715     public function delete( $sOXID = null)
00716     {
00717         if ( !$sOXID ) {
00718             $sOXID = $this->getId();
00719 
00720             //do not allow derived deletion
00721             if ( !$this->allowDerivedDelete() ) {
00722                 return false;
00723             }
00724         }
00725 
00726         if ( !$sOXID ) {
00727             return false;
00728         }
00729 
00730 
00731         $oDB = oxDb::getDb( oxDb::FETCH_MODE_ASSOC );
00732         $sDelete = "delete from $this->_sCoreTable where oxid = ".$oDB->quote( $sOXID );
00733         $rs = $oDB->execute( $sDelete );
00734         if ( $blDelete = ( bool ) $oDB->affected_Rows() ) {
00735             $this->onChange(ACTION_DELETE, $sOXID);
00736         }
00737 
00738         return $blDelete;
00739     }
00740 
00741 
00747     public function save()
00748     {
00749         if ( !is_array( $this->_aFieldNames ) ) {
00750             return false;
00751         }
00752 
00753         $blRet = false;
00754 
00755         // #739A - should be executed here because of date/time formatting feature
00756         if ( $this->isAdmin() && !$this->getConfig()->getConfigParam( 'blSkipFormatConversion' ) ) {
00757             foreach ($this->_aFieldNames as $sName => $sVal) {
00758                 $sLongName = $this->_getFieldLongName($sName);
00759                 if ( isset($this->$sLongName->fldtype) && $this->$sLongName->fldtype == "datetime" ) {
00760                     oxDb::getInstance()->convertDBDateTime( $this->$sLongName, true );
00761                 } elseif ( isset($this->$sLongName->fldtype) && $this->$sLongName->fldtype == "timestamp" ) {
00762                     oxDb::getInstance()->convertDBTimestamp( $this->$sLongName, true);
00763                 } elseif ( isset($this->$sLongName->fldtype) && $this->$sLongName->fldtype == "date" ) {
00764                     oxDb::getInstance()->convertDBDate( $this->$sLongName, true);
00765                 }
00766             }
00767         }
00768         if ( $this->exists() ) {
00769             //do not allow derived update
00770             if ( !$this->allowDerivedUpdate() ) {
00771                 return false;
00772             }
00773 
00774             $blRet = $this->_update();
00775             $sAction = ACTION_UPDATE;
00776         } else {
00777             $blRet = $this->_insert();
00778             $sAction = ACTION_INSERT;
00779         }
00780 
00781         $this->onChange($sAction);
00782 
00783         if ( $blRet ) {
00784             return $this->getId();
00785         } else {
00786             return false;
00787         }
00788     }
00789 
00795     public function allowDerivedUpdate()
00796     {
00797         return !$this->isDerived();
00798     }
00799 
00805     public function allowDerivedDelete()
00806     {
00807         return !$this->isDerived();
00808     }
00809 
00817     public function exists( $sOXID = null)
00818     {
00819         if ( !$sOXID ) {
00820             $sOXID = $this->getId();
00821         }
00822         if ( !$sOXID ) {
00823             return false;
00824         }
00825 
00826         $sViewName = $this->getCoreTableName();
00827         $oDb = oxDb::getDb( oxDb::FETCH_MODE_ASSOC );
00828         $sSelect= "select {$this->_sExistKey} from {$sViewName} where {$this->_sExistKey} = ".$oDb->quote( $sOXID );
00829 
00830         return ( bool ) $oDb->getOne( $sSelect, false, false );
00831     }
00832 
00840     public function getSqlActiveSnippet( $blForceCoreTable = null )
00841     {
00842         $sQ = '';
00843         $sTable = $this->getViewName($blForceCoreTable);
00844 
00845         // has 'active' field ?
00846         if ( isset( $this->_aFieldNames['oxactive'] ) ) {
00847             $sQ = " $sTable.oxactive = 1 ";
00848         }
00849 
00850         // has 'activefrom'/'activeto' fields ?
00851         if ( isset( $this->_aFieldNames['oxactivefrom'] ) && isset( $this->_aFieldNames['oxactiveto'] ) ) {
00852 
00853             $sDate = date( 'Y-m-d H:i:s', oxUtilsDate::getInstance()->getTime() );
00854 
00855             $sQ = $sQ?" $sQ or ":'';
00856             $sQ = " ( $sQ ( $sTable.oxactivefrom < '$sDate' and $sTable.oxactiveto > '$sDate' ) ) ";
00857         }
00858 
00859         return $sQ;
00860     }
00861 
00870     public function validate()
00871     {
00872         $this->_aErrors = array();
00873         foreach ($this->_aFieldNames as $fName => $iVal) {
00874 
00875             $fName = $this->_getFieldLongName($fName);
00876 
00877             if ( method_exists ( $this, "validate_$fName")) {
00878                 $validatorMethod = "validate_$fName";
00879                 if ( $error = $this->$validatorMethod()) {
00880                     $this->_aErrors[$fName] = $error;
00881                 }
00882             }
00883         }
00884         return !$this->hasErrors();
00885     }
00886 
00895     public function beforeUpdate( $sOXID = null )
00896     {
00897     }
00898 
00909     public function onChange( $iAction = null, $sOXID = null)
00910     {
00911     }
00912 
00913 
00921     public function hasErrors()
00922     {
00923         return count($this->_aErrors) > 0;
00924     }
00925 
00933     public function getErrors()
00934     {
00935         return $this->_aErrors;
00936     }
00937 
00947     public function getError( $sField)
00948     {
00949         if (isset($this->_aErrors[$sField])) {
00950             return $this->_aErrors[$sField];
00951         }
00952 
00953         //T2007-10-19
00954         //return array();
00955         return null;
00956     }
00957 
00967     public function getHtmlError( $sField)
00968     {
00969         if ( $error = $this->getError($sField) ) {
00970             return $error;
00971         }
00972     }
00973 
00979     public function setInList()
00980     {
00981         $this->_blIsInList = true;
00982     }
00983 
00989     protected function _isInList()
00990     {
00991         return $this->_blIsInList;
00992     }
00993 
01002     protected function _getObjectViewName( $sTable, $sShopID = null)
01003     {
01004         return getViewName( $sTable, -1, $sShopID);
01005     }
01006 
01007 
01018     protected function _getTableFields($sTable, $blReturnSimple = false)
01019     {
01020         $myUtils = oxUtils::getInstance();
01021 
01022         $sCacheKey   = $sTable . "_allfields_" . $blReturnSimple;
01023         $aMetaFields = $myUtils->fromFileCache( $sCacheKey );
01024 
01025         if ( $aMetaFields ) {
01026             return $aMetaFields;
01027         }
01028 
01029         $aMetaFields = oxDb::getInstance()->getTableDescription( $sTable );
01030 
01031         if ( !$blReturnSimple ) {
01032             $myUtils->toFileCache( $sCacheKey, $aMetaFields );
01033             return $aMetaFields;
01034         }
01035 
01036         //returning simple array
01037         $aRet = array();
01038         if (is_array($aMetaFields)) {
01039             foreach ( $aMetaFields as $oVal ) {
01040                 $aRet[strtolower( $oVal->name )] = 0;
01041             }
01042         }
01043 
01044         $myUtils->toFileCache( $sCacheKey, $aRet);
01045 
01046         return $aRet;
01047     }
01048 
01060     protected function _getAllFields($blReturnSimple = false)
01061     {
01062         if (!$this->_sCoreTable) {
01063             return array();
01064         }
01065         return $this->_getTableFields($this->_sCoreTable, $blReturnSimple);
01066     }
01067 
01076     protected function _initDataStructure($blForceFullStructure = false)
01077     {
01078         $myUtils = oxUtils::getInstance();
01079 
01080         //get field names from cache
01081         $aFieldNames = null;
01082         $sFullCacheKey = 'fieldnames_' .$this->_sCoreTable . "_" . $this->_sCacheKey;
01083         if ($this->_sCacheKey && !$this->_isDisabledFieldCache()) {
01084             $aFieldNames = $myUtils->fromFileCache($sFullCacheKey);
01085         }
01086 
01087         if (!$aFieldNames) {
01088             $aFieldNames = $this->_getNonCachedFieldNames($blForceFullStructure);
01089             if ($this->_sCacheKey && !$this->_isDisabledFieldCache()) {
01090                 $myUtils->toFileCache($sFullCacheKey, $aFieldNames);
01091             }
01092         }
01093 
01094         if ( $aFieldNames !== false ) {
01095             foreach ( $aFieldNames as $sField => $sStatus ) {
01096                 $this->_addField($sField, $sStatus);
01097             }
01098         }
01099     }
01100 
01112     protected function _getNonCachedFieldNames($blForceFullStructure = false)
01113     {
01114         //T2008-02-22
01115         //so if this method is executed on cached version we see it when profiling
01116         startProfile("!__CACHABLE__!");
01117 
01118         //case 1. (admin)
01119         if ($this->isAdmin()) {
01120             $aMetaFields = $this->_getAllFields();
01121             foreach ( $aMetaFields as $oField ) {
01122                 if ( $oField->max_length == -1 ) {
01123                     $oField->max_length = 10;      // double or float
01124                 }
01125 
01126                 if ( $oField->type == "datetime" ) {
01127                     $oField->max_length = 20;
01128                 }
01129 
01130                 $this->_addField( $oField->name, $this->_getFieldStatus($oField->name), $oField->type, $oField->max_length );
01131             }
01132             stopProfile("!__CACHABLE__!");
01133             return false;
01134         }
01135 
01136         //case 2. (just get all fields)
01137         if ( $blForceFullStructure || !$this->_blUseLazyLoading ) {
01138             $aMetaFields = $this->_getAllFields(true);
01139             /*
01140             foreach ( $aMetaFields as $sFieldName => $sVal) {
01141                 $this->_addField( $sFieldName, $this->_getFieldStatus($sFieldName));
01142             }*/
01143             stopProfile("!__CACHABLE__!");
01144             return $aMetaFields;
01145         }
01146 
01147         //case 3. (get only oxid field, so we can fetch the rest of the fields over lazy loading mechanism)
01148         stopProfile("!__CACHABLE__!");
01149         return array("oxid" => 0);
01150     }
01151 
01160     protected function _getFieldStatus( $sFieldName )
01161     {
01162         return 0;
01163     }
01164 
01175     protected function _addField($sName, $iStatus, $sType = null, $sLength = null)
01176     {
01177         //preparation
01178         $sName = strtolower( $sName );
01179 
01180         //adding field names element
01181         $this->_aFieldNames[$sName] = $iStatus;
01182 
01183         //allready set?
01184         $sLongName = $this->_getFieldLongName($sName);
01185         if ( isset($this->$sLongName) ) {
01186             return;
01187         }
01188 
01189         //defining the field
01190         $oField = false;
01191 
01192         if ( isset( $sType ) ) {
01193             $oField = new oxField();
01194             $oField->fldtype = $sType;
01195             //T2008-01-29
01196             //can't clone as the fields are objects and are not fully cloned
01197             $this->_blIsSimplyClonable = false;
01198         }
01199 
01200         if ( isset( $sLength ) ) {
01201             if ( !$oField ) {
01202                 $oField = new oxField();
01203             }
01204             $oField->fldmax_length = $sLength;
01205             $this->_blIsSimplyClonable = false;
01206         }
01207 
01208         $this->$sLongName = $oField;
01209     }
01210 
01218     protected function _getFieldLongName( $sFieldName )
01219     {
01220         //trying to avoid strpos call as often as possible
01221         if ( $sFieldName[2] == $this->_sCoreTable[2] && strpos( $sFieldName, $this->_sCoreTable . "__" ) === 0 ) {
01222             return $sFieldName;
01223         }
01224 
01225         return $this->_sCoreTable . "__" . strtolower( $sFieldName );
01226     }
01227 
01237     protected function _setFieldData( $sFieldName, $sValue, $iDataType = oxField::T_TEXT)
01238     {
01239 
01240         $sLongFieldName = $this->_getFieldLongName( $sFieldName);
01241         //$sLongFieldName = $this->_sCoreTable . "__" . strtolower($sFieldName);
01242 
01243         //T2008-03-14
01244         //doing this because in lazy loaded lists on first load it is harmful to have initilised fields but not yet set
01245         //situation: only first article is loaded fully for "select oxid from oxarticles"
01246         /*
01247         if ($this->_blUseLazyLoading && !isset($this->$sLongFieldName))
01248             return;*/
01249 
01250         //in non lazy loading case we just add a field and do not care about it more
01251         if (!$this->_blUseLazyLoading && !isset($this->$sLongFieldName)) {
01252             $aFields = $this->_getAllFields(true);
01253             if ( isset( $aFields[strtolower($sFieldName)] ) ) {
01254                 $this->_addField($sFieldName, $this->_getFieldStatus($sFieldName));
01255             }
01256         }
01257         // if we have a double field we replace "," with "." in case somebody enters it in european format
01258         if (isset($this->$sLongFieldName) && isset($this->$sLongFieldName->fldtype) && $this->$sLongFieldName->fldtype == "double") {
01259             $sValue = str_replace( ",", ".", $sValue );
01260         }
01261 
01262         // isset is REQUIRED here not to use getter
01263         if (isset($this->$sLongFieldName) && is_object($this->$sLongFieldName)) {
01264             $this->$sLongFieldName->setValue($sValue, $iDataType);
01265         } else {
01266             $this->$sLongFieldName = new oxField($sValue, $iDataType);
01267         }
01268 
01269     }
01270 
01278     protected function _canFieldBeNull( $sFieldName )
01279     {
01280         $aMetaData = $this->_getAllFields();
01281         foreach ( $aMetaData as $oMetaInfo ) {
01282             if ( strcasecmp( $oMetaInfo->name, $sFieldName ) == 0 ) {
01283                 return !$oMetaInfo->not_null;
01284             }
01285         }
01286         return false;
01287     }
01288 
01289 
01297     protected function _getFieldDefaultValue( $sFieldName )
01298     {
01299         $aMetaData = $this->_getAllFields();
01300         foreach ( $aMetaData as $oMetaInfo ) {
01301             if ( strcasecmp( $oMetaInfo->name, $sFieldName ) == 0 ) {
01302                 return $oMetaInfo->default_value;
01303             }
01304         }
01305         return false;
01306     }
01307 
01308 
01317     protected function _getUpdateFieldValue( $sFieldName, $oField )
01318     {
01319         $mValue = null;
01320         if ( $oField instanceof oxField ) {
01321             $mValue = $oField->getRawValue();
01322         } elseif ( isset( $oField->value ) ) {
01323             $mValue = $oField->value;
01324         }
01325 
01326         $oDb = oxDb::getDb();
01327         //Check if this field value is null AND it can be null according if not returning default value
01328         if ( ( null === $mValue ) ) {
01329             if ( $this->_canFieldBeNull( $sFieldName ) ) {
01330                 return 'null';
01331             } elseif ( $mValue = $this->_getFieldDefaultValue( $sFieldName ) ) {
01332                 return $oDb->quote( $mValue );
01333             }
01334         }
01335 
01336         return $oDb->quote( $mValue );
01337     }
01338 
01347     protected function _getUpdateFields( $blUseSkipSaveFields = true )
01348     {
01349         $sSql = '';
01350         $blSep  = false;
01351 
01352         foreach (array_keys($this->_aFieldNames) as $sKey) {
01353             $sLongName = $this->_getFieldLongName($sKey);
01354             $oField = $this->$sLongName;
01355 
01356 
01357             if ( !$blUseSkipSaveFields || ($blUseSkipSaveFields && !in_array(strtolower($sKey), $this->_aSkipSaveFields)) ) {
01358                 $sSql .= (( $blSep) ? ',':'' ).$sKey." = ".$this->_getUpdateFieldValue($sKey, $oField);
01359                 $blSep = true;
01360             }
01361         }
01362 
01363         return $sSql;
01364     }
01365 
01375     protected function _update()
01376     {
01377         //do not allow derived item update
01378         if ( !$this->allowDerivedUpdate() ) {
01379             return false;
01380         }
01381 
01382 
01383         if ( !$this->getId() ) {
01384             $oEx = oxNew( 'oxObjectException' );
01385             $oEx->setMessage( 'EXCEPTION_OBJECT_OXIDNOTSET' );
01386             $oEx->setObject($this);
01387             throw $oEx;
01388         }
01389 
01390         $sIDKey = oxUtils::getInstance()->getArrFldName( $this->_sCoreTable.".oxid");
01391         $this->$sIDKey = new oxField($this->getId(), oxField::T_RAW);
01392         $oDb = oxDb::getDb();
01393 
01394         $sUpdate= "update {$this->_sCoreTable} set ".$this->_getUpdateFields()
01395                  ." where {$this->_sCoreTable}.oxid = ".$oDb->quote( $this->getId() );
01396 
01397         //trigger event
01398         $this->beforeUpdate();
01399 
01400         $blRet = (bool) $oDb->execute( $sUpdate);
01401         $this->_rebuildCache();
01402 
01403         return $blRet;
01404     }
01405 
01413     protected function _insert()
01414     {
01415 
01416         $oDb      = oxDb::getDb( oxDb::FETCH_MODE_ASSOC );
01417         $myConfig = $this->getConfig();
01418         $myUtils  = oxUtils::getInstance();
01419 
01420         // let's get a new ID
01421         if ( !$this->getId()) {
01422             $this->setId();
01423         }
01424 
01425         $sIDKey = $myUtils->getArrFldName( $this->_sCoreTable.".oxid");
01426         $this->$sIDKey = new oxField($this->getId(), oxField::T_RAW);
01427         $sInsert= "Insert into {$this->_sCoreTable} set ";
01428 
01429         //setting oxshopid
01430         $sShopField = $myUtils->getArrFldName($this->_sCoreTable.".oxshopid");
01431 
01432         if (isset($this->$sShopField) && !$this->$sShopField->value) {
01433             $this->$sShopField = new oxField($myConfig->getShopId(), oxField::T_RAW);
01434         }
01435 
01436 
01437         $sInsert .= $this->_getUpdateFields( false );
01438         $blRet = (bool) $oDb->execute( $sInsert);
01439 
01440         $this->_rebuildCache();
01441 
01442         return $blRet;
01443 
01444     }
01445 
01451     protected function _rebuildCache()
01452     {
01453         if ( !$this->_blIsNewCache) {
01454             oxUtils::getInstance()->rebuildCache();
01455             $this->_blIsNewCache = true;
01456         }
01457     }
01458 
01470     protected function _setRecordNumber( $sMaxField, $aWhere = null, $iMaxTryCnt = 5 )
01471     {
01472         // filtering
01473         $sWhere = "";
01474         if ( is_array( $aWhere ) && count( $aWhere ) > 0) {
01475             $sWhere = implode(" and ", $aWhere).' and ';
01476         }
01477         $oDb = oxDb::getDb( oxDb::FETCH_MODE_ASSOC );
01478 
01479         // SQL to set record number
01480         $sUpdate = "update {$this->getViewName()} as t1, (select (max($sMaxField)+1) as t2max from {$this->getViewName()} where $sWhere 1) as t2 set t1.$sMaxField=t2.t2max where t1.oxid = ".$oDb->quote( $this->getId() );
01481 
01482         // SQL to check record number dublicates
01483         //this should not happen normally but we prefer to take extra care in this case due to parallel script execution etc.
01484         $sMaxSelect = "select $sMaxField from ".$this->getViewName()." where oxid=".$oDb->quote( $this->getId() );
01485         $sCheck = "select count(oxid) from ".$this->getViewName()." where $sMaxField = ($sMaxSelect) and $sWhere 1 ";
01486 
01487         do {
01488             if ( $oDb->execute( $sUpdate ) === false ) {
01489                 return false;
01490             }
01491 
01492             $iChkCnt = $oDb->getOne( $sCheck );
01493         } while ( ( $iChkCnt > 1 ) && $iMaxTryCnt-- );
01494 
01495         $sFieldName = $this->getViewName().'__'.$sMaxField;
01496         $this->$sFieldName = new oxField( $oDb->getOne( $sMaxSelect ), oxField::T_RAW);//int value
01497 
01498         return ( $iChkCnt == 1 );
01499     }
01500 
01507     protected function _isDisabledFieldCache()
01508     {
01509         $sClass = get_class($this);
01510         if (isset(self::$_blDisableFieldCaching[$sClass]) && self::$_blDisableFieldCaching[$sClass]) {
01511             return true;
01512         }
01513 
01514         return false;
01515     }
01516 
01522     public function isOx()
01523     {
01524         $sOxId = $this->getId();
01525         if ( $sOxId[0] == 'o' && $sOxId[1] == 'x' ) {
01526             return true;
01527         }
01528         return false;
01529     }
01530 
01536     public function isReadOnly()
01537     {
01538         return $this->_blReadOnly;
01539     }
01540 
01548     public function setReadOnly( $blReadOnly )
01549     {
01550         $this->_blReadOnly = $blReadOnly;
01551     }
01552 
01558     public function getFieldNames()
01559     {
01560         return array_keys( $this->_aFieldNames );
01561     }
01562 
01570     public function addFieldName( $sName )
01571     {
01572         //preparation
01573         $sName = strtolower( $sName );
01574         $this->_aFieldNames[$sName] = 0;
01575     }
01576 
01577 
01583     public function getLanguage()
01584     {
01585         return -1;
01586     }
01587 }