_trackAssets = true; } // If the access property exists, set the default. if (property_exists($this, 'access')){ $this->access = (int) vFactory::getConfig()->get('access'); } if(JVM_VERSION>2){ // Implement JObservableInterface: // Create observer updater and attaches all observers interested by $this class: $this->_observers = new JObserverUpdater($this); JObserverMapper::attachAllObservers($this); } } public function setLoggable() { $this->_loggable = true; $this->created_on = false; $this->created_by = 0; $this->modified_on = ''; $this->modified_by = 0; } /** * * @author Patrick Kohl, * @author Max Milbers */ public function setTranslatable($langFields) { $this->_translatableFields = $langFields; $this->_translatableFields['slug'] = 'slug'; $this->_translatable = true; $this->_langTag = VmConfig::$vmlang; $this->_tbl_lang = $this->_tbl . '_' . $this->_langTag; } public function setLanguage($tag){ $this->_langTag = strtolower(strtr($tag,'-','_')); $this->_tbl_lang = $this->_tbl . '_' . $this->_langTag; } public function getTranslatableFields() { return $this->_translatableFields; } public function setLockable() { $this->locked_on = ''; $this->locked_by = 0; } function setSlug($slugAutoName, $key = 'slug') { $this->_slugAutoName = $slugAutoName; $this->_slugName = $key; $this->$key = ''; $this->setUniqueName($key); } /** * This function defines a database field as parameter field, which means that some values get injected there * As delimiters are used | for the pair and = for key, value * * @author Max Milbers * @param string $paramsFieldName * @param string $varsToPushParam * @param boolean $overwrite */ function setParameterable($paramsFieldName, $varsToPushParam, $overwrite = false) { //if($this->_xParams===0) $this->_xParams = $paramsFieldName; if ($overwrite) { $this->_varsToPushParam = $varsToPushParam; } else { $this->_varsToPushParam = array_merge((array)$varsToPushParam, (array)$this->_varsToPushParam); } foreach ($this->_varsToPushParam as $k => $v) { if (!isset($this->$k)) $this->$k = $v[0]; } //vmdebug('setParameterable called '.$this->_xParams,$this->_varsToPushParam); } /** * Maps the parameters to a subfield. usefull for the vForm * @author Max Milbers * @param $obj * @param $varsToPush * @param string $field */ static function bindParameterableToSubField(&$obj,$varsToPush,$field ='params'){ foreach($varsToPush as $name=>$values){ if(isset($obj->$name)){ $obj->$field->$name = $obj->$name; } else { $obj->$field->$name = $values[0]; } } } /** * This function must be * Takes the bounded values at obj of the field $xParams * and adds them as attributs of obj * @param $obj * @param $xParams * @param $varsToPushParam */ static function bindParameterable(&$obj, $xParams, $varsToPushParam) { if(empty($varsToPushParam)) return; if (empty($xParams)) { //vmError('There are bindParameterables, but $xParams is empty, this is a programmers error ',$varsToPushParam); vmdebug('There are bindParameterables, but $xParams is empty, this is a programmers error ', $obj); vmTrace('$xParams is empty'); } //$paramFields = $obj->$xParams; //vmdebug('$obj->_xParams '.$xParams.' $varsToPushParam ',$obj->$xParams,$varsToPushParam); if(is_object($obj)){ if (!empty($obj->$xParams)) { $params = explode('|', $obj->$xParams); foreach ($params as $item) { $item = explode('=', $item); $key = $item[0]; unset($item[0]); if(isset($varsToPushParam[$key][1])) { $item = implode('=', $item); $item = json_decode($item); if ($item != null){ $obj->$key = $item; } else { //vmdebug('bindParameterable $item ==null '.$key,$varsToPushParam[$key]); } } //else { // Unsolicited Parameter //} } } else { if(!property_exists($obj,$xParams)){ //vmError('There are bindParameterables, but $obj->$xParams is empty, this is a programmers error '.$xParams); vmdebug('There are bindParameterables, but $obj->$xParams is not isset, this is a programmers error ',$xParams , $obj); vmTrace('$obj->$xParams is not isset'); } } foreach ($varsToPushParam as $key => $v) { if (!isset($obj->$key)) { $obj->$key = $v[0]; //vmdebug('Set standard '.$key. ' = '.$v[0]); } } } else { //vmdebug('bindParameterable array ',$obj[$xParams]); if (!empty($obj[$xParams])) { $params = explode('|', $obj[$xParams]); foreach ($params as $item) { $item = explode('=', $item); $key = $item[0]; unset($item[0]); if (isset($item) && isset($varsToPushParam[$key][1])) { $item = implode('=', $item); $item = json_decode($item); if ($item != null){ $obj[$key] = $item; //$obj[$key] = html_entity_decode($item); } } } } else { if($obj[$xParams]==null){ //vmError('There are bindParameterables, but $obj->$xParams is empty, this is a programmers error '.$xParams); vmdebug('There are bindParameterables, but $obj[$xParams] is empty, this is a programmers error ',$xParams , $obj); vmTrace('$obj[$xParams] is empty'); } } foreach ($varsToPushParam as $key => $v) { if (!isset($obj[$key])) { $obj[$key] = $v[0]; } } } } /** * Sets fields encrypted * @author Max Milbers * @param $fieldNames */ public function setCryptedFields($fieldNames){ if(!$fieldNames){ vmTrace('setEncrytped fields false not catched'); return; } if(!is_array($fieldNames)) $fieldNames = array($fieldNames); if(isset($fieldNames[$this->_pkey])){ unset($fieldNames[$this->_pkey]); } $this->_cryptedFields = $fieldNames; } /** * */ public function getCryptedFields(){ return $this->_cryptedFields; } /** * Gives Back the columns of the current table, sets the properties on the table. * * @author Max Milbers * @param int $typeKey use "Field" to get the effect of getTableColumns * @param int $typeValue use "Type" to get the effect of getTableColumns * @param bool $properties disable setting of columns as table properties */ public function showFullColumns($typeKey=0,$typeValue=0,$properties=true){ $hash = 'SFL'.$this->_tbl.$typeKey.$typeValue; if (!isset($this->_cache[$hash])) {//vmSetStartTime('showFullColumns'); $this->_db->setQuery('SHOW FULL COLUMNS FROM `'.$this->_tbl.'` ') ; $this->_cache[$hash] = $this->_db->loadAssocList(); //vmTime('showFullColumns','showFullColumns'); } if ($properties and count($this->_cache[$hash]) > 0) { foreach ($this->_cache[$hash] as $key => $_f) { $_fieldlist[$_f['Field']] = $_f['Default']; } $this->setProperties($_fieldlist); } if ($typeKey or $typeValue){ foreach ($this->_cache[$hash] as $field){ if(empty($typeValue)){ $value = $field; } else { $value = $field[$typeValue]; } if($typeKey){ $result[$field[$typeKey]] = $value; } else { $result[] = $value; } } } else { $result = $this->_cache[$hash]; } return $result; } public function loadFields(){ return $this->showFullColumns(); } function loadFieldValues($array=true){ $tmp = get_object_vars($this); if($array){ $return = array(); foreach ($tmp as $k => $v){ // Do not process internal variables if ('_' != substr($k, 0, 1)){ $return[$k] = $v; } } } else { $return = new stdClass(); foreach ($tmp as $k => $v){ // Do not process internal variables if ('_' != substr($k, 0, 1)){ $return->$k = $v; } } } return $return; } /** * Method to provide a shortcut to binding, checking and storing a JTable * instance to the database table. The method will check a row in once the * data has been stored and if an ordering filter is present will attempt to * reorder the table rows based on the filter. The ordering filter is an instance * property name. The rows that will be reordered are those whose value matches * the JTable instance for the property specified. * * @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved. * @param mixed $src An associative array or object to bind to the JTable instance. * @param string $orderingFilter Filter for the order updating * @param mixed $ignore An optional array or space separated list of properties * to ignore while binding. * * @return boolean True on success. * * @link http://docs.joomla.org/JTable/save * @since 11.1 */ public function save($src, $orderingFilter = '', $ignore = '') { // Attempt to bind the source to the instance. if (!$this->bind($src, $ignore)) { return false; } // Run any sanity checks on the instance and verify that it is ready for storage. if (!$this->check()) { return false; } // Attempt to store the properties to the database table. if (!$this->store()) { return false; } // Attempt to check the row in, just in case it was checked out. if (!$this->checkin()) { return false; } // If an ordering filter is set, attempt reorder the rows in the table based on the filter and value. if ($orderingFilter) { $filterValue = $this->$orderingFilter; $this->reorder($orderingFilter ? $this->_db->quoteName($orderingFilter) . ' = ' . $this->_db->Quote($filterValue) : ''); } return true; } /** * Function setting the loggable data hack procted * In case you want to override the value for administrators, just set the created_on to "0000-00-00 00:00:00" * * @author Max Milbers */ function setLoggableFieldsForStore() { if ($this->_loggable) { // set default values always used //We store in UTC time, dont touch it! $date = vFactory::getDate(); $today = $date->toSQL(); //vmdebug('my today ',$date); $user = vFactory::getUser(); $pkey = $this->_pkey; //Lets check if the user is admin or the mainvendor $admin = vmAccess::manager('core'); if($admin){ // vmdebug('setLoggableFieldsForStore ', $this->created_on); if (empty($this->$pkey) and empty($this->created_on)) { $this->created_on = $today; } else if (empty($this->created_on)) { //If nothing is there, dont update it unset($this->created_on); } else //ADDED BY P2 PETER if ($this->created_on == "0000-00-00 00:00:00") { $this->created_on = $today; $this->created_by = $user->id; } //END ADD if (empty($this->$pkey) and empty($this->created_by)) { $this->created_by = $user->id; } else if (empty($this->created_by)) { //If nothing is there, dont update it unset($this->created_by); } } else { if (empty($this->$pkey)) { $this->created_on = $today; $this->created_by = $user->id; } else { //If nothing is there, dont update it unset($this->created_on); unset($this->created_by); } } $this->modified_on = $today; $this->modified_by = $user->id; } if (isset($this->locked_on)) { //Check if user is allowed to store, then disable or prevent storing $this->locked_on = 0; } } /** * * @param $obj * @param $src * @param array $ignore * @return bool */ static public function bindTo(&$obj, $src, $internals = false, $ignore = array()) { if(empty($src)) return false; if (is_object($src)) { $src = get_object_vars($src); } if(!is_array($src)) return false; $isIndexed = array_values($src) === $src; if($isIndexed) return false; // If the ignore value is a string, explode it over spaces. if (!empty($ignore) and !is_array($ignore)) { $ignore = explode(' ', $ignore); } foreach (get_object_vars($obj) as $k => $v) { if(!$internals and '_' == substr($k, 0, 1)) continue; // Only process fields not in the ignore array. if (!in_array($k, $ignore)) { if (isset($src[$k])) { $obj->$k = $src[$k]; } } } return true; } /** * Technic to inject params as table attributes * @author Max Milbers * $TableJoins array of table names to add and left join to find ID */ function load($oid = null, $overWriteLoadName = 0, $andWhere = 0, $tableJoins = array(), $joinKey = 0) { if($this->_translatable)vmSetStartTime('vmtableload'); if( $overWriteLoadName!==0 ){ $k = $overWriteLoadName; } else { $k = $this->_pkey; } if ($oid !== null) { $this->$k = $oid; } else { $oid = $this->$k; } if (empty($oid)) { if (!empty($this->_xParams)) { if(!empty($this->_varsToPushParam)){ foreach ($this->_varsToPushParam as $key => $v) { if (!isset($this->$key)) { $this->$key = $v[0]; } } } else { //vmdebug('_varsToPushParam empty ',$this); } } //vmdebug('vmtable load empty $oid return proto',$this); return $this; } //Version load the tables using JOIN if ($this->_translatable) { $mainTable = $this->_tbl; $langTable = $this->_tbl . '_' . $this->_langTag; $select = 'SELECT `' . $mainTable . '`.* ,`' . $langTable . '`.* '; $from = ' FROM `' . $mainTable . '` INNER JOIN `' . $langTable . '` using (`' . $this->_tbl_key . '`)'; } else { $mainTable = $this->_tbl; $select = 'SELECT `' . $mainTable . '`.* '; $from = ' FROM `' . $mainTable . '` '; } if (count($tableJoins)) { if (!$joinKey) $joinKey = $this->_tbl_key; foreach ($tableJoins as $tableId => $table) { if(strpos($tableId,',')!==false){ $tableIds = explode(',',$tableId); foreach($tableIds as $sel){ if(strpos($sel,' as ')!==false){ $temp = explode(' as ',$sel); $select .= ',`' . $table . '`.`' . trim($temp[0]) . '` as '.$temp[1].' '; } else { $select .= ',`' . $table . '`.`' . $sel . '` '; } } } else { $select .= ',`' . $table . '`.`' . $tableId . '` '; } $from .= ' LEFT JOIN `' . $table . '` on `' . $table . '`.`' . $joinKey . '`=`' . $mainTable . '`.`' . $joinKey . '`'; } } //the cast to int here destroyed the query for keys like virtuemart_userinfo_id, so no cast on $oid // $query = $select.$from.' WHERE '. $mainTable .'.`'.$this->_tbl_key.'` = "'.$oid.'"'; if ($andWhere === 0) $andWhere = ''; $query = $select . $from . ' WHERE `' . $mainTable . '`.`' . $k . '` = "' . $oid . '" ' . $andWhere; $hashVarsToPush = ''; if (!empty($this->_varsToPushParam)) { $hashVarsToPush = json_encode($this->_varsToPushParam); } $this->_lhash = md5($oid. $select . $k . $mainTable . $andWhere . $hashVarsToPush); //$this->showFullColumns(); if (isset ($this->_cache['l'][$this->_lhash])) { $this->bind($this->_cache['l'][$this->_lhash]); if (!empty($this->_xParams) and !empty($this->_varsToPushParam)) { self::bindParameterable($this, $this->_xParams, $this->_varsToPushParam); } if($this->_cryptedFields){ $this->decryptFields($this); } //vmTime('loaded by cache '.$this->_pkey.' '.$this->_slugAutoName.' '.$oid,'vmtableload'); return $this; } else { //vmdebug('loading '.$this->_pkey.' '.$this->_slugAutoName.' '.$oid); } $db = $this->getDBO(); $db->setQuery($query); $result = $db->loadAssoc(); if ($result) { $this->_loaded = true; $this->bind($result); if (!empty($this->_xParams)) { //Maybe better to use for $this an & self::bindParameterable($this, $this->_xParams, $this->_varsToPushParam); } if (count($tableJoins)) { foreach ($tableJoins as $tableId => $table) { if(strpos($tableId,',')!==false){ $tableIds = explode(',',$tableId); foreach($tableIds as $sel){ if(strpos($sel,' as ')!==false){ $temp = explode(' as ',$sel); $key = trim($temp[1]); //vmdebug('my $result ',$result[$key]); if (isset($result[$key])) $this->$key = $result[$key]; else $this->$key = false; } else { if (isset($result[$sel])) $this->$sel = $result[$sel]; } } } else { if (isset($result[$tableId])) $this->$tableId = $result[$tableId]; } } } } else { if($this->_translatable and VmConfig::$langCount>1 and $this->_ltmp!=VmConfig::$jDefLang ){ if(VmConfig::$defaultLang!=VmConfig::$jDefLang){ if($this->_langTag != VmConfig::$defaultLang ){ $this->_ltmp = $this->_langTag; $this->_langTag = VmConfig::$defaultLang; $this->_tempHash = $this->_lhash; } else { $this->_langTag = VmConfig::$jDefLang; } } else { $this->_ltmp = $this->_langTag; $this->_langTag = VmConfig::$defaultLang; $this->_tempHash = $this->_lhash; } //vmdebug('No result for '.$this->_ltmp.', lets check for Fallback lang '.$this->_langTag); //vmSetStartTime('lfallback'); $this->load($oid, $overWriteLoadName, $andWhere, $tableJoins, $joinKey) ; //vmTime('Time to load language fallback '.$this->_langTag, 'lfallback'); } else { $this->_loaded = false; } } if($this->_ltmp){ //vmdebug('Set Ltmp '.$this->_ltmp.' back to false'); $this->_langTag = $this->_ltmp; $this->_cache['l'][$this->_lhash] = $this->_cache['l'][$this->_tempHash] = $this->loadFieldValues(false); } else { $this->_cache['l'][$this->_lhash] = $this->loadFieldValues(false); } if($this->_cryptedFields){ $this->decryptFields(); } //if($this->_translatable) vmTime('loaded '.$this->_langTag.' '.$mainTable.' '.$oid ,'vmtableload'); $this->_ltmp = false; return $this; } function getLoaded (){ return $this->_loaded; } /** * Typo, had wrong name */ function encryptFields(){ $this->decryptFields(); } function decryptFields(){ if(!class_exists('vmCrypt')){ require(VMPATH_ADMIN.DS.'helpers'.DS.'vmcrypt.php'); } if(isset($this->modified_on) and $this->modified_on!='0000-00-00 00:00:00'){ $date = vFactory::getDate($this->modified_on); $date = $date->toUnix(); } else if(isset($this->created_on) and $this->created_on!='0000-00-00 00:00:00'){ $date = vFactory::getDate($this->created_on); $date = $date->toUnix(); } else { $date = 0; } foreach($this->_cryptedFields as $field){ if(isset($this->$field)){ $this->$field = vmCrypt::decrypt($this->$field, $date); vmdebug($this->_tbl.' Field '.$field.' encrypted = '.$this->$field); } } } /** * Derived from JTable * Records in this table do not need to exist, so we might need to create a record even * if the primary key is set. Therefore we need to overload the store() function. * Technic to inject params as table attributes and to encrypt data * @author Max Milbers * @copyright for derived parts, (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved. * @see libraries/joomla/database/JTable#store($updateNulls) */ function store($updateNulls = false) { $this->setLoggableFieldsForStore(); if($this->_cryptedFields){ if(!class_exists('vmCrypt')){ require(VMPATH_ADMIN.DS.'helpers'.DS.'vmcrypt.php'); } foreach($this->_cryptedFields as $field){ if(isset($this->$field)){ $this->$field = vmCrypt::encrypt($this->$field); } } } $this->storeParams(); if (!empty($this->asset_id)) { $currentAssetId = $this->asset_id; } // The asset id field is managed privately by this class. if ($this->_trackAssets) { unset($this->asset_id); } $tblKey = $this->_tbl_key; if(!empty($this->$tblKey)){ $_qry = 'SELECT `'.$tblKey.'` ' . 'FROM `'.$this->_tbl.'` ' . 'WHERE `'.$tblKey.'` = "' . $this->$tblKey.'" '; $this->_db->setQuery($_qry); $this->$tblKey = $this->_db->loadResult(); } if(!empty($this->$tblKey)){ $ok = $this->_db->updateObject($this->_tbl, $this, $this->_tbl_key, $updateNulls); } else { $ok = $this->_db->insertObject($this->_tbl, $this, $this->_tbl_key); } //reset Params if(isset($this->_tmpParams) and is_array($this->_tmpParams)){ foreach($this->_tmpParams as $k => $v){ $this->$k = $v; } } $this->_tmpParams = false; // If the store failed return false. if (!$ok) { $e = new Exception(vmText::sprintf('JLIB_DATABASE_ERROR_STORE_FAILED', get_class($this), $this->_db->getErrorMsg())); vmError($e); return false; } // If the table is not set to track assets return true. if (!$this->_trackAssets) { return true; } if ($this->_locked) { $this->_unlock(); } $parentId = $this->_getAssetParentId(); $name = $this->_getAssetName(); $title = $this->_getAssetTitle(); $asset = JTable::getInstance('Asset', 'JTable', array('dbo' => $this->getDbo())); $asset->loadByName($name); // Re-inject the asset id. $this->asset_id = $asset->id; // Check for an error. if ($error = $asset->getError()){ vmError($error); return false; } // Specify how a new or moved node asset is inserted into the tree. if (empty($this->asset_id) || $asset->parent_id != $parentId) { $asset->setLocation($parentId, 'last-child'); } // Prepare the asset to be stored. $asset->parent_id = $parentId; $asset->name = $name; $asset->title = $title; if ($this->_rules instanceof JAccessRules) { $asset->rules = (string) $this->_rules; } if (!$asset->check() || !$asset->store($updateNulls)) { vmError($asset->getError()); return false; } // Create an asset_id or heal one that is corrupted. if (empty($this->asset_id) || ($currentAssetId != $this->asset_id && !empty($this->asset_id))) { // Update the asset_id field in this table. $this->asset_id = (int) $asset->id; $q = 'UPDATE '.$this->_db->quoteName($this->_tbl).' SET asset_id = ' . (int) $this->asset_id.' WHERE '.$this->_db->quoteName($tblKey) . ' = ' . (int) $this->$tblKey.';'; $this->_db->setQuery($q); if (!$this->_db->execute()) { $e = new Exception(vmText::sprintf('JLIB_DATABASE_ERROR_STORE_FAILED_UPDATE_ASSET_ID', $this->_db->getErrorMsg())); vmError($e); return false; } } return $ok; } function storeParams() { if (!empty($this->_xParams) and !empty($this->_varsToPushParam)) { $paramFieldName = $this->_xParams; $this->$paramFieldName = ''; $this->_tmpParams = array(); foreach ($this->_varsToPushParam as $key => $v) { if (isset($this->$key)) { $this->$paramFieldName .= $key . '=' . vmJsApi::safe_json_encode($this->$key) . '|'; $this->_tmpParams[$key] = $this->$key; } else { $this->$paramFieldName .= $key . '=' . vmJsApi::safe_json_encode($v[0]) . '|'; $this->_tmpParams[$key] = $v[0]; } unset($this->$key); } } return true; } function checkCreateUnique($tbl_name, $name) { $i = 0; while ($i < 20) { $tbl_key = $this->_tbl_key; $q = 'SELECT `' . $name . '` FROM `' . $tbl_name . '` WHERE `' . $name . '` = "' . $this->$name . '" '; if(!empty($this->$tbl_key)){ $q .= ' AND `' . $this->_tbl_key . '`!=' . $this->$tbl_key.' '; } $this->_db->setQuery($q); $existingSlugName = $this->_db->loadResult(); if (!empty($existingSlugName)) { if($posNbr = strrpos($this->$name,'-')){ $existingNbr = substr($this->$name,$posNbr+1); if(is_numeric($existingNbr)){ $existingNbr++; if($i>10){ $existingNbr = $existingNbr + rand (1, 9); } $this->$name = substr($this->$name,0,$posNbr+1) . $existingNbr; } else{ $this->$name = $this->$name . '-1'; } } else { $this->$name = $this->$name . '-1'; } vmdebug('checkCreateUnique slug = '.$name.' changed to ',$this->$name); } else { return true; } $i++; } return false; } /** * @author Max Milbers * @param */ function check() { if (!empty($this->_slugAutoName)) { $slugAutoName = $this->_slugAutoName; $slugName = $this->_slugName; if (in_array($slugAutoName, $this->_translatableFields)) { $checkTable = $this->_tbl_lang; vmTrace('Language table in normal check?'); } else { $checkTable = $this->_tbl; } if (empty($this->$slugName)) { // vmdebug('table check use _slugAutoName '.$slugAutoName.' '.$slugName); if (!empty($this->$slugAutoName)) { $this->$slugName = $this->$slugAutoName; } else { $pkey = $this->_pkey; vmError('VmTable ' . $checkTable . ' Check not passed. Neither slug nor obligatory value at ' . $slugAutoName . ' for auto slug creation is given '.$this->$pkey); return false; } } //if (JVM_VERSION === 1) $this->$slugName = JFilterOutput::stringURLSafe($this->$slugName); //else $this->$slugName = JApplication::stringURLSafe($this->$slugName); //pro+#'!"§$%&/()=?duct-w-| ||cu|st|omfield-|str //vmdebug('my slugName '.$slugName,$this->$slugName); $this->$slugName = str_replace('-', ' ', $this->$slugName); $this->$slugName = html_entity_decode($this->$slugName,ENT_QUOTES); //$config =& vFactory::getConfig(); //$transliterate = $config->get('unicodeslugs'); $unicodeslugs = VmConfig::get('transliterateSlugs',false); if($unicodeslugs){ $lang = vFactory::getLanguage(); $this->$slugName = $lang->transliterate($this->$slugName); } // Trim white spaces at beginning and end of alias and make lowercase $this->$slugName = trim(JString::strtolower($this->$slugName)); $this->$slugName = str_replace(array('`','´',"'"),'',$this->$slugName); $this->$slugName = vRequest::filterUword($this->$slugName,'-,_,|','-'); while(strpos($this->$slugName,'--')){ $this->$slugName = str_replace('--','-',$this->$slugName); } // Trim dashes at beginning and end of alias $this->$slugName = trim($this->$slugName, '-'); if($unicodeslugs)$this->$slugName = rawurlencode($this->$slugName); $valid = $this->checkCreateUnique($checkTable, $slugName); //vmdebug('my Final slugName '.$slugName,$this->$slugName); if (!$valid) { return false; } } foreach ($this->_obkeys as $obkeys => $error) { if (empty($this->$obkeys)) { $error = get_class($this) . ' ' .vmText::sprintf('COM_VIRTUEMART_STRING_ERROR_OBLIGATORY_KEY', 'COM_VIRTUEMART_' . strtoupper($obkeys) ); vmError($error); return false; } } if ($this->_unique) { if (empty($this->_db)) $this->_db = vFactory::getDBO(); foreach ($this->_unique_name as $obkeys => $error) { if (empty($this->$obkeys)) { $error = vmText::sprintf('COM_VIRTUEMART_STRING_ERROR_NOT_UNIQUE_NAME', 'COM_VIRTUEMART_' . strtoupper($obkeys)); vmError('Non unique ' . $this->_unique_name . ' ' . $error); return false; } else { $valid = $this->checkCreateUnique($this->_tbl, $obkeys); if (!$valid) { return false; } } } } if (property_exists($this,'virtuemart_vendor_id') ) { if(empty($this->virtuemart_vendor_id) and $this->_pkey=='virtuemart_vendor_id'){ $this->virtuemart_vendor_id = $this->_pvalue; } $multix = Vmconfig::get('multix', 'none'); //Lets check if the user is admin or the mainvendor $virtuemart_vendor_id = false; //Todo removed Quickn Dirty, use check in derived class if ($multix == 'none' and get_class($this) !== 'TableVmusers') { $this->virtuemart_vendor_id = 1; return true; } else { $loggedVendorId = vmAccess::isSuperVendor(); $user = vFactory::getUser(); $admin = vmAccess::manager('managevendors'); $tbl_key = $this->_tbl_key; $className = get_class($this); //Todo removed Quickn Dirty, use check in derived class if (strpos($this->_tbl,'virtuemart_vmusers')===FALSE) { $q = 'SELECT `virtuemart_vendor_id` FROM `' . $this->_tbl . '` WHERE `' . $this->_tbl_key . '`="' . $this->$tbl_key . '" '; if (!isset($this->_cache[md5($q)])) { $this->_db->setQuery($q); $this->_cache[md5($q)] = $virtuemart_vendor_id = $this->_db->loadResult(); } else $virtuemart_vendor_id = $this->_cache[md5($q)]; } else { $q = 'SELECT `virtuemart_vendor_id`,`user_is_vendor` FROM `' . $this->_tbl . '` WHERE `' . $this->_tbl_key . '`="' . $this->$tbl_key . '" '; if (!isset($this->_cache[md5($q)])) { $this->_db->setQuery($q); $vmuser = $this->_db->loadRow(); $this->_cache[md5($q)] = $vmuser; } else $vmuser = $this->_cache[md5($q)]; if ($vmuser and count($vmuser) === 2) { $virtuemart_vendor_id = $vmuser[0]; $user_is_vendor = $vmuser[1]; if ($multix == 'none') { if (empty($user_is_vendor)) { $this->virtuemart_vendor_id = 0; } else { $this->virtuemart_vendor_id = 1; } return true; } else { if (!$admin) { $rVendorId = vmAccess::isSuperVendor($user->id); $this->virtuemart_vendor_id = $rVendorId; return true; } } } else { //New User //vmInfo('We run in multivendor mode and you did not set any vendor for '.$className.' and '.$this->_tbl);//, Set to mainvendor '.$this->virtuemart_vendor_id } } if (!$admin and !empty($virtuemart_vendor_id) and !empty($loggedVendorId) and $loggedVendorId != $virtuemart_vendor_id) { //Todo removed Quickn Dirty, use check in derived class //This is the case when a vendor buys products of vendor1 if (strpos($this->_tbl,'virtuemart_order_items')===FALSE and strpos($this->_tbl,'virtuemart_carts')===FALSE) { vmdebug('Blocked storing, logged vendor ' . $loggedVendorId . ' but data belongs to ' . $virtuemart_vendor_id,$this->_tbl); return false; } else { $this->virtuemart_vendor_id = $virtuemart_vendor_id; } } else if (!$admin) { if ($virtuemart_vendor_id) { $this->virtuemart_vendor_id = $virtuemart_vendor_id; vmdebug('Non admin is storing using loaded vendor_id'); } else { if(empty($this->virtuemart_vendor_id)){ $this->virtuemart_vendor_id = $loggedVendorId; } //No id is stored, even users are allowed to use for the storage and vendorId, no change } } else { //Admins are allowed to do anything. We just trhow some messages if (!empty($virtuemart_vendor_id) and $loggedVendorId != $virtuemart_vendor_id) { vmdebug('Admin with vendor id ' . $loggedVendorId . ' is using for storing vendor id ' . $this->virtuemart_vendor_id); } else if (empty($virtuemart_vendor_id) and empty($this->virtuemart_vendor_id)) { if(strpos($this->_tbl,'virtuemart_vendors')===FALSE and strpos($this->_tbl,'virtuemart_vmusers')===FALSE){ $this->virtuemart_vendor_id = $loggedVendorId; vmdebug('Fallback to '.$this->virtuemart_vendor_id.' for $loggedVendorId '.$loggedVendorId.': We run in multivendor mode and you did not set any vendor for '.$className.' and '.$this->_tbl); } } } } } return true; } /** * Method to bind an associative array or object to the JTable instance.This * method only binds properties that are publicly accessible and optionally * takes an array of properties to ignore when binding. * * @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved. * @param mixed $src An associative array or object to bind to the JTable instance. * @param mixed $ignore An optional array or space separated list of properties to ignore while binding. * * @return boolean True on success. * * @link http://docs.joomla.org/JTable/bind * @since 11.1 */ public function bind($src, $ignore = array()) { // If the source value is not an array or object return false. if (!is_object($src) && !is_array($src)) { $e = new Exception(vmText::sprintf('JLIB_DATABASE_ERROR_BIND_FAILED_INVALID_SOURCE_ARGUMENT', get_class($this))); vmError($e); return false; } // If the source value is an object, get its accessible properties. if (is_object($src)) { $src = get_object_vars($src); } // If the ignore value is a string, explode it over spaces. if (!is_array($ignore)) { $ignore = explode(' ', $ignore); } // Bind the source value, excluding the ignored fields. foreach ($this->getProperties() as $k => $v) { // Only process fields not in the ignore array. if (!in_array($k, $ignore)) { if (isset($src[$k])) { $this->$k = $src[$k]; } } } return true; } /** * As shortcat, Important the & MUST be there, even in php5.3 * * @author Max Milbers * @param array/obj $data input data as assoc array or obj * @param boolean $preload You can preload the data here too preserve not updated data * @return array/obj $data the updated data */ public function bindChecknStore(&$data, $preload = false) { $tblKey = $this->_tbl_key; $ok = true; if ($this->_translatable) { if (!class_exists('VmTableData')) require(VMPATH_ADMIN . DS . 'helpers' . DS . 'vmtabledata.php'); $db = vFactory::getDBO(); $dataTable = clone($this); $langTable = new VmTableData($this->_tbl_lang, $tblKey, $db); $langTable->setLanguage($this->_langTag); $langTable->setPrimaryKey($tblKey); $langData = array(); $langObKeys = array(); $langUniqueKeys = array(); if (is_object($data)) { foreach ($this->_translatableFields as $name) { $langTable->$name = $this->$name; if (isset($data->$name)) { //We directly store language stuff "escaped" $langData[$name] = htmlspecialchars(html_entity_decode($data->$name, ENT_QUOTES, "UTF-8"), ENT_QUOTES, "UTF-8"); } unset($dataTable->$name); if (!empty($this->_unique_name[$name])) { $langUniqueKeys[$name] = 1; unset($dataTable->_unique_name[$name]); $langObKeys[$name] = 1; unset($dataTable->_obkeys[$name]); } if (!empty($this->_obkeys[$name])) { $langObKeys[$name] = 1; unset($dataTable->_obkeys[$name]); } } } else { foreach ($this->_translatableFields as $name) { $langTable->$name = $this->$name; if (isset($data[$name])) { $langData[$name] = htmlspecialchars(html_entity_decode($data[$name], ENT_QUOTES, "UTF-8"), ENT_QUOTES, "UTF-8"); } unset($dataTable->$name); if (!empty($this->_unique_name[$name])) { $langUniqueKeys[$name] = 1; unset($dataTable->_unique_name[$name]); $langObKeys[$name] = 1; unset($dataTable->_obkeys[$name]); } if (!empty($this->_obkeys[$name])) { $langObKeys[$name] = 1; unset($dataTable->_obkeys[$name]); } } } $langTable->_unique_name = $langUniqueKeys; $langTable->_obkeys = $langObKeys; $langTable->_slugAutoName = $this->_slugAutoName; unset($dataTable->_slugAutoName); $langTable->_slugName = 'slug'; unset($dataTable->_slugName); $langTable->setProperties($langData); $langTable->_translatable = false; //We must check the langtable BEFORE we store the normal table, cause the langtable is often defining if there are enough data to store it (for exmple the name) if ($ok) { //vmdebug('my langtable before bind',$langTable->id); if (!$langTable->bind($data)) { $ok = false; $msg = 'bind'; // vmdebug('Problem in bind '.get_class($this).' '.$this->_db->getErrorMsg()); vmdebug('Problem in bind ' . get_class($this) . ' '); } } if ($ok) { if (!$langTable->check()) { $ok = false; vmdebug('Check returned false ' . get_class($langTable) . ' ' . $this->_tbl . ' ' . $langTable->_db->getErrorMsg()); } } if ($ok) { $dataTable->bindChecknStoreNoLang($data, $preload); $this->bind($dataTable); $langTable->$tblKey = !empty($this->$tblKey) ? $this->$tblKey : 0; //vmdebug('bindChecknStoreNoLang my $tblKey '.$tblKey.' '.$langTable->$tblKey); if ($ok and $preload) { if (!empty($langTable->$tblKey)) { $id = $langTable->$tblKey; if (!$langTable->load($id)) { $ok = false; vmdebug('Preloading of language table failed, no id given, cannot store ' . $this->_tbl); } } else { if ($ok) { if (!$langTable->bind($data)) { $ok = false; vmdebug('Problem in bind ' . get_class($this) . ' '); } } if ($ok) { if (!$langTable->check()) { $ok = false; vmdebug('Check returned false ' . get_class($langTable) . ' ' . $this->_tbl . ' ' . $langTable->_db->getErrorMsg()); } } } } if ($ok) { if (!$langTable->store()) { $ok = false; // $msg .= ' store'; vmdebug('Problem in store with langtable ' . get_class($langTable) . ' with ' . $tblKey . ' = ' . $this->$tblKey . ' ' . $langTable->_db->getErrorMsg()); } else { $this->bind($langTable); } } } } else { if (!$this->bindChecknStoreNoLang($data, $preload)) { $ok = false; } } if($ok){ if($this->_lhash){ $this->_cache['l'][$this->_lhash] = $this->loadFieldValues(false); } } return $ok; } function bindChecknStoreNoLang(&$data, $preload = false) { $tblKey = $this->_tbl_key; if ($preload) { if (is_object($data)) { if (!empty($data->$tblKey)) { $this->load($data->$tblKey); } } else { if (!empty($data[$tblKey])) { $this->load($data[$tblKey]); } } if ($this->_translatable) { foreach ($this->_translatableFields as $name) { unset($this->$name); } } //vmdebug('bindChecknStoreNoLang language unloaded, why?'); } $ok = true; $msg = ''; if (!$this->bind($data)) { $ok = false; $msg = 'bind'; // vmdebug('Problem in bind '.get_class($this).' '.$this->_db->getErrorMsg()); vmdebug('Problem in bind ' . get_class($this) . ' '); } if ($ok) { if (!$this->checkDataContainsTableFields($data)) { $ok = false; // $msg .= ' developer notice:: checkDataContainsTableFields'; } } if ($ok) { if (!$this->check()) { $ok = false; $msg .= ' check'; vmdebug('Check returned false ' . get_class($this) . ' ' . $this->_db->getErrorMsg()); return false; } } if ($ok) { if (!$this->store($this->_updateNulls)) { $ok = false; $msg .= ' store'; vmdebug('Problem in store ' . get_class($this) . ' ' . $this->_db->getErrorMsg()); return false; } } if (is_object($data)) { $data->$tblKey = !empty($this->$tblKey) ? $this->$tblKey : 0; } else { $data[$tblKey] = !empty($this->$tblKey) ? $this->$tblKey : 0; } // vmdebug('bindChecknStore '.get_class($this).' '.$this->_db->getErrorMsg()); //This should return $ok and not the data, because it is already updated due use of reference return $data; } /** * Description * will make sure that all items in the table are not using the same ordering values * @author stAn * @access public * $where -> limits the categories if a child category of another one */ function fixOrdering($where = '') { $where = $where ? ' WHERE ' . $where : ''; // fast check for duplicities $q = 'SELECT `' . $this->_tbl_key . '` FROM `' . $this->_tbl . '` GROUP BY `' . $this->_orderingKey . '` HAVING COUNT(*) >= 2 ' . $where . ' LIMIT 1'; $this->_db->setQuery($q); $res = $this->_db->loadAssocList(); if (empty($res)) return true; $q = ' SELECT `' . $this->_tbl_key . '` FROM `' . $this->_tbl . '` ' . $where . ' ORDER BY `' . $this->_orderingKey . '` ASC'; $this->_db->setQuery($q, 0, 999999); $res = $this->_db->loadAssocList(); $e = $this->_db->getErrorMsg(); if (!empty($e)) { vmError(get_class($this) . $e); } echo $q . "
\n"; // no data in the table if (empty($res)) return true; // we will set ordering to 5,10,15,20,25 so there is enough space in between for manual editing $start = 5; // it is not really optimized to load full table into array, a while loop would be better especially when having thousands of categories foreach ($res as $row) { $q = 'UPDATE `' . $this->_tbl . '` SET `' . $this->_orderingKey . '` = ' . (int)$start . ' WHERE `' . $this->_tbl_key . '`= ' . $row[$this->_tbl_key] . ' LIMIT 1'; $this->_db->setQuery($q); $r = $this->_db->execute($q); $start = $start + 5; } } /** * Description * * @author Joomla Team, Max Milbers * @access public * @param $dirn * @param $where */ function move($dirn, $where = '', $orderingkey = 0) { // for some reason this function is not used from categories $this->fixOrdering(); $k = $this->_tbl_key; // problem here was that $this->$k returned (0) $cid = vRequest::getInt($this->_pkeyForm,vRequest::getInt($this->_pkey,false)); if (!empty($cid) && (is_array($cid))) { $cid = reset($cid); } else { vmError(get_class($this) . ' is missing cid information !'); return false; } // stAn: if somebody knows how to get current `ordering` of selected cid (i.e. virtuemart_userinfo_id or virtuemart_category_id from defined vars, you can review the code below) $q = "SELECT `" . $this->_orderingKey . '` FROM `' . $this->_tbl . '` WHERE `' . $this->_tbl_key . "` = '" . (int)$cid . "' limit 0,1"; if (!isset($this->_cache[md5($q)])) { $this->_db->setQuery($q); $c_order = $this->_db->loadResult(); // current ordering value of cid } else { $c_order = $this->_cache[md5($q)]; } $this->$orderingkey = $c_order; $e = $this->_db->getErrorMsg(); if (!empty($e)) { vmError(get_class($this) . $e); } // stAn addition: $where .= ' `' . $this->_tbl_key . '` <> ' . (int)$cid . ' '; // explanation: // select one above or under which is not cid and update/set it's ordering of the original cid // could be done with one complex query... but this is more straitforward and the speed is not that much needed in this one if (!empty($orderingkey)) $this->_orderingKey = $orderingkey; if (!in_array($this->_orderingKey, array_keys($this->getProperties()))) { vmError(get_class($this) . ' does not support ordering'); return false; } $k = $this->_tbl_key; // virtuemart_userfield_id column name $orderingKey = $this->_orderingKey; // ordering column name $sql = 'SELECT `' . $this->_tbl_key . '`, `' . $this->_orderingKey . '` FROM ' . $this->_tbl; if ($dirn < 0) { $sql .= ' WHERE `' . $this->_orderingKey . '` <= ' . (int)$c_order; $sql .= ($where ? ' AND ' . $where : ''); $sql .= ' ORDER BY `' . $this->_orderingKey . '` DESC'; } else if ($dirn > 0) { $sql .= ' WHERE `' . $this->_orderingKey . '` >= ' . (int)$c_order; $sql .= ($where ? ' AND ' . $where : ''); $sql .= ' ORDER BY `' . $this->_orderingKey . '`'; } else { $sql .= ' WHERE `' . $this->_orderingKey . '` = ' . (int)$c_order; $sql .= ($where ? ' AND ' . $where : ''); $sql .= ' ORDER BY `' . $this->_orderingKey . '`'; } if (!isset($this->_cache[md5($sql)])) { $this->_db->setQuery($sql, 0, 1); $row = null; $row = $this->_db->loadObject(); } else $row = $this->_cache[md5($sql)]; if (isset($row)) { // ok, we have a problem here - previous or next item has the same ordering as the current one // we need to fix the ordering be reordering it all if ((int)$row->$orderingKey == $c_order) { // if we fix this while loading the ordering, it will slow down FE } // update the next or previous to have the same ordering as the selected $query = 'UPDATE ' . $this->_tbl . ' SET `' . $this->_orderingKey . '` = ' . (int)$c_order . ' WHERE ' . $this->_tbl_key . ' = ' . (int)$row->$k . ' LIMIT 1'; $this->_db->setQuery($query); echo "\n" . $query . '
'; if (!$this->_db->execute()) { $err = $this->_db->getErrorMsg(); vmError( get_class($this) . ':: move isset row $row->$k' . $err); } // update the currently selected to have the same ordering as the next or previous $query = 'UPDATE ' . $this->_tbl . ' SET `' . $this->_orderingKey . '` = ' . (int)$row->$orderingKey . ' WHERE ' . $this->_tbl_key . ' = "' . (int)$cid . '" LIMIT 1'; $this->_db->setQuery($query); //echo $query.'
'; die(); if (!$this->_db->execute()) { $err = $this->_db->getErrorMsg(); vmError( get_class($this) . ':: move isset row $row->$k' . $err); } // stAn, what for is this? $this->ordering = $row->$orderingKey; } else { // stAn: why should we update the same line with the same information when no next or previous found (?) $query = 'UPDATE ' . $this->_tbl . ' SET `' . $this->_orderingKey . '` = ' . (int)$this->$orderingKey . ' WHERE ' . $this->_tbl_key . ' = "' . $this->_db->escape($this->$k) . '" LIMIT 1'; $this->_db->setQuery($query); if (!$this->_db->execute()) { $err = $this->_db->getErrorMsg(); vmError( get_class($this) . ':: move update $this->$k' . $err); } } return true; } /** * Returns the ordering value to place a new item last in its group * * @access public * @param string query WHERE clause for selecting MAX(ordering). */ function getNextOrder($where = '', $orderingkey = 0) { $where = $this->_db->escape($where); $orderingkey = $this->_db->escape($orderingkey); if (!empty($orderingkey)) $this->_orderingKey = $orderingkey; if (!in_array($this->_orderingKey, array_keys($this->getProperties()))) { vmError(get_class($this) . ' does not support ordering'); return false; } $query = 'SELECT MAX(`' . $this->_orderingKey . '`)' . ' FROM ' . $this->_tbl . ($where ? ' WHERE ' . $where : ''); if (!isset($this->_cache[md5($query)])) { $this->_db->setQuery($query); $maxord = $this->_db->loadResult(); } else $maxord = $this->_cache[md5($query)]; if ($this->_db->getErrorNum()) { vmError(get_class($this) . ' getNextOrder ' . $this->_db->getErrorMsg()); return false; } return $maxord + 1; } /** * Compacts the ordering sequence of the selected records * * @access public * @param string Additional where query to limit ordering to a particular subset of records */ function reorder($where = '', $orderingkey = 0) { $where = $this->_db->escape($where); $orderingkey = $this->_db->escape($orderingkey); if (!empty($orderingkey)) $this->_orderingKey = $orderingkey; $k = $this->_tbl_key; if (!in_array($this->_orderingKey, array_keys($this->getProperties()))) { vmError(get_class($this) . ' does not support ordering'); return false; } if ($this->_tbl == '#__content_frontpage') { $order2 = ", content_id DESC"; } else { $order2 = ""; } $query = 'SELECT ' . $this->_tbl_key . ', ' . $this->_orderingKey . ' FROM ' . $this->_tbl . ' WHERE `' . $this->_orderingKey . '` >= 0' . ($where ? ' AND ' . $where : '') . ' ORDER BY `' . $this->_orderingKey . '` ' . $order2; $this->_db->setQuery($query); if (!($orders = $this->_db->loadObjectList())) { vmError(get_class($this) . ' reorder ' . $this->_db->getErrorMsg()); return false; } $orderingKey = $this->_orderingKey; // compact the ordering numbers for ($i = 0, $n = count($orders); $i < $n; $i++) { if ($orders[$i]->$orderingKey >= 0) { if ($orders[$i]->$orderingKey != $i + 1) { $orders[$i]->$orderingKey = $i + 1; $query = 'UPDATE ' . $this->_tbl . ' SET `' . $this->_orderingKey . '` = "' . $this->_db->escape($orders[$i]->$orderingKey) . '" WHERE ' . $k . ' = "' . $this->_db->escape($orders[$i]->$k) . '"'; $this->_db->setQuery($query); $this->_db->execute(); } } } return true; } /** * Checks out a row * * @access public * @param integer The id of the user * @param mixed The primary key value for the row * @return boolean True if successful, or if checkout is not supported */ function checkout($who, $oid = null) { if (!in_array('locked_by', array_keys($this->getProperties()))) { return true; } $k = $this->_tbl_key; if ($oid !== null) { $this->$k = $oid; } $config = vFactory::getConfig(); $siteOffset = $config->get('offset'); $date = vFactory::getDate('now', $siteOffset); $time = $date->toSql(); $query = 'UPDATE ' . $this->_db->quoteName($this->_tbl) . ' SET locked_by = ' . (int)$who . ', locked_on = "' . $this->_db->escape($time) . '" WHERE ' . $this->_tbl_key . ' = "' . $this->_db->escape($this->$k) . '"'; $this->_db->setQuery($query); $this->locked_by = $who; $this->locked_on = $time; return $this->_db->execute(); } /** * Checks in a row * * @access public * @param mixed The primary key value for the row * @return boolean True if successful, or if checkout is not supported */ function checkin($oid = null) { if (!( in_array('locked_by', array_keys($this->getProperties())) || in_array('locked_on', array_keys($this->getProperties())) ) ) { return true; } $k = $this->_tbl_key; if ($oid !== null) { $this->$k = $oid; } if ($this->$k == NULL) { return false; } $query = 'UPDATE ' . $this->_db->quoteName($this->_tbl) . ' SET locked_by = 0, locked_on = "' . $this->_db->escape($this->_db->getNullDate()) . '" WHERE ' . $this->_tbl_key . ' = "' . $this->_db->escape($this->$k) . '"'; $this->_db->setQuery($query); $this->locked_by = 0; $this->locked_on = ''; return $this->_db->execute(); } /** * Check if an item is checked out * * This function can be used as a static function too, when you do so you need to also provide the * a value for the $against parameter. * * @static * @access public * @param integer $with The userid to preform the match with, if an item is checked out * by this user the function will return false * @param integer $against The userid to perform the match against when the function is used as * a static function. * @return boolean */ function isCheckedOut($with = 0, $against = null) { if (isset($this) && is_a($this, 'VmTable') && is_null($against)) { $against = $this->get('locked_by'); } //item is not checked out, or being checked out by the same user if (!$against || $against == $with) { return false; } $session = VmTable::getInstance('session'); return $session->exists($against); } /** * toggle (0/1) a field * or invert by $val * @author impleri * @author Max Milbers * @param string $field the field to toggle * @param boolean $val field value (0/1) * @todo could make this multi-id as well... */ function toggle($field, $val = NULL) { if ($val === NULL) { $this->$field = !$this->$field; } else { $this->$field = $val; } $k = $this->_tbl_key; $q = 'UPDATE `' . $this->_tbl . '` SET `' . $field . '` = "' . $this->$field . '" WHERE `' . $k . '` = "' . $this->$k . '" '; $this->_db->setQuery($q); if (!$res = $this->_db->execute()) { vmError('There was an error toggling ' . $field, $this->_db->getErrorMsg()); } else { vmdebug('Toggled '.$q ); } return $res; } public function resetErrors() { $this->_errors = array(); } // author stAn // returns true when mysql version is larger than 5.0 function isMysql51Plus() { $r = $this->getMysqlVersion(); return version_compare($r, '5.1.0', '>='); } // author: stan, added in 2.0.16+ // returns mysql version for query optimalization function getMysqlVersion() { $q = 'select version()'; if (!isset($this->_cache[md5($q)])) { $this->_db->setQuery($q); return $this->_db->loadResult(); } else return $this->_cache[md5($q)]; } /** * Add, change or drop userfields * * @param string $_act Action: ADD, DROP or CHANGE (synonyms available, see the switch cases) * @param string $_col Column name * @param string $_type fieldtype * @param string $_col2 Second Column name * @return boolean True on success * @author Oscar van Eijk * * stAn - note: i disabled deleting of user data when a column (shopper field) is deleted. If a deletion of specific user or order is needed, it can be done separatedly * The column if not set with $_col2 will be renamed to ORIGINALNAME_DELETED_{timestamp()} and depending on mysql version it's definition will change */ function _modifyColumn($_act, $_col, $_type = '', $_col2 = '') { if(!vmAccess::manager('core')) return false; $_sql = 'ALTER TABLE `' . $this->_tbl . '` '; $_check_act = strtoupper(substr($_act, 0, 3)); //Check if a column is there //$columns = $this->_db->getTableColumns($this->_tbl); $columns = $this->showFullColumns('Field','Type',false); $res = array_key_exists($_col, $columns); if ($_check_act != 'ADD' and $_check_act != 'CRE') { if (!$res) { vmdebug('_modifyColumn Command was ' . $_check_act . ' column does not exist, changed to ADD'); $_check_act = 'ADD'; } } else { if ($res) { vmdebug('_modifyColumn Command was ' . $_check_act . ' column already exists, changed to MOD'); $_check_act = 'UPD'; } } switch ($_check_act) { case 'ADD': case 'CRE': // Create $_sql .= 'ADD `'.$_col.'` '.$_type.' '; break; case 'DRO': // Drop case 'DEL': // Delete //stAn, i strongly do not recommend to delete customer information only because a field was deleted if (empty($_col2)){ $_col2 = $_col . '_DELETED_' . time(); vmInfo('Be aware the column of table '.$this->_tbl.' is not deleted, only renamed to '.$_col2); } if (!$this->isMysql51Plus()) { if (empty($_type)) $_type = 'TEXT CHARACTER SET utf8'; } // NOT NULL not allowed for deleted columns //$t_type = str_ireplace(' NOT ', '', $_type); $_sql .= 'CHANGE `'.$_col.'` `'.$_col2.'` '.$_type.' '; //was: $_sql .= "DROP $_col "; break; case 'MOD': // Modify case 'UPD': // Update case 'CHA': // Change if (empty($col2)) $_col2 = $_col; // change type only $_sql .= 'CHANGE `'.$_col.'` `'.$_col2.'` '.$_type.' '; break; } $this->_db->setQuery($_sql); $this->_db->execute(); if ($this->_db->getErrorNum() != 0) { vmError(get_class($this) . '::modify table - ' . $this->_db->getErrorMsg() . '
values: action ' . $_act . ', columname: ' . $_col . ', type: ' . $_type . ', columname2: ' . $_col2); return false; } vmdebug('_modifyColumn executed successfully ' . $_sql); return true; } /** * Method to lock the database table for writing. * @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved. * @return boolean True on success. * * @since 11.1 * @throws JDatabaseException */ protected function _lock() { $this->_db->lockTable($this->_tbl); $this->_locked = true; return true; } /** * Method to unlock the database table for writing. * @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved. * @return boolean True on success. * * @since 11.1 */ protected function _unlock() { $this->_db->unlockTables(); $this->_locked = false; return true; } /** * Method to compute the default name of the asset. * The default name is in the form table_name.id * where id is the value of the primary key of the table. * @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved. * @return string * * @since 11.1 */ protected function _getAssetName() { $k = $this->_tbl_key; return $this->_tbl . '.' . (int) $this->$k; } /** * Method to return the title to use for the asset table. In * tracking the assets a title is kept for each asset so that there is some * context available in a unified access manager. Usually this would just * return $this->title or $this->name or whatever is being used for the * primary name of the row. If this method is not overridden, the asset name is used. * @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved. * @return string The string to use as the title in the asset table. * * @link http://docs.joomla.org/JTable/getAssetTitle * @since 11.1 */ protected function _getAssetTitle() { return $this->_getAssetName(); } /** * Method to get the parent asset under which to register this one. * By default, all assets are registered to the ROOT node with ID, * which will default to 1 if none exists. * The extended class can define a table and id to lookup. If the * asset does not exist it will be created. * @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved. * @param JTable $table A JTable object for the asset parent. * @param integer $id Id to look up * * @return integer * * @since 11.1 */ protected function _getAssetParentId($table = null, $id = null) { // For simple cases, parent to the asset root. $assets = self::getInstance('Asset', 'VmTable', array('dbo' => $this->getDbo())); $rootId = $assets->getRootId(); if (!empty($rootId)) { return $rootId; } return 1; } public function reset() { $this->showFullColumns(); } /** * Method to set rules for the record. * * @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved. * @param mixed $input A JAccessRules object, JSON string, or array. * @return void * @since 11.1 */ public function setRules($input) { if ($input instanceof JAccessRules) { $this->_rules = $input; } else { $this->_rules = new JAccessRules($input); } } /** * Method to get the rules for the record. * * @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved. * @return JAccessRules object * @since 11.1 */ public function getRules() { return $this->_rules; } /** * Implement JObservableInterface: * Adds an observer to this instance. * This method will be called fron the constructor of classes implementing JObserverInterface * which is instanciated by the constructor of $this with JObserverMapper::attachAllObservers($this) * @copyright Copyright (C) 2014 Open Source Matters, Inc. All rights reserved. * @param JObserverInterface|JTableObserver $observer The observer object * * @return void * * @since 3.1.2 */ public function attachObserver(JObserverInterface $observer) { $this->_observers->attachObserver($observer); } }