PageRenderTime 55ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/administrator/components/com_virtuemart/helpers/vmtable.php

https://github.com/srgg6701/auction-ruseasons
PHP | 1451 lines | 946 code | 245 blank | 260 comment | 212 complexity | f2a70d877e182f71d26d513b977c2371 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-3.0, LGPL-2.1, BSD-3-Clause, JSON
  1. <?php
  2. /**
  3. * virtuemart table class, with some additional behaviours.
  4. *
  5. *
  6. * @package VirtueMart
  7. * @subpackage Helpers
  8. * @author Max Milbers
  9. * @copyright Copyright (c) 2011 VirtueMart Team. All rights reserved.
  10. * @license http://www.gnu.org/copyleft/gpl.html GNU/GPL, see LICENSE.php
  11. * VirtueMart is free software. This version may have been modified pursuant
  12. * to the GNU General Public License, and as distributed it includes or
  13. * is derivative of works licensed under the GNU General Public License or
  14. * other free or open source software licenses.
  15. * See /administrator/components/com_virtuemart/COPYRIGHT.php for copyright notices and details.
  16. *
  17. * http://virtuemart.net
  18. */
  19. defined('_JEXEC') or die();
  20. jimport('joomla.user.user');
  21. /**
  22. * Replaces JTable with some more advanced functions and fitting to the nooku conventions
  23. *
  24. * checked_out = locked_by,checked_time = locked_on
  25. *
  26. * Enter description here ...
  27. * @author Milbo
  28. *
  29. */
  30. class VmTable extends JTable{
  31. protected $_pkey = '';
  32. protected $_pkeyForm = '';
  33. protected $_obkeys = array();
  34. protected $_unique = false;
  35. protected $_unique_name = array();
  36. protected $_orderingKey = 'ordering';
  37. // var $_useSlug = false;
  38. protected $_slugAutoName = '';
  39. protected $_slugName = '';
  40. protected $_loggable = false;
  41. protected $_xParams = 0;
  42. protected $_varsToPushParam = array();
  43. var $_translatable = false;
  44. protected $_translatableFields = array();
  45. static $_cache = null;
  46. static $_query_cache = null;
  47. function __construct( $table, $key, &$db ){
  48. $this->_tbl = $table;
  49. $this->_tbl_key = $key;
  50. $this->_db =& $db;
  51. $this->_pkey = $key;
  52. $this->_cache = null;
  53. $this->_query_cache = null;
  54. }
  55. function setPrimaryKey($key, $keyForm=0){
  56. $error = JText::sprintf('COM_VIRTUEMART_STRING_ERROR_PRIMARY_KEY', JText::_('COM_VIRTUEMART_' . strtoupper($key)));
  57. $this->setObligatoryKeys('_pkey', $error);
  58. $this->_pkey = $key;
  59. $this->_pkeyForm = empty($keyForm) ? $key : $keyForm;
  60. $this->$key = 0;
  61. }
  62. public function setObligatoryKeys($key){
  63. $error = JText::sprintf('COM_VIRTUEMART_STRING_ERROR_OBLIGATORY_KEY', JText::_('COM_VIRTUEMART_' . strtoupper($key)));
  64. $this->_obkeys[$key] = $error;
  65. }
  66. public function setUniqueName($name){
  67. $error = JText::sprintf('COM_VIRTUEMART_STRING_ERROR_NOT_UNIQUE_NAME', JText::_('COM_VIRTUEMART_' . strtoupper($name)));
  68. $this->_unique = true;
  69. $this->_obkeys[$name] = $error;
  70. $this->_unique_name[$name] = $error;
  71. }
  72. public function setLoggable(){
  73. $this->_loggable = true;
  74. $this->created_on = false;
  75. $this->created_by = 0;
  76. $this->modified_on = '';
  77. $this->modified_by = 0;
  78. }
  79. /**
  80. *
  81. * @author Patrick Kohl,
  82. * @author Max Milbers
  83. */
  84. public function setTranslatable($langFields){
  85. $this->_translatableFields = $langFields;
  86. $this->_translatableFields['slug'] = 'slug';
  87. $this->_translatable = true;
  88. if(!defined('VMLANG')){
  89. if (!class_exists( 'VmConfig' ))
  90. /* MODIFIED START */
  91. require(JPATH_ADMINISTRATOR.DS.'components'.DS.'com_virtuemart'.DS.'helpers'.DS.'config.php');
  92. // Заменено:
  93. // с JPATH_COMPONENT_ADMINISTRATOR
  94. // на JPATH_ADMINISTRATOR.DS.'components'.DS.'com_virtuemart'
  95. /* MODIFIED END */
  96. //require(JPATH_COMPONENT_ADMINISTRATOR.DS.'helpers'.DS.'config.php');
  97. VmConfig::loadConfig();
  98. }
  99. $this->_langTag = VMLANG;
  100. $this->_tbl_lang = $this->_tbl.'_'.$this->_langTag;
  101. }
  102. public function getTranslatableFields(){
  103. return $this->_translatableFields;
  104. }
  105. public function setLockable(){
  106. $this->locked_on = '';
  107. $this->locked_by = 0;
  108. }
  109. function setOrderable($key='ordering', $auto=true){
  110. $this->_orderingKey = $key;
  111. $this->_orderable = 1;
  112. $this->_autoOrdering = $auto;
  113. $this->$key = 0;
  114. }
  115. function setSlug($slugAutoName, $key = 'slug'){
  116. // $this->_useSlug = true;
  117. $this->_slugAutoName = $slugAutoName;
  118. $this->_slugName = $key;
  119. $this->$key = '';
  120. $this->setUniqueName($key);
  121. }
  122. /**
  123. * This function defines a database field as parameter field, which means that some values get injected there
  124. * As delimiters are used | for the pair and = for key, value
  125. *
  126. * @author Max Milbers
  127. * @param string $paramsFieldName
  128. * @param string $varsToPushParam
  129. */
  130. function setParameterable($paramsFieldName,$varsToPushParam,$overwrite = false){
  131. if($this->_xParams===0) $this->_xParams = $paramsFieldName;
  132. if($overwrite){
  133. $this->_varsToPushParam = $varsToPushParam;
  134. } else {
  135. $this->_varsToPushParam = array_merge((array)$varsToPushParam,(array)$this->_varsToPushParam);
  136. }
  137. foreach($this->_varsToPushParam as $k=>$v){
  138. if(!isset($this->$k))$this->$k = $v[0];
  139. }
  140. //vmdebug('setParameterable called '.$this->_xParams,$this->_varsToPushParam);
  141. }
  142. var $_tablePreFix = '';
  143. function setTableShortCut($prefix){
  144. $this->_tablePreFix = $prefix.'.';
  145. }
  146. /**
  147. * Load the fieldlist
  148. */
  149. public function loadFields()
  150. {
  151. $_fieldlist = array();
  152. $_q = 'SHOW COLUMNS FROM `'.$this->_tbl.'`';
  153. if (!isset(self::$_query_cache[md5($_q)]))
  154. {
  155. $this->_db->setQuery($_q);
  156. $_fields = $this->_db->loadObjectList();
  157. }
  158. else $_fields = self::$_query_cache[md5($_q)];
  159. if (count($_fields) > 0) {
  160. foreach ($_fields as $key => $_f) {
  161. $_fieldlist[$_f->Field] = $_f->Default;
  162. }
  163. $this->setProperties($_fieldlist);
  164. }
  165. }
  166. /**
  167. * Get the columns from database table.
  168. *
  169. * adjusted to vm2, We use the same, except that the cache is not a global static,.. we use static belonging to table
  170. * @return mixed An array of the field names, or false if an error occurs.
  171. *
  172. * @since 11.1
  173. */
  174. public function getFields()
  175. {
  176. if ($this->_cache === null)
  177. {
  178. // Lookup the fields for this table only once.
  179. $name = $this->_tbl;
  180. $fields = $this->_db->getTableColumns($name, false);
  181. if (empty($fields))
  182. {
  183. $e = new JException(JText::_('JLIB_DATABASE_ERROR_COLUMNS_NOT_FOUND'));
  184. $this->setError($e);
  185. return false;
  186. }
  187. $this->_cache = $fields;
  188. }
  189. return $this->_cache;
  190. }
  191. function checkDataContainsTableFields($from, $ignore=array()){
  192. if(empty($from))
  193. return false;
  194. $fromArray = is_array($from);
  195. $fromObject = is_object($from);
  196. if(!$fromArray && !$fromObject){
  197. vmError(get_class($this) . '::check if data contains table fields failed. Invalid from argument <pre>' . print_r($from, 1) . '</pre>');
  198. return false;
  199. }
  200. if(!is_array($ignore)){
  201. $ignore = explode(' ', $ignore);
  202. }
  203. foreach($this->getProperties() as $k => $v){
  204. // internal attributes of an object are ignored
  205. if(!in_array($k, $ignore)){
  206. if($fromArray && isset($from[$k])){
  207. return true;
  208. }else if($fromObject && isset($from->$k)){
  209. return true;
  210. }
  211. }
  212. }
  213. vmdebug('VmTable developer notice, table ' . get_class($this) . ' means that there is no data to store. When you experience that something does not get stored as expected, please write in the forum.virtuemart.net');
  214. return false;
  215. }
  216. function setLoggableFieldsForStore(){
  217. if($this->_loggable){
  218. // set default values always used
  219. //We store in UTC time, dont touch it!
  220. $date = JFactory::getDate();
  221. $today = $date->toMySQL();
  222. //vmdebug('my today ',$date);
  223. $user = JFactory::getUser();
  224. $pkey = $this->_pkey;
  225. //Lets check if the user is admin or the mainvendor
  226. if(!class_exists('Permissions')) require(JPATH_VM_ADMINISTRATOR.DS.'helpers'.DS.'permissions.php');
  227. $admin = Permissions::getInstance()->check('admin');
  228. if($admin){
  229. if(empty($this->$pkey) and empty($this->created_on)){
  230. $this->created_on = $today;
  231. }
  232. if(empty($this->$pkey) and empty($this->created_by)){
  233. $this->created_by = $user->id;
  234. }
  235. } else {
  236. if(empty($this->$pkey)){
  237. $this->created_on = $today;
  238. $this->created_by = $user->id;
  239. }
  240. }
  241. //ADDED BY P2 PETER
  242. if($this->created_on=="0000-00-00 00:00:00"){
  243. $this->created_on = $this->$today;
  244. }
  245. //END ADD
  246. $this->modified_on = $today;
  247. $this->modified_by = $user->id;
  248. }
  249. if(isset($this->locked_on)){
  250. //Check if user is allowed to store, then disable or prevent storing
  251. $this->locked_on = 0;
  252. }
  253. }
  254. /**
  255. * Technic to inject params as table attributes
  256. * @author Max Milbers
  257. * $TableJoins array of table names to add and left join to find ID
  258. */
  259. function load($oid=null,$overWriteLoadName=0,$andWhere=0,$tableJoins= array(),$joinKey = 0){
  260. if($overWriteLoadName!=0){
  261. $k = $overWriteLoadName;
  262. } else {
  263. $k = $this->_pkey;
  264. }
  265. if ($oid !== null) {
  266. $this->$k = $oid;
  267. } else {
  268. $oid = $this->$k;
  269. }
  270. // vmdebug('load '.$oid);
  271. if ($oid === null) {
  272. $oid = 0;
  273. }
  274. else if(empty($oid)){
  275. if(!empty($this->_xParams)){
  276. foreach($this->_varsToPushParam as $key=>$v){
  277. if(!isset($this->$key)){
  278. $this->$key = $v[0];
  279. }
  280. }
  281. }
  282. return $this;
  283. }
  284. //Why we have this reset? it is calling getFields, which is calling getTableColumns, which is calling SHOW COLUMNS, which is slow
  285. //
  286. //$this->reset();
  287. //Version load the tables using JOIN
  288. if($this->_translatable){
  289. $mainTable = $this->_tbl.'_'.VMLANG ;
  290. $select = 'SELECT `'.$mainTable.'`.* ,`'.$this->_tbl.'`.* ';
  291. $from = ' FROM `'.$mainTable.'` JOIN '.$this->_tbl.' using (`'.$this->_tbl_key.'`)';
  292. } else {
  293. $mainTable = $this->_tbl ;
  294. $select = 'SELECT `'.$mainTable.'`.* ';
  295. $from = ' FROM `'.$mainTable .'` ';
  296. }
  297. if (count($tableJoins)) {
  298. if (!$joinKey) $joinKey = $this->_tbl_key ;
  299. foreach ($tableJoins as $tableId => $table) {
  300. $select .= ',`'.$table.'`.`'.$tableId.'` ';
  301. $from .= ' LEFT JOIN `'.$table.'` on `'.$table.'`.`'.$joinKey.'`=`'. $mainTable .'`.`'.$joinKey.'`';
  302. }
  303. }
  304. //the cast to int here destroyed the query for keys like virtuemart_userinfo_id, so no cast on $oid
  305. // $query = $select.$from.' WHERE '. $mainTable .'.`'.$this->_tbl_key.'` = "'.$oid.'"';
  306. $query = $select.$from.' WHERE '. $mainTable .'.`'.$k.'` = "'.$oid.'"';
  307. if (!isset(self::$_query_cache[md5($query)]))
  308. {
  309. $db = $this->getDBO();
  310. $db->setQuery( $query );
  311. $result = $db->loadAssoc( );
  312. self::$_cache[md5($query)] = $result;
  313. $error = $db->getErrorMsg();
  314. }
  315. else
  316. {
  317. $result = self::$_cache[md5($query)];
  318. }
  319. // vmdebug('vmtable load '.$db->getQuery(),$result);
  320. if(!empty($error )){
  321. vmError('vmTable load' . $error );
  322. return false;
  323. }
  324. //vmdebug('load',$result );
  325. if($result){
  326. $this->bind($result);
  327. if(!empty($this->_xParams)){
  328. //Maybe better to use for $this an &
  329. self::bindParameterable($this,$this->_xParams,$this->_varsToPushParam);
  330. }
  331. if (count($tableJoins)) {
  332. foreach ($tableJoins as $tableId => $table) {
  333. if(isset( $result[$tableId] )) $this->$tableId = $result[$tableId];
  334. }
  335. }
  336. }
  337. return $this;
  338. }
  339. static function bindParameterable(&$obj,$xParams,$varsToPushParam){
  340. //$paramFields = $obj->$xParams;
  341. //vmdebug('$obj->_xParams '.$xParams.' $obj->$xParams ',$paramFields);
  342. if(!empty($obj->$xParams)){
  343. // if(strpos($obj->$xParams,'|')!==false){
  344. $params = explode('|', $obj->$xParams);
  345. foreach($params as $item){
  346. $item = explode('=',$item);
  347. $key = $item[0];
  348. unset($item[0]);
  349. $item = implode('=',$item);
  350. if(!empty($item) && isset($varsToPushParam[$key][1]) ){
  351. $obj->$key = json_decode($item);
  352. }
  353. }
  354. /* } else {
  355. $params = json_decode($obj->$xParams);
  356. foreach($params as $key=>$item){
  357. if(!empty($item) && isset($varsToPushParam[$key][1]) ){
  358. $obj->$key = $item;
  359. }
  360. //unset($item[0]);
  361. }
  362. }
  363. */
  364. } else {
  365. if(empty($xParams)){
  366. vmdebug('There are bindParameterables, but $xParams is emtpy, this is a programmers error '.$obj);
  367. }
  368. }
  369. foreach($varsToPushParam as $key=>$v){
  370. if(!isset($obj->$key)){
  371. $obj->$key = $v[0];
  372. }
  373. }
  374. }
  375. /**
  376. * Technic to inject params as table attributes
  377. * @author Max Milbers
  378. */
  379. function store($updateNulls = false){
  380. $this->setLoggableFieldsForStore();
  381. $this->storeParams();
  382. return parent::store($updateNulls);
  383. }
  384. function storeParams(){
  385. if(!empty($this->_xParams)){
  386. $paramFieldName = $this->_xParams;
  387. $this->$paramFieldName = '';
  388. foreach($this->_varsToPushParam as $key=>$v){
  389. if(isset($this->$key)){
  390. $this->$paramFieldName .= $key.'='.json_encode($this->$key).'|';
  391. } else {
  392. $this->$paramFieldName .= $key.'='.json_encode($v[0]).'|';
  393. }
  394. unset($this->$key);
  395. }
  396. }
  397. return true;
  398. }
  399. function checkCreateUnique($tbl_name,$name){
  400. $i = 0;
  401. while($i<20){
  402. $tbl_key = $this->_tbl_key;
  403. $q = 'SELECT `'.$name.'` FROM `'.$tbl_name.'` WHERE `'.$name.'` = "'.$this->$name.'" AND `'.$this->_tbl_key.'`!='.$this->$tbl_key ;
  404. // stAn: using cache can be dangerous here if the function is called twice with an update in between
  405. if (!isset(self::$_query_cache[md5($q)]))
  406. {
  407. $this->_db->setQuery($q);
  408. $existingSlugName =$this->_db->loadResult();
  409. }
  410. else $existingSlugName = self::$_query_cache[md5($q)];
  411. if(!empty($existingSlugName)){
  412. if($i==0){
  413. if(JVM_VERSION===1) $this->$name = $this->$name . JFactory::getDate()->toFormat("%Y-%m-%d-%H-%M-%S").'_';
  414. else $this->$name = $this->$name . JFactory::getDate()->format('Y-m-d-H-i-s').'_';
  415. } else{
  416. $this->$name = $this->$name.rand(1,9);
  417. }
  418. } else {
  419. return true;
  420. }
  421. $i++;
  422. }
  423. return false;
  424. }
  425. /**
  426. * @author Max Milbers
  427. * @param
  428. */
  429. function check(){
  430. if(!empty($this->_slugAutoName)){
  431. $slugAutoName = $this->_slugAutoName; // product_name
  432. //
  433. $slugName = $this->_slugName; // slug
  434. if(in_array($slugAutoName,$this->_translatableFields)){
  435. $checkTable = $this->_tbl.'_'.VMLANG;
  436. } else {
  437. $checkTable = $this->_tbl; // #__virtuemart_products_ru_ru
  438. }
  439. if(empty($this->$slugName)){
  440. //vmdebug('table check use _slugAutoName '.$slugAutoName.' '.$slugName);
  441. if(!empty($this->$slugAutoName)){ // VmTableData()->product_name
  442. $this->$slugName = $this->$slugAutoName;
  443. } else {
  444. // !$this->product
  445. //echo "<div class=''>slugAutoName= ".$slugAutoName."</div>";
  446. //var_dump($this->$slugAutoName);
  447. //var_dump($this);
  448. //echo ('LINE: '.__LINE__);
  449. vmError('VmTable '.$checkTable.' Check not passed. Neither slug nor obligatory value at '.$slugAutoName.' for auto slug creation is given');
  450. // .'<br>slugName = '.$slugName.', slugAutoName var_name = '.$slugAutoName
  451. return false;
  452. }
  453. }
  454. //if (!class_exists('VmMediaHandler')) require(JPATH_VM_ADMINISTRATOR.DS.'helpers'.DS.'mediahandler.php');
  455. //vmdebug('check $slug before stringURLSafe',$this->$slugName);
  456. //$this->$slugName = vmFile::makeSafe( $this->$slugName );
  457. //$lang = JFactory::getLanguage();
  458. //$this->$slugName = $lang->transliterate($this->$slugName);
  459. if(JVM_VERSION===1) $this->$slugName = JFilterOutput::stringURLSafe($this->$slugName);
  460. else $this->$slugName = JApplication::stringURLSafe($this->$slugName);
  461. $valid = $this->checkCreateUnique($checkTable,$slugName);
  462. if(!$valid){
  463. return false;
  464. }
  465. }
  466. foreach($this->_obkeys as $obkeys => $error){
  467. if(empty($this->$obkeys)){
  468. if(empty($error)){
  469. $error = 'Serious error cant save ' . $this->_tbl . ' without ' . $obkeys;
  470. }else {
  471. // $error = get_class($this).' '.JText::_($error);
  472. $error = get_class($this).' '.$error;
  473. }
  474. $this->setError($error);
  475. vmError($error);
  476. return false;
  477. }
  478. }
  479. if($this->_unique){
  480. if(empty($this->_db))$this->_db = JFactory::getDBO();
  481. foreach($this->_unique_name as $obkeys => $error){
  482. if(empty($this->$obkeys)){
  483. // vmError(JText::sprintf('COM_VIRTUEMART_NON_UNIQUE_KEY',$this->$obkeys));
  484. $this->setError($error);
  485. vmError('Non unique '.$this->_unique_name.' '.$error);
  486. return false;
  487. } else {
  488. $valid = $this->checkCreateUnique($this->_tbl,$obkeys);
  489. if(!$valid){
  490. return false;
  491. }
  492. }
  493. }
  494. }
  495. if(isset($this->virtuemart_vendor_id )){
  496. $multix = Vmconfig::get('multix','none');
  497. //Lets check if the user is admin or the mainvendor
  498. if(!class_exists('Permissions')) require(JPATH_VM_ADMINISTRATOR.DS.'helpers'.DS.'permissions.php');
  499. $virtuemart_vendor_id = false;
  500. if( $multix == 'none' and get_class($this)!=='TableVmusers'){
  501. $this->virtuemart_vendor_id = 1;
  502. } else {
  503. $loggedVendorId = Permissions::getInstance()->isSuperVendor();
  504. $admin = Permissions::getInstance()->check('admin');
  505. $tbl_key = $this->_tbl_key ;
  506. if(get_class($this)!=='TableVmusers'){
  507. $q = 'SELECT `virtuemart_vendor_id` FROM `' . $this->_tbl . '` WHERE `' . $this->_tbl_key.'`="'.$this->$tbl_key.'" ';
  508. if (!isset(self::$_query_cache[md5($q)]))
  509. {
  510. $this->_db->setQuery($q);
  511. $virtuemart_vendor_id = $this->_db->loadResult();
  512. }
  513. else $virtuemart_vendor_id = self::$_query_cache[md5($q)];
  514. } else {
  515. $q = 'SELECT `virtuemart_vendor_id`,`user_is_vendor` FROM `' . $this->_tbl . '` WHERE `' . $this->_tbl_key.'`="'.$this->$tbl_key.'" ';
  516. if (!isset(self::$_query_cache[md5($q)]))
  517. {
  518. $this->_db->setQuery($q);
  519. $vmuser = $this->_db->loadRow();
  520. }
  521. else $vmuser = self::$_query_cache[md5($q)];
  522. if($vmuser and count($vmuser)===2){
  523. $virtuemart_vendor_id = $vmuser[0];
  524. $user_is_vendor = $vmuser[1];
  525. if($multix == 'none' ){
  526. if(empty($user_is_vendor)){
  527. $this->virtuemart_vendor_id = 0;
  528. } else {
  529. $this->virtuemart_vendor_id = 1;
  530. }
  531. return true;
  532. } else {
  533. if (!$admin) {
  534. $this->virtuemart_vendor_id = $loggedVendorId;
  535. return true;
  536. }
  537. }
  538. }
  539. }
  540. if(!$admin and !empty($virtuemart_vendor_id) and !empty($loggedVendorId) and $loggedVendorId!=$virtuemart_vendor_id ){
  541. //vmWarn('COM_VIRTUEMART_NOT_SAME_VENDOR',$loggedVendorId,$virtuemart_vendor_id
  542. //vmWarn('Stop try to hack this store, you got logged');
  543. vmdebug('Hacking attempt stopped, logged vendor '.$loggedVendorId.' but data belongs to '.$virtuemart_vendor_id);
  544. return false;
  545. } else if (!$admin) {
  546. if($virtuemart_vendor_id){
  547. $this->virtuemart_vendor_id = $virtuemart_vendor_id;
  548. vmdebug('Non admin is storing using loaded vendor_id');
  549. } else {
  550. //No id is stored, even users are allowed to use for the storage and vendorId, no change
  551. }
  552. } else if (!empty($virtuemart_vendor_id) and $loggedVendorId!=$virtuemart_vendor_id) {
  553. vmInfo('Admin with vendor id '.$loggedVendorId.' is using for storing vendor id '.$this->virtuemart_vendor_id);
  554. vmdebug('Admin with vendor id '.$loggedVendorId.' is using for storing vendor id '.$this->virtuemart_vendor_id);
  555. $this->virtuemart_vendor_id = $virtuemart_vendor_id;
  556. }
  557. }
  558. //tables to consider for multivendor
  559. //if(get_class($this)!== 'TableOrders' and get_class($this)!== 'TableInvoices' and get_class($this)!== 'TableOrder_items'){
  560. }
  561. return true;
  562. }
  563. /**
  564. * As shortcut, Important the & MUST be there, even in php5.3
  565. *
  566. * @author Max Milbers
  567. * @param array/obj $data input data as assoc array or obj
  568. * @param boolean $preload You can preload the data here too preserve not updated data
  569. * @return array/obj $data the updated data
  570. */
  571. public function bindChecknStore(&$data,$preload=false){
  572. $tblKey = $this->_tbl_key; //virtuemart_product_id, OK
  573. $ok = true;
  574. if($this->_translatable){ // 1
  575. // components\com_virtuemart\helpers\vmtabledata.php:
  576. if(!class_exists('VmTableData'))
  577. require(JPATH_VM_ADMINISTRATOR.DS.'helpers'.DS.'vmtabledata.php');
  578. $db = JFactory::getDBO();
  579. $langTable = new VmTableData($this->_tbl_lang,$tblKey,$db);
  580. $langTable->setPrimaryKey($tblKey);
  581. $langData = array();
  582. $langObKeys = array();
  583. $langUniqueKeys = array();
  584. if(is_object($data)){
  585. foreach($this->_translatableFields as $name){
  586. if(!empty($data->$name)){
  587. $langData[$name] = $data->$name;
  588. } else {
  589. $langData[$name] = '';
  590. }
  591. unset($this->$name);
  592. if(!empty($this->_unique_name[$name])){
  593. $langUniqueKeys[$name] = JText::sprintf('COM_VIRTUEMART_STRING_ERROR_NOT_UNIQUE_NAME', JText::_('COM_VIRTUEMART_' . strtoupper($name)));
  594. unset($this->_unique_name[$name]);
  595. $langObKeys[$name] = JText::sprintf('COM_VIRTUEMART_STRING_ERROR_OBLIGATORY_KEY', JText::_('COM_VIRTUEMART_' . strtoupper($name)));
  596. unset($this->_obkeys[$name]);
  597. }
  598. if(!empty($this->_obkeys[$name])){
  599. $langObKeys[$name] = JText::sprintf('COM_VIRTUEMART_STRING_ERROR_OBLIGATORY_KEY', JText::_('COM_VIRTUEMART_' . strtoupper($name)));
  600. unset($this->_obkeys[$name]);
  601. }
  602. }
  603. // $langTable->$tblKey = $data->$tblKey;
  604. } else {
  605. foreach($this->_translatableFields as $name){
  606. if(!empty($data[$name])){
  607. $langData[$name] = $data[$name];
  608. } else {
  609. $langData[$name] = '';
  610. }
  611. unset($this->$name);
  612. if(!empty($this->_unique_name[$name])){
  613. $langUniqueKeys[$name] = JText::sprintf('COM_VIRTUEMART_STRING_ERROR_NOT_UNIQUE_NAME', JText::_('COM_VIRTUEMART_' . strtoupper($name)));
  614. unset($this->_unique_name[$name]);
  615. $langObKeys[$name] = JText::sprintf('COM_VIRTUEMART_STRING_ERROR_OBLIGATORY_KEY', JText::_('COM_VIRTUEMART_' . strtoupper($name)));
  616. unset($this->_obkeys[$name]);
  617. }
  618. if(!empty($this->_obkeys[$name])){
  619. $langObKeys[$name] = JText::sprintf('COM_VIRTUEMART_STRING_ERROR_OBLIGATORY_KEY', JText::_('COM_VIRTUEMART_' . strtoupper($name)));
  620. unset($this->_obkeys[$name]);
  621. }
  622. }
  623. // $langTable->$tblKey = $data[$tblKey];
  624. }
  625. $langTable->_unique_name = $langUniqueKeys;
  626. $langTable->_obkeys = $langObKeys;
  627. $langTable->_slugAutoName = $this->_slugAutoName;
  628. unset($this->_slugAutoName);
  629. $langTable->_slugName = 'slug';
  630. unset($this->_slugName);
  631. $langTable->setProperties($langData);
  632. $langTable->_translatable = false;
  633. //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)
  634. //echo "<div class=''>ok (bindChecknStore(), ".__LINE__.")= ".$ok."</div>";
  635. if($ok){
  636. //vmdebug('my langtable before bind',$langTable->id);
  637. if(!$langTable->bind($data)){
  638. $ok = false;
  639. $msg = 'bind';
  640. // vmdebug('Problem in bind '.get_class($this).' '.$this->_db->getErrorMsg());
  641. vmdebug('Problem in bind '.get_class($this).' ');
  642. }
  643. //echo "<div class=''>ok (bindChecknStore(), ".__LINE__.")= ".$ok."</div>";
  644. }
  645. if($ok){
  646. if(!$langTable->check()){
  647. $ok = false;
  648. echo "<div class=''>ok FALSE (bindChecknStore(), ".__LINE__.")= ".$ok."</div>";
  649. vmdebug('Check returned false '.get_class($langTable).' '.$this->_tbl.' '.$langTable->_db->getErrorMsg());
  650. //var_dump($langTable);
  651. }
  652. }
  653. if($ok){
  654. $this->bindChecknStoreNoLang($data,$preload);
  655. $langTable->$tblKey = !empty($this->$tblKey) ? $this->$tblKey : 0;
  656. //vmdebug('bindChecknStoreNoLang my $tblKey '.$tblKey.' '.$langTable->$tblKey);
  657. if($ok and $preload){
  658. if(!empty($langTable->$tblKey)){
  659. $id = $langTable->$tblKey;
  660. if(!$langTable->load($id)){
  661. $ok = false;
  662. vmdebug('Preloading of language table failed, no id given, cannot store '.$this->_tbl);
  663. }
  664. }
  665. }
  666. if($ok){
  667. if(!$langTable->bind($data)){
  668. $ok = false;
  669. vmdebug('Problem in bind '.get_class($this).' ');
  670. }
  671. }
  672. if($ok){
  673. if(!$langTable->check()){
  674. $ok = false;
  675. vmdebug('Check returned false '.get_class($langTable).' '.$this->_tbl.' '.$langTable->_db->getErrorMsg());
  676. }
  677. }
  678. if($ok){
  679. if(!$langTable->store()){
  680. $ok = false;
  681. // $msg .= ' store';
  682. vmdebug('Problem in store with langtable '.get_class($langTable).' with '.$tblKey.' = '.$this->$tblKey.' '.$langTable->_db->getErrorMsg());
  683. }
  684. }
  685. }
  686. } else {
  687. if(!$this->bindChecknStoreNoLang($data,$preload)){
  688. $ok= false;
  689. }
  690. }
  691. echo "<div class=''>ok (bindChecknStore(), ".__LINE__.")= ".$ok."</div>";
  692. return $ok;
  693. }
  694. function bindChecknStoreNoLang(&$data,$preload=false){
  695. $tblKey = $this->_tbl_key;
  696. if($preload){
  697. if(is_object($data)){
  698. if(!empty($data->$tblKey)){
  699. $this->load($data->$tblKey);
  700. }
  701. }else {
  702. if(!empty($data[$tblKey])){
  703. $this->load($data[$tblKey]);
  704. }
  705. }
  706. if($this->_translatable){
  707. foreach( $this->_translatableFields as $name){
  708. unset($this->$name);
  709. }
  710. }
  711. //vmdebug('bindChecknStoreNoLang language unloaded, why?');
  712. }
  713. $ok = true;
  714. $msg = '';
  715. if(!$this->bind($data)){
  716. $ok = false;
  717. $msg = 'bind';
  718. // vmdebug('Problem in bind '.get_class($this).' '.$this->_db->getErrorMsg());
  719. vmdebug('Problem in bind '.get_class($this).' ');
  720. }
  721. if($ok){
  722. if(!$this->checkDataContainsTableFields($data)){
  723. $ok = false;
  724. // $msg .= ' developer notice:: checkDataContainsTableFields';
  725. }
  726. }
  727. if($ok){
  728. if(!$this->check()){
  729. $ok = false;
  730. $msg .= ' check';
  731. vmdebug('Check no lang returned false '.get_class($this).' '.$this->_db->getErrorMsg());
  732. return false;
  733. }
  734. }
  735. if($ok){
  736. if(!$this->store()){
  737. $ok = false;
  738. $msg .= ' store';
  739. vmdebug('Problem in store '.get_class($this).' '.$this->_db->getErrorMsg());
  740. return false;
  741. }
  742. }
  743. if(is_object($data)){
  744. $data->$tblKey = !empty($this->$tblKey) ? $this->$tblKey : 0;
  745. }else {
  746. $data[$tblKey] = !empty($this->$tblKey) ? $this->$tblKey : 0;
  747. }
  748. // vmdebug('bindChecknStore '.get_class($this).' '.$this->_db->getErrorMsg());
  749. //This should return $ok and not the data, because it is already updated due use of reference
  750. return $data;
  751. }
  752. /**
  753. * Description
  754. * will make sure that all items in the table are not using the same ordering values
  755. * @author stAn
  756. * @access public
  757. * $where -> limits the categories if a child category of another one
  758. */
  759. function fixOrdering($where='')
  760. {
  761. $where = $where ? ' WHERE ' . $where : '';
  762. // fast check for duplicities
  763. $q = 'SELECT `'.$this->_tbl_key.'` FROM `'.$this->_tbl.'` GROUP BY `'.$this->_orderingKey.'` HAVING COUNT(*) >= 2 '.$where.' LIMIT 1';
  764. $this->_db->setQuery($q);
  765. $res = $this->_db->loadAssocList();
  766. if (empty($res)) return true;
  767. $q = ' SELECT `'.$this->_tbl_key.'` FROM `'.$this->_tbl.'` '.$where.' ORDER BY `'.$this->_orderingKey.'` ASC';
  768. $this->_db->setQuery($q, 0, 999999);
  769. $res = $this->_db->loadAssocList();
  770. $e = $this->_db->getErrorMsg(); if (!empty($e)) {
  771. vmError(get_class($this) . $e);
  772. }
  773. echo $q."<br />\n";
  774. // no data in the table
  775. if (empty($res)) return true;
  776. // we will set ordering to 5,10,15,20,25 so there is enough space in between for manual editing
  777. $start = 5;
  778. // it is not really optimized to load full table into array, a while loop would be better especially when having thousands of categories
  779. foreach ($res as $row)
  780. {
  781. $q = 'UPDATE `'.$this->_tbl.'` SET `'.$this->_orderingKey.'` = '.(int)$start.' WHERE `'.$this->_tbl_key.'`= '.$row[$this->_tbl_key].' LIMIT 1';
  782. $this->_db->setQuery($q);
  783. $r = $this->_db->query($q);
  784. $start = $start + 5;
  785. }
  786. }
  787. /**
  788. * Description
  789. *
  790. * @author Joomla Team, Max Milbers
  791. * @access public
  792. * @param $dirn
  793. * @param $where
  794. */
  795. function move($dirn, $where='', $orderingkey=0){
  796. // for some reason this function is not used from categories
  797. $this->fixOrdering();
  798. $k = $this->_tbl_key;
  799. // problem here was that $this->$k returned (0)
  800. $cid = JRequest::getVar('cid');
  801. if (!empty($cid) && (is_array($cid)))
  802. {
  803. $cid = reset($cid);
  804. }
  805. else
  806. {
  807. // either we fix custom fields or fix it here:
  808. $cid = JRequest::getVar('virtuemart_custom_id');
  809. if (!empty($cid) && (is_array($cid)))
  810. {
  811. $cid = reset($cid);
  812. }
  813. else
  814. {
  815. vmError(get_class($this) . ' is missing cid information !');
  816. return false;
  817. }
  818. }
  819. // 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)
  820. $q = "SELECT `".$this->_orderingKey.'` FROM `'.$this->_tbl.'` WHERE `'.$this->_tbl_key."` = '".(int)$cid."' limit 0,1";
  821. if (!isset(self::$_query_cache[md5($q)]))
  822. {
  823. $this->_db->setQuery($q);
  824. $c_order = $this->_db->loadResult(); // current ordering value of cid
  825. } else { $c_order = self::$_query_cache[md5($q)]; }
  826. $this->$orderingkey = $c_order;
  827. $e = $this->_db->getErrorMsg(); if (!empty($e)) {
  828. vmError(get_class($this) . $e);
  829. }
  830. // stAn addition:
  831. $where .= ' `'.$this->_tbl_key.'` <> '.(int)$cid.' ';
  832. // explanation:
  833. // select one above or under which is not cid and update/set it's ordering of the original cid
  834. // could be done with one complex query... but this is more straitforward and the speed is not that much needed in this one
  835. if(!empty($orderingkey))
  836. $this->_orderingKey = $orderingkey;
  837. if(!in_array($this->_orderingKey, array_keys($this->getProperties()))){
  838. vmError(get_class($this) . ' does not support ordering');
  839. return false;
  840. }
  841. $k = $this->_tbl_key; // virtuemart_userfield_id column name
  842. $orderingKey = $this->_orderingKey; // ordering column name
  843. $sql = 'SELECT `' . $this->_tbl_key . '`, `' . $this->_orderingKey . '` FROM ' . $this->_tbl;
  844. if($dirn < 0){
  845. $sql .= ' WHERE `' . $this->_orderingKey . '` <= ' . (int)$c_order;
  846. $sql .= ( $where ? ' AND ' . $where : '');
  847. $sql .= ' ORDER BY `' . $this->_orderingKey . '` DESC';
  848. }else if($dirn > 0){
  849. $sql .= ' WHERE `' . $this->_orderingKey . '` >= ' . (int)$c_order;
  850. $sql .= ( $where ? ' AND ' . $where : '');
  851. $sql .= ' ORDER BY `' . $this->_orderingKey . '`';
  852. }else {
  853. $sql .= ' WHERE `' . $this->_orderingKey . '` = ' . (int)$c_order;
  854. $sql .= ( $where ? ' AND ' . $where : '');
  855. $sql .= ' ORDER BY `' . $this->_orderingKey . '`';
  856. }
  857. if (!isset(self::$_query_cache[md5($sql)]))
  858. {
  859. $this->_db->setQuery($sql, 0, 1);
  860. $row = null;
  861. $row = $this->_db->loadObject();
  862. }
  863. else $row = self::$_query_cache[md5($sql)];
  864. if(isset($row)){
  865. // ok, we have a problem here - previous or next item has the same ordering as the current one
  866. // we need to fix the ordering be reordering it all
  867. if ((int)$row->$orderingKey == $c_order)
  868. {
  869. // if we fix this while loading the ordering, it will slow down FE
  870. }
  871. // update the next or previous to have the same ordering as the selected
  872. $query = 'UPDATE ' . $this->_tbl
  873. . ' SET `' . $this->_orderingKey . '` = ' . (int)$c_order
  874. . ' WHERE ' . $this->_tbl_key . ' = ' . (int)$row->$k . ' LIMIT 1'
  875. ;
  876. $this->_db->setQuery($query);
  877. echo "\n".$query.'<br />';
  878. if(!$this->_db->query()){
  879. $err = $this->_db->getErrorMsg();
  880. JError::raiseError(500, get_class( $this ).':: move isset row $row->$k'.$err);
  881. }
  882. // update the currently selected to have the same ordering as the next or previous
  883. $query = 'UPDATE ' . $this->_tbl
  884. . ' SET `' . $this->_orderingKey . '` = ' . (int)$row->$orderingKey
  885. . ' WHERE ' . $this->_tbl_key . ' = "' . (int)$cid . '" LIMIT 1'
  886. ;
  887. $this->_db->setQuery($query);
  888. //echo $query.'<br />'; die();
  889. if(!$this->_db->query()){
  890. $err = $this->_db->getErrorMsg();
  891. JError::raiseError(500, get_class( $this ).':: move isset row $row->$k'.$err);
  892. }
  893. // stAn, what for is this?
  894. $this->ordering = $row->$orderingKey;
  895. }else {
  896. // stAn: why should we update the same line with the same information when no next or previous found (?)
  897. $query = 'UPDATE ' . $this->_tbl
  898. . ' SET `' . $this->_orderingKey . '` = ' . (int)$this->$orderingKey
  899. . ' WHERE ' . $this->_tbl_key . ' = "' . $this->_db->getEscaped($this->$k) . '" LIMIT 1'
  900. ;
  901. $this->_db->setQuery($query);
  902. if(!$this->_db->query()){
  903. $err = $this->_db->getErrorMsg();
  904. JError::raiseError(500, get_class( $this ).':: move update $this->$k'. $err);
  905. }
  906. }
  907. return true;
  908. }
  909. /**
  910. * Returns the ordering value to place a new item last in its group
  911. *
  912. * @access public
  913. * @param string query WHERE clause for selecting MAX(ordering).
  914. */
  915. function getNextOrder($where='', $orderingkey = 0){
  916. $where = $this->_db->getEscaped($where);
  917. $orderingkey = $this->_db->getEscaped($orderingkey);
  918. if(!empty($orderingkey))
  919. $this->_orderingKey = $orderingkey;
  920. if(!in_array($this->_orderingKey, array_keys($this->getProperties()))){
  921. vmError(get_class($this) . ' does not support ordering');
  922. return false;
  923. }
  924. $query = 'SELECT MAX(`' . $this->_orderingKey . '`)' .
  925. ' FROM ' . $this->_tbl .
  926. ($where ? ' WHERE ' . $where : '');
  927. if (!isset(self::$_query_cache[md5($query)]))
  928. {
  929. $this->_db->setQuery($query);
  930. $maxord = $this->_db->loadResult();
  931. }
  932. else $maxord = self::$_query_cache[md5($query)];
  933. if($this->_db->getErrorNum()){
  934. vmError(get_class($this) . ' getNextOrder ' . $this->_db->getErrorMsg());
  935. return false;
  936. }
  937. return $maxord + 1;
  938. }
  939. /**
  940. * Compacts the ordering sequence of the selected records
  941. *
  942. * @access public
  943. * @param string Additional where query to limit ordering to a particular subset of records
  944. */
  945. function reorder($where='', $orderingkey = 0){
  946. $where = $this->_db->getEscaped($where);
  947. $orderingkey = $this->_db->getEscaped($orderingkey);
  948. if(!empty($orderingkey))
  949. $this->_orderingKey = $orderingkey;
  950. $k = $this->_tbl_key;
  951. if(!in_array($this->_orderingKey, array_keys($this->getProperties()))){
  952. vmError(get_class($this) . ' does not support ordering');
  953. return false;
  954. }
  955. if($this->_tbl == '#__content_frontpage'){
  956. $order2 = ", content_id DESC";
  957. }else {
  958. $order2 = "";
  959. }
  960. $query = 'SELECT ' . $this->_tbl_key . ', ' . $this->_orderingKey
  961. . ' FROM ' . $this->_tbl
  962. . ' WHERE `' . $this->_orderingKey . '` >= 0' . ( $where ? ' AND ' . $where : '' )
  963. . ' ORDER BY `' . $this->_orderingKey . '` ' . $order2
  964. ;
  965. $this->_db->setQuery($query);
  966. if(!($orders = $this->_db->loadObjectList())){
  967. vmError(get_class($this) . ' reorder ' . $this->_db->getErrorMsg());
  968. return false;
  969. }
  970. $orderingKey = $this->_orderingKey;
  971. // compact the ordering numbers
  972. for($i = 0, $n = count($orders); $i < $n; $i++){
  973. if($orders[$i]->$orderingKey >= 0){
  974. if($orders[$i]->$orderingKey != $i + 1){
  975. $orders[$i]->$orderingKey = $i + 1;
  976. $query = 'UPDATE ' . $this->_tbl
  977. . ' SET `' . $this->_orderingKey . '` = "' . $this->_db->getEscaped($orders[$i]->$orderingKey) . '"
  978. WHERE ' . $k . ' = "' . $this->_db->getEscaped($orders[$i]->$k) . '"'
  979. ;
  980. $this->_db->setQuery($query);
  981. $this->_db->query();
  982. }
  983. }
  984. }
  985. return true;
  986. }
  987. /**
  988. * Checks out a row
  989. *
  990. * @access public
  991. * @param integer The id of the user
  992. * @param mixed The primary key value for the row
  993. * @return boolean True if successful, or if checkout is not supported
  994. */
  995. function checkout($who, $oid = null){
  996. if(!in_array('locked_by', array_keys($this->getProperties()))){
  997. return true;
  998. }
  999. $k = $this->_tbl_key;
  1000. if($oid !== null){
  1001. $this->$k = $oid;
  1002. }
  1003. $config = JFactory::getConfig();
  1004. $siteOffset = $config->getValue('config.offset');
  1005. $date = JFactory::getDate('now', $siteOffset);
  1006. $time = $date->toMysql();
  1007. $query = 'UPDATE ' . $this->_db->nameQuote($this->_tbl) .
  1008. ' SET locked_by = ' . (int)$who . ', locked_on = "' . $this->_db->getEscaped($time) . '"
  1009. WHERE ' . $this->_tbl_key . ' = "' . $this->_db->getEscaped($this->$k) . '"';
  1010. $this->_db->setQuery($query);
  1011. $this->locked_by = $who;
  1012. $this->locked_on = $time;
  1013. return $this->_db->query();
  1014. }
  1015. /**
  1016. * Checks in a row
  1017. *
  1018. * @access public
  1019. * @param mixed The primary key value for the row
  1020. * @return boolean True if successful, or if checkout is not supported
  1021. */
  1022. function checkin($oid=null){
  1023. if(!(
  1024. in_array('locked_by', array_keys($this->getProperties())) ||
  1025. in_array('locked_on', array_keys($this->getProperties()))
  1026. )){
  1027. return true;
  1028. }
  1029. $k = $this->_tbl_key;
  1030. if($oid !== null){
  1031. $this->$k = $oid;
  1032. }
  1033. if($this->$k == NULL){
  1034. return false;
  1035. }
  1036. $query = 'UPDATE ' . $this->_db->nameQuote($this->_tbl) .
  1037. ' SET locked_by = 0, locked_on = "' . $this->_db->getEscaped($this->_db->getNullDate()) . '"
  1038. WHERE ' . $this->_tbl_key . ' = "' . $this->_db->getEscaped($this->$k) . '"';
  1039. $this->_db->setQuery($query);
  1040. $this->locked_by = 0;
  1041. $this->locked_on = '';
  1042. return $this->_db->query();
  1043. }
  1044. /**
  1045. * Check if an item is checked out
  1046. *
  1047. * This function can be used as a static function too, when you do so you need to also provide the
  1048. * a value for the $against parameter.
  1049. *
  1050. * @static
  1051. * @access public
  1052. * @param integer $with The userid to preform the match with, if an item is checked out
  1053. * by this user the function will return false
  1054. * @param integer $against The userid to perform the match against when the function is used as
  1055. * a static function.
  1056. * @return boolean
  1057. */
  1058. function isCheckedOut($with = 0, $against = null){
  1059. if(isset($this) && is_a($this, 'JTable') && is_null($against)){
  1060. $against = $this->get('locked_by');
  1061. }
  1062. //item is not checked out, or being checked out by the same user
  1063. if(!$against || $against == $with){
  1064. return false;
  1065. }
  1066. $session = JTable::getInstance('session');
  1067. return $session->exists($against);
  1068. }
  1069. /**
  1070. * toggle (0/1) a field
  1071. * or invert by $val
  1072. * @author impleri
  1073. * @author Max Milbers
  1074. * @param string $field the field to toggle
  1075. * @param boolean $val field value (0/1)
  1076. * @todo could make this multi-id as well...
  1077. */
  1078. function toggle($field, $val = NULL){
  1079. if($val === NULL){
  1080. $this->$field = !$this->$field;
  1081. }else {
  1082. $this->$field = $val;
  1083. }
  1084. $k = $this->_tbl_key;
  1085. $q = 'UPDATE `'.$this->_tbl.'` SET `'.$field.'` = "'.$this->$field.'" WHERE `'.$k.'` = "'.$this->$k.'" ';
  1086. $this->_db->setQuery($q);
  1087. vmdebug('toggle '.$q);
  1088. return ($this->_db->query());
  1089. }
  1090. public function resetErrors(){
  1091. $this->_errors = array();
  1092. }
  1093. // TODO add Translatable delete ???
  1094. //
  1095. function delete( $oid=null , $where = 0 ){
  1096. $k = $this->_tbl_key;
  1097. if ($oid) {
  1098. $this->$k = intval( $oid );
  1099. }
  1100. $mainTableError = $this->checkAndDelete($this->_tbl,$where);
  1101. if($this->_translatable){
  1102. $langs = VmConfig::get('active_languages',array()) ;
  1103. if (!$langs) $langs[]= VMLANG;
  1104. if(!class_exists('VmTableData'))require(JPATH_VM_ADMINISTRATOR.DS.'helpers'.DS.'vmtabledata.php');
  1105. foreach($langs as $lang){
  1106. $lang = strtolower(strtr($lang,'-','_'));
  1107. $langError = $this->checkAndDelete($this->_tbl.'_'.$lang);
  1108. $mainTableError = min($mainTableError,$langError);
  1109. }
  1110. }
  1111. return $mainTableError;
  1112. }
  1113. // author stAn
  1114. // returns true when mysql version is larger than 5.0
  1115. function isMysql51Plus()
  1116. {
  1117. $r = $this->getMysqlVersion();
  1118. return version_compare($r, '5.1.0', '>=');
  1119. }
  1120. // author: stan, added in 2.0.16+
  1121. // returns mysql version for query optimalization
  1122. function getMysqlVersion()
  1123. {
  1124. $q = 'select version()';
  1125. if (!isset(self::$_query_cache[md5($q)]))
  1126. {
  1127. $this->_db->setQuery($q);
  1128. return $this->_db->loadResult();
  1129. }
  1130. else return self::$_query_cache[md5($q)];
  1131. }
  1132. function checkAndDelete($table,$where = 0){
  1133. $ok = 1;
  1134. $k = $this->_tbl_key;
  1135. if($where!==0){
  1136. $whereKey = $where;
  1137. } else {
  1138. $whereKey = $this->_pkey;
  1139. }
  1140. $query = 'SELECT `'.$this->_tbl_key.'` FROM `'.$table.'` WHERE '.$whereKey.' = "' .$this->$k . '"';
  1141. $this->_db->setQuery( $query );
  1142. // vmdebug('checkAndDelete',$query);
  1143. $list = $this->_db->loadResultArray();
  1144. // vmdebug('checkAndDelete',$list);
  1145. if($list){
  1146. foreach($list as $row){
  1147. $ok = $row;
  1148. $query = 'DELETE FROM `'.$table.'` WHERE '.$this->_tbl_key.' = "'.$row.'"';
  1149. $this->_db->setQuery( $query );
  1150. if (!$this->_db->query()){
  1151. $this->setError($this->_db->getErrorMsg());
  1152. vmError('checkAndDelete '.$this->_db->getErrorMsg());
  1153. $ok = 0;
  1154. }
  1155. }
  1156. }
  1157. return $ok;
  1158. }
  1159. /**
  1160. * Add, change or drop userfields
  1161. *
  1162. * @param string $_act Action: ADD, DROP or CHANGE (synonyms available, see the switch cases)
  1163. * @param string $_col Column name
  1164. * @param string $_type Fieldtype
  1165. * @return boolean True on success
  1166. * @author Oscar van Eijk
  1167. *
  1168. * 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
  1169. * The column if not set with $_col2 will be renamed to ORIGINALNAME_DELETED_{timestamp()} and depending on mysql version it's definition will change
  1170. */
  1171. function _modifyColumn ($_act, $_col, $_type = '', $_col2='')
  1172. {
  1173. $_sql = "ALTER TABLE `".$this->_tbl."` ";
  1174. $_check_act = strtoupper(substr($_act, 0, 3));
  1175. switch ($_check_act) {
  1176. case 'ADD':
  1177. case 'CRE': // Create
  1178. $_sql .= "ADD $_col $_type ";
  1179. break;
  1180. case 'DRO': // Drop
  1181. case 'DEL': // Delete
  1182. //stAn, i strongly do not recommend to delete customer information only because a field was deleted
  1183. if (empty($_col2)) $_col2 = $_col.'_DELETED_'.time();
  1184. if (!$this->isMysql51Plus())
  1185. if (empty($_type)) $_type = 'TEXT CHARACTER SET utf8';
  1186. // NOT NULL not allowed for deleted columns
  1187. $t_type = str_ireplace(' NOT ', '', $_type);
  1188. $_sql .= "CHANGE $_col $_col2 $_type ";
  1189. //was: $_sql .= "DROP $_col ";
  1190. break;
  1191. case 'MOD': // Modify
  1192. case 'UPD': // Update
  1193. case 'CHA': // Change
  1194. if (empty($col2)) $_col2 = $_col; // change type only
  1195. $_sql .= "CHANGE $_col $_col2 $_type ";
  1196. break;
  1197. }
  1198. $this->_db->setQuery($_sql);
  1199. $this->_db->query();
  1200. if ($this->_db->getErrorNum() != 0) {
  1201. vmError(get_class( $this ).'::modify table - '.$this->_db->getErrorMsg());
  1202. return false;
  1203. }
  1204. return true;
  1205. }
  1206. }