PageRenderTime 51ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/components/com_fabrik/models/list.php

https://github.com/danimara/fabrik
PHP | 6768 lines | 4793 code | 620 blank | 1355 comment | 1060 complexity | 1abb393149b25aa8800bebd08992558f MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
  1. <?php
  2. /**
  3. * @package Joomla
  4. * @subpackage Fabrik
  5. * @copyright Copyright (C) 2005 Rob Clayburn. All rights reserved.
  6. * @license http://www.gnu.org/copyleft/gpl.html GNU/GPL, see LICENSE.php
  7. */
  8. // Check to ensure this file is included in Joomla!
  9. defined('_JEXEC') or die();
  10. jimport('joomla.application.component.modelform');
  11. require_once(COM_FABRIK_FRONTEND.DS.'helpers'.DS.'pagination.php');
  12. require_once(COM_FABRIK_FRONTEND.DS.'helpers'.DS.'string.php');
  13. require_once(COM_FABRIK_FRONTEND.DS.'helpers'.DS.'joomfish.php');
  14. class FabrikFEModelList extends JModelForm {
  15. /** @var int id of table to load */
  16. public $id = null;
  17. /** @var int package id */
  18. public $packageId = null;
  19. /** @var object the tables connection object */
  20. protected $_oConn = null;
  21. /** @var object table Table */
  22. protected $_table = null;
  23. /** @var object table's form model */
  24. protected $_oForm = null;
  25. /** @var array joins */
  26. protected $_aJoins = null;
  27. /** @var array column calculations */
  28. protected $_aRunCalculations = array();
  29. /** @var string table output format - set to rss to collect correct element data within function gettData()*/
  30. protected $_outPutFormat = 'html';
  31. protected $isMambot = false;
  32. /** @var object to contain access rights **/
  33. protected $_access = null;
  34. /** @var int the id of the last inserted record (or if updated the last record updated) **/
  35. public $lastInsertId = null;
  36. /** @var array store data to create joined records from */
  37. protected $_joinsToProcess = null;
  38. /** @var array database fields */
  39. protected $_dbFields = null;
  40. /** @var bol force reload table calculations **/
  41. protected $_reloadCalculations = false;
  42. /** @var array data contains request data **/
  43. protected $_aData = null;
  44. /**
  45. * @since 3.0 replaces _postMethod
  46. * @var bool is ajax used */
  47. protected $ajax = null;
  48. /** @var object plugin manager */
  49. protected $_pluginManager = null;
  50. /** @var string join sql **/
  51. protected $_joinsSQL = null;
  52. /** @var array order by column names **/
  53. var $orderByFields = null;
  54. /** @var bol is the object inside a package? */
  55. //var $_inPackage = false;
  56. protected $_joinsToThisKey = null;
  57. protected $_real_filter_action = null;
  58. /** array merged request and session data used to potentially filter the table **/
  59. protected $_request = null;
  60. protected $_aRow = null;
  61. /** array rows to delete **/
  62. protected $_rowsToDelete = null;
  63. /** @var array original table data BEFORE form saved - used to ensure uneditable data is stored */
  64. protected $_origData = null;
  65. /** @var bol set to true to load records STARTING from a random id (used in the getPageNav func) **/
  66. public $randomRecords = false;
  67. protected $_data = null;
  68. var $nav = null;
  69. var $fields = null;
  70. var $prefilters = null;
  71. var $filters = null;
  72. var $aJoinsToThisKey = null;
  73. var $canSelectRows = null;
  74. var $asfields = null;
  75. var $_temp_db_key_addded = false;
  76. var $_group_by_added = false;
  77. var $_pluginQueryWhere = array();
  78. var $_pluginQueryGroupBy = array();
  79. /** @var bol is the table a view **/
  80. var $_isview = null;
  81. /** @var array index objects **/
  82. var $_indexes = null;
  83. /** @var array previously submitted advanced search data */
  84. var $advancedSearchRows = null;
  85. /** @var string table action url */
  86. var $tableAction = null;
  87. /** @var bool doing CSV import */
  88. var $_importingCSV = false;
  89. var $encrypt = array();
  90. /** @var int which record to start showing from */
  91. var $limitStart = null;
  92. /** @var int # records to show */
  93. var $limitLength = null;
  94. protected $rows = null;
  95. /** @var bool should a heading be added for action buttons (returns true if at least one row has buttons)*/
  96. protected $actionHeading = false;
  97. /**
  98. * Constructor
  99. *
  100. * @since 1.5
  101. */
  102. public function getForm($data = array(), $loadData = true)
  103. {
  104. // Get the form.
  105. $form = $this->loadForm('com_fabrik.list', 'view', array('control' => 'jform', 'load_data' => $loadData));
  106. if (empty($form)) {
  107. return false;
  108. }
  109. return $form;
  110. }
  111. function __construct()
  112. {
  113. parent::__construct();
  114. $usersConfig = JComponentHelper::getParams('com_fabrik');
  115. $id = JRequest::getInt('listid', $usersConfig->get('listid'));
  116. $this->packageId = (int)JRequest::getInt('packageid', $usersConfig->get('packageid'));
  117. $this->setId($id);
  118. $this->_access = new stdClass();
  119. }
  120. /**
  121. * process the table plug-ins
  122. * @return array of table plug-in result messages
  123. */
  124. function processPlugin()
  125. {
  126. $pluginManager =& $this->getPluginManager();
  127. $pluginManager->runPlugins('process', $this, 'list');
  128. return $pluginManager->_data;
  129. }
  130. /**
  131. * get the html that is outputted by table plug-in buttons
  132. *
  133. * @return array buttons
  134. */
  135. function getPluginButtons()
  136. {
  137. $pluginManager =& $this->getPluginManager();
  138. $pluginManager->getPlugInGroup('list');
  139. $pluginManager->runPlugins('button', $this, 'list');
  140. $buttons = $pluginManager->_data;
  141. $this->getPluginJsClasses();
  142. return $buttons;
  143. }
  144. function getPluginJsClasses()
  145. {
  146. $pluginManager =& $this->getPluginManager();
  147. $pluginManager->getPlugInGroup('list');
  148. $pluginManager->runPlugins('loadJavascriptClass', $this, 'list');
  149. }
  150. function getPluginJsObjects($container = null)
  151. {
  152. if (is_null($container)) {
  153. $container = "listform_".$this->getId();
  154. }
  155. $pluginManager =& $this->getPluginManager();
  156. $pluginManager->getPlugInGroup('list');
  157. $pluginManager->runPlugins('loadJavascriptInstance', $this, 'list', $container);
  158. return $pluginManager->_data;
  159. }
  160. /**
  161. * main query to build table
  162. *
  163. */
  164. function render()
  165. {
  166. FabrikHelperHTML::debug($_POST, 'render:post');
  167. global $_PROFILER;
  168. $id = $this->getId();
  169. if (is_null($id) || $id == '0') {
  170. return JError::raiseError(500, JText::_('COM_FABRIK_INCORRECT_LIST_ID'));
  171. }
  172. $this->_outPutFormat = JRequest::getVar('format', 'html');
  173. if ($this->_outPutFormat == 'fabrikfeed') {
  174. $this->_outPutFormat = 'feed';
  175. }
  176. $item =& $this->getTable();
  177. if ($item->db_table_name == '') {
  178. return JError::raiseError(500, JText::_('COM_FABRIK_INCORRECT_LIST_ID'));
  179. }
  180. //cant set time limit in safe mode so suppress warning
  181. @set_time_limit(60);
  182. //$this->getRequestData();
  183. JDEBUG ? $_PROFILER->mark('About to get table filter') : null;
  184. $filters =& $this->getFilterArray();
  185. JDEBUG ? $_PROFILER->mark('Got filters') : null;
  186. $this->setLimits();
  187. $this->setElementTmpl();
  188. $this->getData();
  189. JDEBUG ? $_PROFILER->mark('got data') : null;
  190. //think we really have to do these as the calc isnt updated when the table is filtered
  191. $this->doCalculations();
  192. JDEBUG ? $_PROFILER->mark('done calcs') : null;
  193. $this->getCalculations();
  194. JDEBUG ? $_PROFILER->mark('got cacls') : null;
  195. $item->hit();
  196. }
  197. /**
  198. * set the navigation limit and limitstart
  199. */
  200. function setLimits()
  201. {
  202. $app = JFactory::getApplication();
  203. $item = $this->getTable();
  204. $params = $this->getParams();
  205. $id = $this->getId();
  206. // $$$ rob dont make the key list.X as the registry doesnt seem to like keys with just '1' a
  207. $context = 'com_fabrik.list'.$id.'.';
  208. $limitStart = $this->randomRecords ? $this->getRandomLimitStart() : 0;
  209. // deal with the fact that you can have more than one table on a page so limitstart has to be
  210. // specfic per table
  211. //if table is rendered as a content plugin dont set the limits in the session
  212. if ($app->scope == 'com_content') {
  213. $limitLength = JRequest::getInt('limit'.$id, $item->rows_per_page);
  214. if (!$this->randomRecords) {
  215. $limitStart = JRequest::getInt('limitstart'.$id, $limitStart);
  216. }
  217. } else {
  218. $limitLength = $app->getUserStateFromRequest($context.'limitlength', 'limit'.$id, $item->rows_per_page);
  219. if (!$this->randomRecords) {
  220. $limitStart = $app->getUserStateFromRequest($context.'limitstart', 'limitstart'.$id, $limitStart, 'int');
  221. }
  222. }
  223. if ($this->_outPutFormat == 'feed') {
  224. $limitLength = JRequest::getVar('limit', $params->get('rsslimit',150));
  225. $maxLimit = $params->get('rsslimitmax', 2500);
  226. if ($limitLength > $maxLimit) {
  227. $limitLength = $maxLimit;
  228. }
  229. }
  230. $this->limitLength = $limitLength;
  231. $this->limitStart = $limitStart;
  232. }
  233. /**
  234. * this merges session data for the fromForm with any request data
  235. * allowing us to filter data results from both search forms and filters
  236. *
  237. * @return array
  238. */
  239. function getRequestData()
  240. {
  241. global $_PROFILER;
  242. JDEBUG ? $_PROFILER->mark('start get Request data') : null; // 0.5 sec here!
  243. $f = $this->getFilterModel()->getFilters();
  244. JDEBUG ? $_PROFILER->mark('end get Request data') : null;
  245. return $f;
  246. }
  247. /**
  248. * get the table's filter model
  249. * @return model filter model
  250. */
  251. function &getFilterModel()
  252. {
  253. if (!isset($this->filterModel)) {
  254. $this->filterModel = JModel::getInstance('Listfilter', 'FabrikFEModel');
  255. $this->filterModel->setListModel($this);
  256. }
  257. return $this->filterModel;
  258. }
  259. /**
  260. * $$$ hugh - once we have a few table joins, our select statements are
  261. * getting big enough to hit default select length max in MySQL. Added per-table
  262. * setting to enable_big_selects, 3/16/2010.
  263. */
  264. function setBigSelects()
  265. {
  266. $fabrikDb = $this->getDb();
  267. $params =& $this->getParams();
  268. if ($params->get('enable_big_selects', 0)) {
  269. $fabrikDb->setQuery("SET OPTION SQL_BIG_SELECTS=1");
  270. $fabrikDb->query();
  271. }
  272. }
  273. /**
  274. * get the table's data
  275. *
  276. * @return array of objects (rows)
  277. */
  278. function getData()
  279. {
  280. global $_PROFILER;
  281. $pluginManager =& $this->getPluginManager();
  282. $fbConfig =& JComponentHelper::getParams('com_fabrik');
  283. $pluginManager->runPlugins('onPreLoadData', $this, 'list');
  284. if (isset($this->_data) && !is_null($this->_data)) {
  285. return $this->_data;
  286. }
  287. $traceModel = ini_get('mysql.trace_mode');
  288. ini_set('mysql.trace_mode', 'off'); // needs to be off for FOUND_ROWS() to work
  289. $fabrikDb =& $this->getDb();
  290. JDEBUG ? $_PROFILER->mark('query build start') : null;
  291. $query = $this->_buildQuery();
  292. JDEBUG ? $_PROFILER->mark('query build end') : null;
  293. $this->setBigSelects();
  294. // $$$ rob - if merging joined data then we don't want to limit
  295. // the query as we have already done so in _buildQuery()
  296. if ($this->mergeJoinedData()) {
  297. $fabrikDb->setQuery($query);
  298. } else {
  299. $fabrikDb->setQuery($query, $this->limitStart, $this->limitLength);
  300. }
  301. FabrikHelperHTML::debug($fabrikDb->getQuery(), 'list GetData:' . $this->getTable()->label);
  302. JDEBUG ? $_PROFILER->mark('before query run') : null;
  303. //set 2nd param to false in attempt to stop joomfish db adaptor from translating the orignal query
  304. // fabrik3 - 2nd param in j16 is now used - guessing that joomfish now uses the third param for the false switch?
  305. $this->_data = $fabrikDb->loadObjectList('', 'stdClass', false);
  306. if ($fabrikDb->getErrorNum() != 0) {
  307. jexit('getData:' . $fabrikDb->getErrorMsg());
  308. }
  309. /// $$$ rob better way of getting total records
  310. if ($this->mergeJoinedData()) {
  311. $this->totalRecords = $this->getTotalRecords();
  312. } else {
  313. $fabrikDb->setQuery("SELECT FOUND_ROWS()");
  314. $this->totalRecords = $fabrikDb->loadResult();
  315. }
  316. if ($this->randomRecords) {
  317. shuffle($this->_data);
  318. }
  319. ini_set('mysql.trace_mode', $traceModel);
  320. $nav =& $this->getPagination($this->totalRecords, $this->limitStart, $this->limitLength);
  321. JDEBUG ? $_PROFILER->mark('query run and data loaded') : null;
  322. //@TODO test in J1.7
  323. // $this->translateData($this->_data);
  324. if ($fabrikDb->getErrorNum() != 0) {
  325. JError::raiseNotice(500, 'getData: ' . $fabrikDb->getErrorMsg());
  326. }
  327. JDEBUG ? $_PROFILER->mark('start format data') : null;
  328. $this->formatData($this->_data);
  329. JDEBUG ? $_PROFILER->mark('start format for joins') : null;
  330. $this->formatForJoins($this->_data);
  331. JDEBUG ? $_PROFILER->mark('data formatted') : null;
  332. $pluginManager->runPlugins('onLoadData', $this, 'list');
  333. return $this->_data;
  334. }
  335. function translateData(&$data)
  336. {
  337. $params =& $this->getParams();
  338. if (!JPluginHelper::isEnabled('system', 'jfdatabase')) {
  339. return;
  340. }
  341. if (defined('JOOMFISH_PATH') && $params->get('allow-data-translation')) {
  342. $table = $this->getTable();
  343. $db = FabrikWorker::getDbo();
  344. $jf =& JoomFishManager::getInstance();
  345. $config = JFactory::getConfig();
  346. $tableName = str_replace($config->getValue('dbprefix'), '', $table->db_table_name);
  347. $contentElement =& $jf->getContentElement($tableName);
  348. if (!is_object($contentElement)) {
  349. return;
  350. }
  351. $title = Fabrikstring::shortColName($params->get('joomfish-title'));
  352. $activelangs = $jf->getActiveLanguages();
  353. $registry = JFactory::getConfig();
  354. $langid = $activelangs[$registry->getValue("config.jflang")]->id;
  355. $db->setQuery($contentElement->createContentSQL($langid));
  356. if ($title == '') {
  357. $contentTable = $contentElement->getTable();
  358. foreach ($contentTable->Fields as $tableField) {
  359. if ($tableField->Type == 'titletext') {
  360. $title = $tableField->Name;
  361. }
  362. }
  363. }
  364. $longKey = FabrikString::safeColNameToArrayKey($table->db_primary_key);
  365. $res =& $db->loadObjectList(FabrikString::shortColName($table->db_primary_key));
  366. // $$$ hugh - if no JF results, bail out, otherwise we pitch warnings in the foreach loop.
  367. if (empty($res)) {
  368. return;
  369. }
  370. foreach ($data as &$row) {
  371. //$$$ rob if the id isnt published fall back to __pk_val
  372. $translateRow = array_key_exists($longKey, $row) ? $res[$row->$longKey] : $res[$row->__pk_val];
  373. foreach ($row as $key => $val) {
  374. $shortkey = array_pop(explode("___", $key));
  375. if ($shortkey === $title) {
  376. $row->$key = $translateRow->titleTranslation;
  377. $key = $key ."_raw";
  378. $row->$key = $translateRow->titleTranslation;
  379. } else {
  380. if (array_key_exists($shortkey, $translateRow)) {
  381. $row->$key = $translateRow->$shortkey;
  382. $key = $key ."_raw";
  383. if (array_key_exists($key, $row)) {
  384. $row->$key = $translateRow->$shortkey;
  385. }
  386. }
  387. }
  388. }
  389. }
  390. }
  391. }
  392. /**
  393. * run the table data through element filters
  394. *
  395. * @param array $data
  396. */
  397. function formatData(&$data)
  398. {
  399. global $_PROFILER;
  400. jimport('joomla.filesystem.file');
  401. $form =& $this->getFormModel();
  402. $tableParams =& $this->getParams();
  403. $table =& $this->getTable();
  404. $pluginManager =& $this->getPluginManager();
  405. $method = 'renderListData_' . $this->_outPutFormat;
  406. $this->_aLinkElements = array();
  407. // $$$ hugh - temp foreach fix
  408. $groups = $form->getGroupsHiarachy();
  409. $ec = count($data);
  410. foreach ($groups as $groupModel) {
  411. //$$$ rob pointless getting elemetsnnot shown in the table view?
  412. // $$$ hugh - oops, they might be using elements in group-by template not shown in table
  413. // http://fabrikar.com/forums/showthread.php?p=102600#post102600
  414. // $$$ rob in that case lets test that rather than loading blindly
  415. // $$$ rob 15/02/2011 or out put may be csv in which we want to format any fields not shown in the form
  416. if (($tableParams->get('group_by_template') !== '' && $this->getGroupBy() != '') || $this->_outPutFormat == 'csv' || $this->_outPutFormat == 'feed') {
  417. $elementModels =& $groupModel->getPublishedElements();
  418. } else {
  419. $elementModels =& $groupModel->getPublishedTableElements();
  420. }
  421. foreach ($elementModels as $elementModel) {
  422. $e =& $elementModel->getElement();
  423. $elementModel->setContext($groupModel, $form, $this);
  424. $params =& $elementModel->getParams();
  425. $col = $elementModel->getFullName(false, true, false);
  426. //check if there is a custom out put handler for the tables format
  427. // currently supports "renderListData_csv", "renderListData_rss", "renderListData_html", "renderListData_json"
  428. if (!empty($data) && array_key_exists($col, $data[0])) {
  429. if (method_exists($elementModel, $method)) {
  430. for ($i=0; $i<count($data); $i++) {
  431. $thisRow = $data[$i];
  432. $coldata = $thisRow->$col;
  433. $data[$i]->$col = $elementModel->$method($coldata, $col, $thisRow);
  434. }
  435. } else {
  436. JDEBUG ? $_PROFILER->mark('elements renderListData: ' ."($ec)". " talbeid = $table->id " . $col) : null;
  437. for ($i=0; $i < $ec; $i++) {
  438. $thisRow = $data[$i];
  439. $coldata = $thisRow->$col;
  440. $data[$i]->$col = $elementModel->renderListData($coldata, $thisRow);
  441. $rawCol = $col . "_raw";
  442. // Not sure if this works, as far as I can tell _raw will always exist, even if
  443. // the element model hasn't explicitly done anything with it (except mayeb unsetting it?)
  444. // For instance, the calc element needs to set _raw. For now, I changed $thisRow above to
  445. // be a =& reference to $data[$i], and in renderListData() the calc element modifies
  446. // the _raw entry in $thisRow. I guess it could simply unset the _raw in $thisRow and
  447. // then implement a renderRawTableData. Anyway, just sayin'.
  448. if (!array_key_exists($rawCol, $thisRow)) {
  449. $data[$i]->$rawCol = $elementModel->renderRawTableData($coldata, $thisRow);
  450. }
  451. }
  452. }
  453. }
  454. }
  455. }
  456. JDEBUG ? $_PROFILER->mark('elements rendered for table data') : null;
  457. $this->_aGroupInfo = array();
  458. $groupTitle = array();
  459. $this->grouptemplates = array();
  460. //check if the data has a group by applied to it
  461. $groupBy = $this->getGroupBy();
  462. if ($groupBy != '' && $this->_outPutFormat != 'csv') {
  463. $w = new FabrikWorker();
  464. // 3.0 if not group by template spec'd byt group by assigned in qs then use that as the group by tmpl
  465. $requestGroupBy = JRequest::getCmd('group_by');
  466. if ($requestGroupBy == '') {
  467. $groupTemplate = $tableParams->get('group_by_template');
  468. } else {
  469. $groupTemplate = '{'.$requestGroupBy.'}';
  470. }
  471. $groupedData = array();
  472. $thisGroupedData = array();
  473. $groupBy = FabrikString::safeColNameToArrayKey($groupBy);
  474. // $$$ rob commenting this out as if you group on a date then the group by value doesnt correspond
  475. // to the keys found in the calculation array
  476. //see if we can use a raw value instead
  477. /*if (!empty($data) && array_key_exists($groupBy . "_raw", $data[0])) {
  478. $groupBy = $groupBy . "_raw";
  479. }*/
  480. $groupTitle = null;
  481. $aGroupTitles = array();
  482. $groupId = 0;
  483. for ($i=0; $i <count($data); $i++) {
  484. if (!in_array($data[$i]->$groupBy , $aGroupTitles)) {
  485. $aGroupTitles[] = $data[$i]->$groupBy;
  486. $grouptemplate = $w->parseMessageForPlaceHolder($groupTemplate, JArrayHelper::fromObject($data[$i]));
  487. $this->grouptemplates[$data[$i]->$groupBy] = nl2br($grouptemplate);
  488. $groupedData[$data[$i]->$groupBy] = array();
  489. }
  490. $data[$i]->_groupId = $data[$i]->$groupBy;
  491. $gKey = $data[$i]->$groupBy;
  492. // if the group_by was added in in getAsFields remove it from the returned data set (to avoid mess in package view)
  493. if ($this->_group_by_added) {
  494. unset($data[$i]->$groupBy);
  495. }
  496. if ($this->_temp_db_key_addded) {
  497. $k = $table->db_primary_key;
  498. }
  499. $groupedData[$gKey][] = $data[$i];
  500. }
  501. $data = $groupedData;
  502. } else {
  503. for ($i=0; $i<count($data); $i++) {
  504. if ($this->_temp_db_key_addded) {
  505. $k = $table->db_primary_key;
  506. }
  507. }
  508. //make sure that the none grouped data is in the same format
  509. $data = array($data);
  510. }
  511. JDEBUG ? $_PROFILER->mark('table groupd by applied') : null;
  512. if ($this->_outPutFormat != 'pdf' && $this->_outPutFormat != 'csv' && $this->_outPutFormat != 'feed') {
  513. $this->addSelectBoxAndLinks($data);
  514. FabrikHelperHTML::debug($data, 'table:data');
  515. }
  516. JDEBUG ? $_PROFILER->mark('end format data') : null;
  517. }
  518. /**
  519. * add the select box and various links into the data array
  520. * @param array table row objects
  521. */
  522. function addSelectBoxAndLinks(&$data)
  523. {
  524. $item = $this->getTable();
  525. $app = JFactory::getApplication();
  526. $db = FabrikWorker::getDbo(true);
  527. $params = $this->getParams();
  528. $nextview = ($this->canEdit()) ? "form" : "details";
  529. $tmpKey = '__pk_val';
  530. $factedlinks = $params->get('factedlinks');
  531. //get a list of fabrik tables and ids for view table and form links
  532. $linksToForms = $this->getLinksToThisKey();
  533. $action = $app->isAdmin() ? "task" : "view";
  534. $sql = "SELECT id, label, db_table_name FROM #__{package}_lists";
  535. $db->setQuery($sql);
  536. $aTableNames = $db->loadObjectList('label');
  537. if ($db->getErrorNum()) {
  538. JError::raiseError(500, $db->getErrorMsg());
  539. }
  540. $cx = count($data);
  541. $viewLinkAdded = false;
  542. //get pk values
  543. $pks = array();
  544. foreach ($data as $groupKey=>$group) {
  545. $cg = count($group);
  546. for ($i=0; $i < $cg; $i++) {
  547. $pks[] = @$data[$groupKey][$i]->$tmpKey;
  548. }
  549. }
  550. $joins =& $this->getJoins();
  551. //for ($x=0; $x<$cx; $x++) { //if grouped data then the key is not numeric
  552. foreach ($data as $groupKey=>$group) {
  553. //$group =& $data[$key]; //Messed up in php 5.1 group positioning in data became ambiguous
  554. $cg = count($group);
  555. for ($i=0; $i < $cg; $i++) {
  556. $row =& $data[$groupKey][$i];
  557. $viewLinkAdded = false;
  558. //done each row as its result can change
  559. $canEdit = $this->canEdit($row);
  560. $canView = $this->canView($row);
  561. $canDelete = $this->canDelete($row);
  562. $nextview = $canEdit ? "form" : "details";
  563. $pKeyVal = array_key_exists($tmpKey, $row) ? $row->$tmpKey : '';
  564. $pkcheck = '<div style="display:none">';
  565. foreach ($joins as $join) {
  566. if ($join->list_id !== '0') {
  567. // $$$ rob 22/02/2011 was not using _raw before which was intserting html into the value for image elements
  568. $fkey = $join->table_join_alias.'___'.$join->table_key."_raw";
  569. if (isset($row->$fkey)) {
  570. $fKeyVal= $row->$fkey;
  571. $pkcheck .= '<input type="checkbox" class="fabrik_joinedkey" value="'.$fKeyVal.'" name="'.$join->table_join_alias.'['.$row->__pk_val.']" />'."\n";
  572. }
  573. }
  574. }
  575. $pkcheck .= '</div>';
  576. $row->fabrik_select = $this->canSelectRow($row) ? '<input type="checkbox" id="id_'.$row->__pk_val.'" name="ids['.$row->__pk_val.']" value="'.$pKeyVal.'" />'.$pkcheck : '';
  577. //add in some default links if no element choosen to be a link
  578. $link = $this->viewDetailsLink($data[$groupKey][$i]);//dont use $row as it generates a pas by ref error
  579. $edit_link = $this->editLink($data[$groupKey][$i]);
  580. $row->fabrik_view_url = $link;
  581. $row->fabrik_edit_url = $edit_link;
  582. $editLinkAttribs = $this->getCustomLink('attribs', 'edit');
  583. $detailsLinkAttribs = $this->getCustomLink('attribs', 'details');
  584. $row->fabrik_view = '';
  585. $row->fabrik_edit = '';
  586. $editLabel = $params->get('editlabel', JText::_('COM_FABRIK_EDIT'));
  587. $editLink = "<a class=\"fabrik__rowlink\" $editLinkAttribs href=\"$edit_link\" title=\"$editLabel\">".
  588. FabrikHelperHTML::image('edit.png', 'list', '', $editLabel).
  589. '<span>'.$editLabel.'</span></a>';
  590. $viewLabel = $params->get('detaillabel', JText::_('COM_FABRIK_VIEW'));
  591. $viewLink = "<a class=\"fabrik___rowlink\" $detailsLinkAttribs href=\"$link\" title=\"$viewLabel\">".
  592. FabrikHelperHTML::image('view.png', 'list', '', $viewLabel).
  593. '<span>'.$viewLabel.'</span></a>';
  594. //3.0 actions now in list in one cell
  595. $row->fabrik_actions = array();
  596. if ($canView || $canEdit) {
  597. if ($canEdit == 1) {
  598. if ($params->get('editlink')) {
  599. $row->fabrik_edit = $editLink;
  600. $row->fabrik_actions['fabrik_edit'] = '<li class="fabrik_edit">'.$row->fabrik_edit.'</li>';
  601. }
  602. $row->fabrik_edit_url = $edit_link;
  603. if ($this->canViewDetails() && $params->get('detaillink') == 1) {
  604. $row->fabrik_view = $viewLink;
  605. $row->fabrik_actions['fabrik_view'] = '<li class="fabrik_view">'.$row->fabrik_view.'</li>';
  606. }
  607. } else {
  608. if ($this->canViewDetails() && $params->get('detaillink') == '1') {
  609. if (empty($this->_aLinkElements)) {
  610. $viewLinkAdded = true;
  611. $row->fabrik_view = $viewLink;
  612. $row->fabrik_actions['fabrik_view'] = '<li class="fabrik_view">'.$row->fabrik_view.'</li>';
  613. }
  614. } else {
  615. $row->fabrik_edit = '';
  616. }
  617. }
  618. }
  619. if ($this->canViewDetails() && !$viewLinkAdded && $params->get('detaillink') == '1') {
  620. $link = $this->viewDetailsLink($row, 'details');
  621. $row->fabrik_view_url = $link;
  622. $row->fabrik_view = $viewLink;
  623. $row->fabrik_actions['fabrik_view'] = '<li class="fabrik_view">'.$row->fabrik_view.'</li>';
  624. }
  625. if ($this->deletePossible()) {
  626. $row->fabrik_actions['fabrik_delete'] = $this->deleteButton();
  627. }
  628. // create columns containing links which point to tables associated with this table
  629. $joinsToThisKey = $this->getJoinsToThisKey();
  630. $f = 0;
  631. $keys = isset($factedlinks->linkedlist) ? array_keys(JArrayHelper::fromObject($factedlinks->linkedlist)) : array();
  632. for ($ii=0; $ii <count($joinsToThisKey); $ii++) {
  633. if (!array_key_exists($f, $keys)) {
  634. continue;
  635. }
  636. $join = $joinsToThisKey[$ii];
  637. $linkedTable = $factedlinks->linkedlist->$keys[$f];
  638. $popupLink = $factedlinks->linkedlist_linktype->$keys[$f];
  639. $linkedListText = $factedlinks->linkedlisttext->$keys[$f];
  640. if ($linkedTable != '0') {
  641. $recordKey = $join->element_id."___".$linkedTable;
  642. $key = $recordKey."_list_heading";
  643. $val = $pKeyVal;
  644. $recordCounts =& $this->getRecordCounts($join, $pks);
  645. $count = 0;
  646. $linkKey = '';
  647. if (is_array($recordCounts)) {
  648. if (array_key_exists($val, $recordCounts)) {
  649. $count = $recordCounts[$val]->total;
  650. $linkKey = $recordCounts[$val]->linkKey;
  651. } else {
  652. if (array_key_exists((int)$val, $recordCounts) && (int)$val !== 0) {
  653. $count = $recordCounts[(int)$val]->total;
  654. $linkKey = $recordCounts[$val]->linkKey;
  655. }
  656. }
  657. }
  658. $join->list_id = array_key_exists($join->listlabel, $aTableNames) ? $aTableNames[$join->listlabel]->id : '';
  659. $linkLabel = $this->parseMessageForRowHolder($linkedListText, JArrayHelper::fromObject($row));
  660. $linkKey .= '_raw';
  661. $group[$i]->$key = $this->viewDataLink($popupLink, $join->list_id, $row, $linkKey, $val, $count, $linkLabel);
  662. }
  663. $f ++;
  664. }
  665. $f = 0;
  666. //create columns containing links which point to forms assosciated with this table
  667. foreach ($linksToForms as $join) {
  668. if (array_key_exists($f, $keys)) {
  669. $linkedForm = $factedlinks->linkedform->$keys[$f];
  670. $popupLink = $factedlinks->linkedform_linktype->$keys[$f];
  671. // $$$ hugh @TODO - rob, can you check this, I added this line,
  672. // but the logic applied for $val in the linked table code above seems to be needed?
  673. // http://fabrikar.com/forums/showthread.php?t=9535
  674. $val = $pKeyVal;
  675. if ($linkedForm !== '0') {
  676. if (is_object($join)) {
  677. //$$$rob moved these two lines here as there were giving warnings since Hugh commented out the if ($element != '') {
  678. $linkKey = @$join->db_table_name . "___" . @$join->name;
  679. $gkey = $linkKey . "_form_heading";
  680. $linkLabel = $this->parseMessageForRowHolder($factedlinks->linkedformtext->$keys[$f], JArrayHelper::fromObject($row));
  681. $group[$i]->$gkey = $this->viewFormLink($popupLink, $join->list_id, $join->form_id, $row, $linkKey, $val, false, $linkLabel);
  682. }
  683. }
  684. $f ++;
  685. }
  686. }
  687. }
  688. }
  689. $args['data'] = &$data;
  690. $pluginButtons = $this->getPluginButtons();
  691. foreach ($data as $groupKey=>$group) {
  692. //$group =& $data[$key]; //Messed up in php 5.1 group positioning in data became ambiguous
  693. $cg = count($group);
  694. for ($i=0; $i < $cg; $i++) {
  695. $row =& $data[$groupKey][$i];
  696. foreach ($pluginButtons as $b) {
  697. if (trim($b) !== '') {
  698. $row->fabrik_actions[] = '<li>'.$b.'</li>';
  699. }
  700. }
  701. if (!empty($row->fabrik_actions)) {
  702. $this->actionHeading = true;
  703. $row->fabrik_actions = '<ul class="fabrik_action">'.implode("\n", $row->fabrik_actions).'</ul>';
  704. } else {
  705. $row->fabrik_actions = '';
  706. }
  707. }
  708. }
  709. }
  710. /**
  711. * @since 3.0
  712. * get delete button
  713. */
  714. protected function deleteButton()
  715. {
  716. return '<li class="fabrik_delete"><a href="#" class="delete" title="'.JText::_('COM_FABRIK_DELETE').'">'.
  717. FabrikHelperHTML::image('delete.png', 'list', '', JText::_('COM_FABRIK_DELETE')).
  718. '<span>'.JText::_('COM_FABRIK_DELETE').'</span></a></li>';
  719. }
  720. /**
  721. *
  722. * get a list of possible menus
  723. * USED TO BUILD RELTED TABLE LNKS WITH CORRECT iTEMD AND TEMPLATE
  724. * @return array linked table menu items
  725. * @since 2.0.4
  726. */
  727. protected function getTableLinks()
  728. {
  729. if (isset($this->tableLinks)){
  730. return $this->tableLinks;
  731. }
  732. $db =& JFactory::getDBO();
  733. $joinsToThisKey = $this->getJoinsToThisKey();
  734. if (empty($joinsToThisKey)) {
  735. $this->tableLinks = array();
  736. } else {
  737. $query = "SELECT * FROM #__menu WHERE type = 'component' AND ";
  738. foreach ($joinsToThisKey as $element) {
  739. $linkWhere[] = "link LIKE 'index.php?option=com_fabrik&view=list&listid=".(int)$element->list_id."%'";
  740. }
  741. $query .= '('.implode(' OR ', $linkWhere).')';
  742. $db->setQuery($query);
  743. $this->tableLinks = $db->loadObjectList();
  744. }
  745. return $this->tableLinks;
  746. }
  747. /**
  748. * for releated table links get the record count for each of the table's rows
  749. * @param $element
  750. * @param array primary keys to count on
  751. * @return array counts key'd on element primary key
  752. */
  753. public function getRecordCounts(&$element, $pks = array())
  754. {
  755. if (!isset($this->recordCounts)) {
  756. $this->recordCounts = array();
  757. }
  758. $k = $element->element_id;
  759. if (array_key_exists($k, $this->recordCounts)) {
  760. return $this->recordCounts[$k];
  761. }
  762. $listModel = JModel::getInstance('List', 'FabrikFEModel');
  763. $listModel->setId($element->list_id);
  764. $db =& $listModel->getDb();
  765. $elementModel =& $listModel->getFormModel()->getElement($element->element_id, true);
  766. $key = $elementModel->getFullName(false, false, false);
  767. $linkKey = FabrikString::safeColName($key);
  768. $fparams =& $listModel->getParams();
  769. //ensure that the facte table's require filters option is set to false
  770. $fparams->set('require-filter', false);
  771. //ignore facted tables session filters
  772. $origIncSesssionFilters = JRequest::getVar('fabrik_incsessionfilters', true);
  773. JRequest::setVar('fabrik_incsessionfilters', false);
  774. $where = $listModel->_buildQueryWhere(JRequest::getVar('incfilters', 0));
  775. if (!empty($pks)) {
  776. //only load the current record sets record counts
  777. $where .= trim($where) == '' ? ' WHERE ' : ' AND ';
  778. $where .= "$linkKey IN (" . implode(',', $pks) . ")";
  779. }
  780. $listModel->set('_joinsSQL', null); //force reload of join sql
  781. $listModel->set('includeCddInJoin', false); //trigger load of joins without cdd elements - seems to mess up count otherwise
  782. //see http://fabrikar.com/forums/showthread.php?t=12860
  783. //$totalSql = "SELECT $linkKey AS id, COUNT($linkKey) AS total FROM " . $element->db_table_name . " " . $tableModel->_buildQueryJoin();
  784. $k2 = $db->Quote(FabrikString::safeColNameToArrayKey($key));
  785. //$totalSql = "SELECT $k2 AS linkKey, $linkKey AS id, COUNT($linkKey) AS total FROM " . $listModel->getTable()->db_table_name . " " . $listModel->_buildQueryJoin();
  786. //$$$ Jannus - see http://fabrikar.com/forums/showthread.php?t=20751
  787. $distinct = $listModel->mergeJoinedData() ? 'DISTINCT ' : '';
  788. $totalSql = "SELECT $k2 AS linkKey, $linkKey AS id, COUNT($distinct ".$listModel->getTable()->db_primary_key.") AS total FROM " . $listModel->getTable()->db_table_name . " " . $listModel->_buildQueryJoin();
  789. $totalSql .= " $where GROUP BY $linkKey";
  790. $listModel->set('includeCddInJoin', true);
  791. $db->setQuery($totalSql);
  792. $this->recordCounts[$k] =& $db->loadObjectList('id');
  793. $this->recordCounts[$k]['linkKey'] = FabrikString::safeColNameToArrayKey($key);
  794. FabrikHelperHTML::debug($db->getQuery(), 'getRecordCounts query: '.$linkKey);
  795. FabrikHelperHTML::debug($this->recordCounts[$k], 'getRecordCounts data: '.$linkKey);
  796. JRequest::setVar('fabrik_incsessionfilters', $origIncSesssionFilters);
  797. return $this->recordCounts[$k];
  798. }
  799. /**
  800. * creates the html <a> link allowing you to edit other forms from the table
  801. * E.g. Faceted browsing: those specified in the table's "Form's whose primary keys link to this table"
  802. *
  803. * @param bol $popUp
  804. * @param object element 27/06/2011 - changed to passing in element
  805. * @param object $row
  806. * @param string $key
  807. * @param string $val
  808. * @param int param repeat value 27/11/2011
  809. * @return string <a> html part
  810. */
  811. function viewFormLink($popUp = false, $element, $row = null, $key = '', $val = '', $usekey = false, $f = 0)
  812. {
  813. $params =& $this->getParams();
  814. $listid = $element->table_id;
  815. $formid = $element->form_id;
  816. $linkedFormText = $params->get('linkedformtext', '', '_default', 'array');
  817. $label = $this->parseMessageForRowHolder(JArrayHelper::getValue($linkedFormText, $f), JArrayHelper::fromObject($row));
  818. $app = JFactory::getApplication();
  819. $Itemid = $app->getMenu('site')->getActive()->id;
  820. if (is_null($listid)) {
  821. $list = $this->getTable();
  822. $listid = $list->id;
  823. }
  824. if (is_null($formid)) {
  825. $form = $this->getFormModel()->getForm();
  826. $formid = $form->id;
  827. }
  828. $facetTable = $this->_facetedTable($listid);
  829. if (!$facetTable->canAdd()) {
  830. return '<div style="text-align:center"><a title="'.JText::_('JERROR_ALERTNOAUTHOR').'"><img src="media/com_fabrik/images/login.png" alt="'.JText::_('JERROR_ALERTNOAUTHOR').'" /></a></div>';
  831. }
  832. if ($app->isAdmin()) {
  833. $bits[] = "task=form.view";
  834. $bits[] = "cid=$formid";
  835. } else {
  836. $bits[] = "view=form";
  837. //$bits[] = "listid=$listid";
  838. $bits[] = "Itemid=$Itemid";
  839. }
  840. $bits[] = "formid=$formid";
  841. $bits[] = "referring_table=". $this->getTable()->id;
  842. // $$$ hugh - change in fabrikdatabasejoin getValue() means we have to append _raw to key name
  843. if ($key != '') {
  844. $bits[] = "{$key}_raw=$val";
  845. }
  846. if ($popUp) {
  847. $bits[] = "tmpl=component";
  848. $bits[] = "ajax=1";
  849. }
  850. if ($usekey and $key != '' and !is_null($row)) {
  851. $bits[] = "usekey=" . FabrikString::shortColName($key);
  852. $bits[] = "rowid=" . $row->slug;
  853. } else {
  854. $bits[] = "rowid=0";
  855. }
  856. $url = "index.php?option=com_fabrik&" . implode("&", $bits);
  857. $url = JRoute::_($url);
  858. if (is_null($label) || $label == '') {
  859. $label = JText::_('COM_FABRIK_LINKED_FORM_ADD');
  860. }
  861. if ($popUp) {
  862. FabrikHelperHTML::mocha('a.popupwin');
  863. $opts = new stdClass();
  864. $opts->maximizable = 1;
  865. $opts->title = JText::_('COM_FABRIK_ADD');
  866. $opts->evalScripts = 1;
  867. $opts = json_encode($opts);
  868. $link = "<a rel=\"$opts\" href=\"$url\" class=\"popupwin\" title=\"$label\">" . $label . "</a>";
  869. } else {
  870. $link = "<a href=\"$url\" title=\"$label\">" . $label . "</a>";
  871. }
  872. $url = "<span class=\"addbutton\">$link</span></a>";
  873. return $url;
  874. }
  875. /**
  876. * get one of the current tables facet tables
  877. *(used in tables that link to this tables links)
  878. * @param int table id
  879. * @return object table
  880. */
  881. function _facetedTable($id)
  882. {
  883. if (!isset($this->facettables)) {
  884. $this->facettables = array();
  885. }
  886. if (!array_key_exists($id, $this->facettables)) {
  887. $this->facettables[$id] = JModel::getInstance('List', 'FabrikFEModel');
  888. $this->facettables[$id]->setId($id);
  889. }
  890. return $this->facettables[$id];
  891. }
  892. /**
  893. * build the link (<a href..>) for viewing table data
  894. *
  895. * @param bol $popUp is the link to generated a popup to show
  896. * @param obj element 27/06/2011
  897. * @param object $row
  898. * @param string $key 28/06/2011 - do longer passed in with _raw appended (done in this method)
  899. * @param string $val
  900. * @param int number of related records
  901. * @param int ref to related data admin info 27/16/2011
  902. * @return string
  903. */
  904. function viewDataLink($popUp = false, $element, $row = null, $key = '', $val = '', $count = 0, $f)
  905. {
  906. $listid = $element->table_id;
  907. $app = JFactory::getApplication();
  908. $params =& $this->getParams();
  909. $linkedTableText = $params->get('linkedtabletext', '', '_default', 'array');
  910. $label = $this->parseMessageForRowHolder(JArrayHelper::getValue($linkedTableText, $f), JArrayHelper::fromObject($row));
  911. $Itemid = $app->isAdmin() ? 0 : @$app->getMenu('site')->getActive()->id;
  912. $action = $app->isAdmin() ? "task" : "view";
  913. $url = "index.php?option=com_fabrik&";
  914. if (is_null($listid)) {
  915. $list = $this->getTable();
  916. $listid = $list->id;
  917. }
  918. $facetTable = $this->_facetedTable($listid);
  919. if (!$facetTable->canView()) {
  920. return '<div style="text-align:center"><a title="'.JText::_('Insufficient access rights. Please login').'"><img src="media/com_fabrik/images/login.png" alt="'.JText::_('iInsufficient access rights. Please login').'" /></a></div>';
  921. }
  922. $tlabel = ($label === '') ? JText::_('COM_FABRIK_NO_RECORDS') : '(0) '.$label;
  923. if ($count === 0) {
  924. $aExisitngLinkedForms = $params->get('linkedform', '', '_default', 'array');
  925. $linkedForm = JArrayHelper::getValue($aExisitngLinkedForms, $f, false);
  926. $addLink = $linkedForm == '0' ? $this->viewFormLink($popUp, $element, $row, $key, $val, false, $f) : '';
  927. return '<div style="text-align:center" class="related_data_norecords">'.$tlabel.'</div>'.$addLink;
  928. }
  929. $key .= '_raw';
  930. if ($label === '') {
  931. $label = JText::_('COM_FABRIK_VIEW');
  932. }
  933. $label = '('.$count.') '.$label;
  934. if ($app->isAdmin()) {
  935. $bits[] = "task=viewTable";
  936. $bits[] = "cid=$listid";
  937. } else {
  938. $bits[] = "view=list";
  939. $bits[] = "listid=$listid";
  940. $tableLinks = $this->getTableLinks();
  941. // $$$ rob 01/03/2011 find at matching itemid in another menu item for the related data link
  942. foreach ($tableLinks as $tlink) {
  943. if (strstr($tlink->link, 'index.php?option=com_fabrik&view=list&listid='.$listid)) {
  944. $bits[] = "Itemid=".$tlink->id;
  945. $Itemid = $tlink->id;
  946. break;
  947. }
  948. }
  949. $bits[] = "Itemid=$Itemid";
  950. }
  951. if ($key != '') {
  952. $bits[] = "{$key}=$val";
  953. }
  954. $bits[] = 'limitstart=0';
  955. if ($popUp) {
  956. $bits[] = "tmpl=component";
  957. $bits[] = "ajax=1";
  958. }
  959. $bits[] = "&resetfilters=1";
  960. //$bits[] = "clearfilters=1"; //nope stops url filter form workin on related data :(
  961. $url .= implode("&", $bits);
  962. $url = JRoute::_($url);
  963. if ($popUp) {
  964. FabrikHelperHTML::mocha('a.popupwin');
  965. $opts = new stdClass();
  966. $opts->maximizable = 1;
  967. $opts->title = JText::_('COM_FABRIK_VIEW');
  968. $opts->evalScripts = 1;
  969. $opts = str_replace('"', "'", json_encode($opts));
  970. $url = '<a rel="'.$opts.'" href="'. $url.'" class="popupwin">'.$label.'</a>';
  971. } else {
  972. $url = '<a class="related_data" href="'.$url.'">'.$label."</a>";
  973. }
  974. return $url;
  975. }
  976. /**
  977. * add a normal/custom link to the element data
  978. *
  979. * @param string element $data
  980. * @param object element
  981. * @param object of all row data
  982. * @return string element data with link added if specified
  983. */
  984. public function _addLink($data, &$elementModel, $row, $repeatCounter = 0)
  985. {
  986. $element =& $elementModel->getElement();
  987. if ($this->_outPutFormat == 'csv' || $element->link_to_detail == 0) {
  988. return $data;
  989. }
  990. $params =& $elementModel->getParams();
  991. $customLink = $params->get('custom_link');
  992. // $$$ rob if its a custom link then we aren't linking to the details view so we should
  993. // ignore the view details access settings
  994. if (!$this->canViewDetails($row) && trim($customLink) == '') {
  995. return $data;
  996. }
  997. $list = $this->getTable();
  998. $primaryKeyVal = $this->getKeyIndetifier($row);
  999. $link = $this->linkHref($elementModel, $row, $repeatCounter);
  1000. if ($link == '') {
  1001. return $data;
  1002. }
  1003. //try to remove any previously entered links
  1004. $data = preg_replace('/<a(.*?)>|<\/a>/', '', $data);
  1005. $data = "<a class=\"fabrik___rowlink\" href=\"$link\">$data</a>";
  1006. return $data;
  1007. }
  1008. /**
  1009. * since 2.0.4 get the href for the edit link
  1010. * @param object $elementModel
  1011. * @param array $row data
  1012. * @return string link href
  1013. */
  1014. public function linkHref($elementModel, $row, $repeatCounter = 0)
  1015. {
  1016. $element =& $elementModel->getElement();
  1017. $table =& $this->getTable();
  1018. $params =& $elementModel->getParams();
  1019. $customLink = $params->get('custom_link');
  1020. $link = '';
  1021. if ($customLink == '') {
  1022. // $$$ rob only test canEdit and canView on stardard edit links - if custom we should always use them,
  1023. //3.0 get either edit or view link - as viewDetailslInk now always returns the view details link
  1024. if ($this->canEdit($row)) {
  1025. $this->_aLinkElements[] = $element->name;
  1026. $link = $this->editLink($row);
  1027. } else if ($this->canViewDetails($row)) {
  1028. $this->_aLinkElements[] = $element->name;
  1029. $link = $this->viewDetailsLink($row);
  1030. }
  1031. } else {
  1032. $array = JArrayHelper::fromObject($row);
  1033. foreach ($array as $k => &$v) {
  1034. $v = json_decode($v, $true);
  1035. if (is_array($v)) {
  1036. $v = JArrayHelper::getValue($v, $repeatCounter);
  1037. }
  1038. }
  1039. $array['rowid'] = $this->getSlug($row);
  1040. $array['listid'] = $table->id;
  1041. $link = JRoute::_($this->parseMessageForRowHolder($customLink, $array));
  1042. }
  1043. return $link;
  1044. }
  1045. /**
  1046. * get query to make records
  1047. * @return string sql
  1048. */
  1049. function _buildQuery()
  1050. {
  1051. global $_PROFILER;
  1052. JDEBUG ? $_PROFILER->mark('_buildQuery: start') : null;
  1053. $query = array();
  1054. if ($this->mergeJoinedData()) {
  1055. // $$$ rob - get a list of the main table's ids limited on the navigation
  1056. // this will then be used to filter the main query,
  1057. // by modifying the where part of the query
  1058. $db = $this->getDb();
  1059. $table = $this->getTable();
  1060. // $$$ rob build order first so that we know of any elemenets we need to include in the select statement
  1061. $order = $this->_buildQueryOrder();
  1062. $this->selectedOrderFields = (array)$this->selectedOrderFields;
  1063. array_unshift($this->selectedOrderFields , "DISTINCT ".$table->db_primary_key . " AS __pk_val");
  1064. $query['select'] = "SELECT ". implode(', ', $this->selectedOrderFields) . " FROM ".$db->nameQuote($table->db_table_name);
  1065. $query['join'] = $this->_buildQueryJoin();
  1066. $query['where'] = $this->_buildQueryWhere(JRequest::getVar('incfilters', 1));
  1067. $query['grouby'] = $this->_buildQueryGroupBy();
  1068. $query['order'] = $order;
  1069. //check that the order by fields are in the select statement
  1070. $squery = implode(" ", $query);
  1071. $db->setQuery($squery, $this->limitStart, $this->limitLength);
  1072. FabrikHelperHTML::debug($db->getQuery(), 'table:mergeJoinedData get ids');
  1073. $ids = JArrayHelper::getColumn($db->loadObjectList(), '__pk_val');
  1074. }
  1075. $query = array();
  1076. $query['select'] = $this->_buildQuerySelect();
  1077. JDEBUG ? $_PROFILER->mark('queryselect: got') : null;
  1078. $query['join'] = $this->_buildQueryJoin();
  1079. JDEBUG ? $_PROFILER->mark('queryjoin: got') : null;
  1080. if ($this->mergeJoinedData()) {
  1081. // $$$ rob We've already used _buildQueryWhere to get our list of main pk ids.
  1082. // so lets use that list of ids to create the where statement. This will return 5/10/20 etc
  1083. // records from our main table, as per our page nav, even if a main record has 3 rows of joined
  1084. // data. If no ids found then do where 1 = -1 to return no records
  1085. if (!empty($ids)) {
  1086. $query['where'] = " WHERE $table->db_primary_key IN (".implode($ids, ',').')';
  1087. } else {
  1088. $query['where'] = " WHERE 1 = -1";
  1089. }
  1090. } else {
  1091. // $$$ rob we aren't merging joined records so lets just add the standard where query
  1092. //incfilters set when exporting as CSV
  1093. $query['where'] = $this->_buildQueryWhere(JRequest::getVar('incfilters', 1));
  1094. }
  1095. $query['groupby'] = $this->_buildQueryGroupBy();
  1096. $query['order'] = $this->_buildQueryOrder();
  1097. $query = $this->pluginQuery($query);
  1098. $query = implode(" ", $query);
  1099. return $query;
  1100. }
  1101. /**
  1102. * pass an sql query through the table plug-ins
  1103. * @param string $query
  1104. * @return string altered query.
  1105. */
  1106. public function pluginQuery($query)
  1107. {
  1108. //pass the query as an object property so it can be updated via reference
  1109. $args = new stdClass();
  1110. $args->query = $query;
  1111. $this->getPluginManager()->runPlugins('onQueryBuilt', $this, 'list', $args);
  1112. $query = $args->query;
  1113. return $query;
  1114. }
  1115. /**
  1116. * get the select part of the query
  1117. *
  1118. * @return string
  1119. */
  1120. function _buildQuerySelect()
  1121. {
  1122. global $_PROFILER;
  1123. JDEBUG ? $_PROFILER->mark('queryselect: start') : null;
  1124. $db = $this->getDb();
  1125. $form =& $this->getFormModel();
  1126. $table =& $this->getTable();
  1127. $form->getGroupsHiarachy(true);
  1128. JDEBUG ? $_PROFILER->mark('queryselect: fields load start') : null;
  1129. $fields =& $this->getAsFields();
  1130. $pk = FabrikString::safeColName($table->db_primary_key);
  1131. //SEFSLUG TEST
  1132. $params =& $this->getParams();
  1133. if (in_array($this->_outPutFormat, array('raw', 'html', 'feed', 'pdf', 'phocapdf'))) {
  1134. $slug = $params->get('sef-slug');
  1135. if ($slug != '') {
  1136. $slug = FabrikString::safeColName($slug);
  1137. $fields[] = "CONCAT_WS(':', $pk, $slug) AS slug";
  1138. } else {
  1139. if ($pk !== '``') {
  1140. $fields[] = "$pk AS slug";
  1141. }
  1142. }
  1143. }
  1144. //END
  1145. JDEBUG ? $_PROFILER->mark('queryselect: fields loaded') : null;
  1146. $sfields = (empty($fields)) ? '' : implode(", \n ", $fields) . "\n ";
  1147. //$$$rob added raw as an option to fix issue in saving calendener data
  1148. if (trim($table->db_primary_key) != '' && (in_array($this->_outPutFormat, array('raw','html','feed','pdf','phocapdf','csv')))) {
  1149. $sfields .= ", ";
  1150. $strPKey = $pk . " AS " . $db->nameQuote('__pk_val') . "\n";
  1151. $query = 'SELECT SQL_CALC_FOUND_ROWS DISTINCT ' . $sfields . $strPKey;
  1152. } else {
  1153. $query = 'SELECT SQL_CALC_FOUND_ROWS DISTINCT ' . trim($sfields, ", \n") . "\n";
  1154. }
  1155. $query .= " FROM ".$db->nameQuote($table->db_table_name)." \n";
  1156. return $query;
  1157. }
  1158. /**
  1159. * get the part of the sql statement that orders the table data
  1160. * @param mixed false or a query object
  1161. * @return string ordering part of sql statement
  1162. */
  1163. function _buildQueryOrder($query = false)
  1164. {
  1165. $params = $this->getParams();
  1166. $table =& $this->getTable();
  1167. $db = FabrikWorker::getDbo();
  1168. $this->selectedOrderFields = array();
  1169. if ($this->_outPutFormat == 'feed')
  1170. {
  1171. $dateColId = (int)$params->get('feed_date', 0);
  1172. $db->setQuery('SELECT name FROM #__{package}_elements WHERE id = '.$dateColId);
  1173. $dateCol = $db->nameQuote($table->db_table_name).'.'.$db->nameQuote($db->loadResult());
  1174. if ($dateColId !== 0) {
  1175. $this->order_dir = 'DESC';
  1176. $this->order_by = $dateCol;
  1177. if (!$query) {
  1178. return "\n ORDER BY $dateCol DESC";
  1179. } else {
  1180. $query->order($dateCol.' DESC');
  1181. return $query;
  1182. }
  1183. }
  1184. }
  1185. $session = JFactory::getSession();
  1186. //$$$rob - when table reordered the controller runs order() and
  1187. // stores the order settings in the session by calling setOrderByAndDir()
  1188. // it then redirects to the table view and here all we need to do it get
  1189. // those order settings from the session
  1190. $elements =& $this->getElements();
  1191. //build the order by statement from the session
  1192. $strOrder = '';
  1193. $clearOrdering = (bool)JRequest::getInt('clearordering', false) && JRequest::getCmd('task') !== 'order';
  1194. //$$$tom Added single-ordering option
  1195. if ($params->get('enable_single_sorting', 'default') == 'default') { // Use global
  1196. $fbConfig =& JComponentHelper::getParams('com_fabrik');
  1197. $singleOrdering = $fbConfig->get('enable_single_sorting', false);
  1198. }
  1199. else {
  1200. $singleOrdering = $params->get('enable_single_sorting', false);
  1201. }
  1202. $id = $this->getId();
  1203. foreach ($elements as $element) {
  1204. $context = 'com_fabrik.table'.$id.'.order.'.$element->getElement()->id;
  1205. if ($clearOrdering) {
  1206. $session->set($context, '');
  1207. } else {
  1208. //$$$tom Added single-ordering option
  1209. if (!$singleOrdering || ($singleOrdering && $element->getElement()->id == JRequest::getInt('orderby', ''))) {
  1210. $dir = $session->get($context);
  1211. if ($dir != '' && $dir != '-' && trim($dir) != 'Array') {
  1212. $strOrder == '' ? $strOrder = "\n ORDER BY " : $strOrder .= ',';
  1213. $strOrder .= $element->getOrderByName()." $dir";
  1214. $this->orderEls[] = $element->getOrderByName();
  1215. $this->orderDirs[] = $dir;
  1216. $element->getAsField_html($this->selectedOrderFields, $aAsFields);
  1217. }
  1218. }
  1219. else {
  1220. $session->set($context, '');
  1221. }
  1222. }
  1223. }
  1224. //if nothing found in session use default ordering
  1225. if ($strOrder == '') {
  1226. $orderbys = json_decode($table->order_by, true);
  1227. $orderdirs = json_decode($table->order_dir, true);
  1228. if (!empty($orderbys)) {
  1229. $bits = array();
  1230. for ($o = 0; $o < count($orderbys); $o++) {
  1231. $dir = JArrayHelper::getValue($orderdirs, $o, 'desc');
  1232. if ($orderbys[$o] !== '') {
  1233. $orderby = FabrikString::safeColName($orderbys[$o]);
  1234. $els = $this->getElements('filtername');
  1235. if (array_key_exists($orderby, $els)) {
  1236. // $$$ hugh - getOrderByName can return a CONCAT, ie join element ...
  1237. $field = $els[$orderby]->getOrderByName();
  1238. if (!stristr($field, 'CONCAT(')) {
  1239. $field = FabrikString::safeColName($field);
  1240. }
  1241. $bits[] = " $field $dir";
  1242. $this->orderEls[] = $field;
  1243. $this->orderDirs[] = $dir;
  1244. } else {
  1245. if (strstr($orderby, '_raw`')) {
  1246. $orderby = FabrikString::safeColNameToArrayKey($orderby);
  1247. }
  1248. $bits[] = " $orderby $dir";
  1249. $this->orderEls[] = $orderby;
  1250. $this->orderDirs[] = $dir;
  1251. }
  1252. }
  1253. }
  1254. if (!empty($bits)) {
  1255. if (!$query) {
  1256. $strOrder = "\n ORDER BY" . implode(',', $bits);
  1257. } else {
  1258. $query->order(implode(',', $bits));
  1259. }
  1260. }
  1261. }
  1262. }
  1263. // apply group ordering
  1264. // @TODO - explain something to hugh! Why is this "group ordering"? AFAICT, it's just a secondary
  1265. // order by, isn't specific to the Group By feature in any way? So why not just put this option in
  1266. //
  1267. $groupOrderBy = $params->get('group_by_order');
  1268. if ($groupOrderBy != '') {
  1269. $groupOrderDir = $params->get('group_by_order_dir');
  1270. $strOrder == '' ? $strOrder = "\n ORDER BY " : $strOrder .= ',';
  1271. $orderby = strstr($groupOrderBy, '_raw`') ? FabrikString::safeColNameToArrayKey($groupOrderBy) : FabrikString::safeColName($groupOrderBy);
  1272. if (!$query) {
  1273. $strOrder .= $orderby." ".$groupOrderDir;
  1274. } else {
  1275. $query->order($orderby." ".$groupOrderDir);
  1276. }
  1277. $this->orderEls[] = $orderby;
  1278. $this->orderDirs[] = $groupOrderDir;
  1279. }
  1280. return $query === false ? $strOrder : $query;
  1281. }
  1282. /**
  1283. * called when the table column order by is clicked
  1284. * store order options in session
  1285. * @return null
  1286. */
  1287. function setOrderByAndDir()
  1288. {
  1289. $session = JFactory::getSession();
  1290. $postOrderBy = JRequest::getInt('orderby', '');
  1291. $postOrderDir = JRequest::getVar('orderdir', '');
  1292. $arOrderVals = array('asc', 'desc', '-');
  1293. $id = $this->getId();
  1294. if (in_array($postOrderDir, $arOrderVals)) {
  1295. $context = 'com_fabrik.table'.$id.'.order.'.$postOrderBy;
  1296. $session->set($context, $postOrderDir);
  1297. }
  1298. }
  1299. /**
  1300. * get the part of the sql query that creates the joins
  1301. * used when building the table's data
  1302. * @param mixed
  1303. * @return string join sql
  1304. */
  1305. function _buildQueryJoin($query = false)
  1306. {
  1307. $db = FabrikWorker::getDbo();
  1308. $ref = $query ? '1': '0';
  1309. if (isset($this->_joinsSQL[$ref])) {
  1310. return $this->_joinsSQL[$ref];
  1311. }
  1312. $statements = array();
  1313. $table =& $this->getTable();
  1314. $selectedTables[] = $table->db_table_name;
  1315. $return = array();
  1316. $joins = ($this->get('includeCddInJoin', true) === false) ? $this->getJoinsNoCdd() : $this->getJoins();
  1317. $tableGroups = array();
  1318. foreach ($joins as $join) {
  1319. //used to bypass user joins if the table connect isnt the Joomla
  1320. //connection
  1321. if ((int)$join->canUse === 0) {
  1322. continue;
  1323. }
  1324. if ($join->join_type == '') {
  1325. $join->join_type = 'LEFT';
  1326. }
  1327. $sql = strtoupper($join->join_type) ." JOIN ".$db->nameQuote($join->table_join);
  1328. $k = FabrikString::safeColName($join->keytable.'.'.$join->table_key);
  1329. if ($join->table_join_alias == '') {
  1330. $on = FabrikString::safeColName($join->table_join.'.'.$join->table_join_key);
  1331. $sql .= " ON $on = $k \n";
  1332. } else {
  1333. $on = FabrikString::safeColName($join->table_join_alias.'.'.$join->table_join_key);
  1334. $sql .= " AS ".FabrikString::safeColName($join->table_join_alias)." ON $on = $k \n";
  1335. }
  1336. // try to order join statements to ensure that you are selecting from tables that have
  1337. //already been included (either via a previous join statement or the table select statement)
  1338. if (in_array($join->keytable, $selectedTables)) {
  1339. $return[] = $sql;
  1340. $selectedTables[] = $join->table_join;
  1341. } else {
  1342. //didnt find anything so defer it till later
  1343. //$statements[$join->keytable] = $sql;
  1344. //$$$rob - sometimes the keytable is the same for 2 deferred joins
  1345. //in this case the first join is incorrectly overwritten in the $statements array
  1346. //keying on join->id should solve this
  1347. $statements[$join->id] = array($join->keytable, $sql);
  1348. }
  1349. //go through the deferred join statements and see if their table has now been selected
  1350. foreach ($statements as $joinid => $ar) {
  1351. $t = $ar[0];
  1352. $s = $ar[1];
  1353. if (in_array($t, $selectedTables)) {
  1354. if (!in_array($s, $return)) { //$$$rob test to avoid duplicate join queries
  1355. //ahhh now its there so we can add the statement
  1356. $return[] = $s;
  1357. unset($statements[$t]);
  1358. }
  1359. }
  1360. }
  1361. }
  1362. // $$$rob test for bug #376
  1363. foreach ($statements as $joinid => $ar) {
  1364. $s = $ar[1];
  1365. if (!in_array($s, $return)) {
  1366. $return[] = $s;
  1367. }
  1368. }
  1369. // 3.0 not really tested
  1370. if ($query !== false) {
  1371. foreach ($return as $r) {
  1372. $words = explode(" ", trim($r));
  1373. $type = array_shift($words);
  1374. $statement = str_replace('JOIN', '', implode(' ', $words));
  1375. $query->join($type, $statement);
  1376. }
  1377. return $query;
  1378. } else {
  1379. $return = implode(" ", $return);
  1380. $this->_joinsSQL[$ref] = $return;
  1381. }
  1382. return $query == false ? $return: $query;
  1383. }
  1384. function _buildQueryPrefilterWhere(&$element)
  1385. {
  1386. $elementName =& FabrikString::safeColName($element->getFullName(false, false, false));
  1387. $filters = $this->getFilterArray();
  1388. $keys = array_keys($filters);
  1389. $vkeys = array_keys(JArrayHelper::getValue($filters, 'value', array()));
  1390. foreach ($vkeys as $i) {
  1391. if ($filters['search_type'][$i] != 'prefilter' || $filters['key'][$i] != $elementName) {
  1392. foreach ($keys as $key) {
  1393. unset($filters[$key][$i]);
  1394. }
  1395. }
  1396. }
  1397. list($sqlNoFilter, $sql) = $this->_filtersToSQL($filters);
  1398. $where = str_replace('WHERE', '', $sql);
  1399. if ($where != '') {
  1400. $where = " AND $where";
  1401. }
  1402. return $where;
  1403. }
  1404. /**
  1405. * get the part of the main query that provides a group by statement
  1406. * only added by 'count' element plug-in at the moment
  1407. * @return string
  1408. */
  1409. function _buildQueryGroupBy()
  1410. {
  1411. $groups =& $this->getFormModel()->getGroupsHiarachy();
  1412. foreach ($groups as $groupModel) {
  1413. $elementModels =& $groupModel->getPublishedElements();
  1414. foreach ($elementModels as $elementModel) {
  1415. $res = $elementModel->getGroupByQuery();
  1416. if ($res != '') {
  1417. $this->_pluginQueryGroupBy[] = $res;
  1418. }
  1419. }
  1420. }
  1421. if (!empty($this->_pluginQueryGroupBy)) {
  1422. return ' GROUP BY '.implode(', ', $this->_pluginQueryGroupBy);
  1423. }
  1424. return '';
  1425. }
  1426. /**
  1427. * does a filter have to be appled before we show any table data
  1428. * @retrun bool
  1429. */
  1430. protected function filtersRequired()
  1431. {
  1432. $app =& JFactory::getApplication();
  1433. $params =& $this->getParams();
  1434. if (!$this->getRequiredFiltersFound()) {
  1435. return true;
  1436. }
  1437. switch ($params->get('require-filter', 0)) {
  1438. case 0:
  1439. default:
  1440. return false;
  1441. break;
  1442. case 1:
  1443. return true;
  1444. break;
  1445. case 2:
  1446. return $app->isAdmin() ? false : true;
  1447. break;
  1448. }
  1449. }
  1450. /**
  1451. * get the part of the sql query that relates to the where statement
  1452. *
  1453. * @param bol $incFilters if true the SQL contains
  1454. * any filters if false only contains prefilter sql
  1455. * @param bool start the statement with 'where' (true is for j1.5 way of making queries, false for j1.6+)
  1456. * @return string where query
  1457. */
  1458. function _buildQueryWhere($incFilters = true, $query = false)
  1459. {
  1460. $sig = !$query ? 'string' : 'query';
  1461. $db = FabrikWorker::getDbo();
  1462. if (isset($this->_whereSQL[$sig])) {
  1463. return $this->_whereSQL[$sig][$incFilters];
  1464. }
  1465. $filters =& $this->getFilterArray();
  1466. $params =& $this->getParams();
  1467. # $$$ hugh - added option to 'require filtering', so if no filters specified
  1468. # we return an empty table. Only do this where $inFilters is set, so we're only doing this
  1469. # on the main row count and data fetch, and things like
  1470. # filter dropdowns still get built.
  1471. // $$$ rob prefilters shouldnt be included in 'require filtering'
  1472. $ftypes = JArrayHelper::getValue($filters, 'search_type', array());
  1473. foreach ($ftypes as $i => $ftype) {
  1474. if ($ftype == 'prefilter') {
  1475. unset($ftypes[$i]);
  1476. }
  1477. }
  1478. if ($incFilters && $this->filtersRequired() && empty($ftypes)) {
  1479. $this->emptyMsg = JText::_('COM_FABRIK_SELECT_AT_LEAST_ONE_FILTER');
  1480. if (!$query) {
  1481. return 'WHERE 1 = -1 ';
  1482. } else {
  1483. $query->where('1 = -1');
  1484. return $query;
  1485. }
  1486. }
  1487. $groups =& $this->getFormModel()->getGroupsHiarachy();
  1488. foreach ($groups as $groupModel) {
  1489. $elementModels =& $groupModel->getPublishedElements();
  1490. foreach ($elementModels as $elementModel) {
  1491. $elementModel->appendTableWhere($this->_pluginQueryWhere);
  1492. }
  1493. }
  1494. if (empty($filters)) {
  1495. // $$$ hugh - testing hack for plugins to add WHERE clauses
  1496. if (!empty($this->_pluginQueryWhere)) {
  1497. if (!$query) {
  1498. return 'WHERE '.implode(' AND ', $this->_pluginQueryWhere);
  1499. } else {
  1500. $query->where(implode(' AND ', $this->_pluginQueryWhere));
  1501. return $query;
  1502. }
  1503. }
  1504. else {
  1505. return $query ? $query : '';
  1506. }
  1507. }
  1508. $addWhere = $query == false ? true : false;
  1509. list($sqlNoFilter, $sql) = $this->_filtersToSQL($filters, $addWhere);
  1510. $this->_whereSQL[$sig] = array('0' => $sqlNoFilter, '1' => $sql);
  1511. if (!$query) {
  1512. return $this->_whereSQL[$sig][$incFilters];
  1513. } else {
  1514. $query->where($this->_whereSQL[$sig][$incFilters]);
  1515. return $query;
  1516. }
  1517. }
  1518. /**
  1519. * used by _buildWhereQuery and _buildQueryPrefilterWhere
  1520. * takes a filter array and returns the SQL
  1521. * @param array filters
  1522. * @param bool start the statement with 'where' (true is for j1.5 way of making queries, false for j1.6+)
  1523. * @return array nofilter, filter sql
  1524. */
  1525. private function _filtersToSQL(&$filters, $startWithWhere = true)
  1526. {
  1527. $prefilters = $this->_groupFilterSQL($filters, 'prefilter');
  1528. $postfilers = $this->_groupFilterSQL($filters);
  1529. if (!empty($prefilters) && !empty($postfilers)) {
  1530. array_unshift($postfilers, 'AND');
  1531. }
  1532. $sql = array_merge($prefilters, $postfilers);
  1533. $pluginQueryWhere = trim(implode(' AND ', $this->_pluginQueryWhere));
  1534. if ($pluginQueryWhere !== '') {
  1535. $pluginQueryWhere = '('.$pluginQueryWhere.')';
  1536. if (!empty($sql)) {
  1537. $sql[] = ' AND ';
  1538. }
  1539. if (!empty($prefilters)) {
  1540. $prefilters[] = ' AND ';
  1541. }
  1542. $sql[] = $pluginQueryWhere;
  1543. $prefilters[] = $pluginQueryWhere;
  1544. }
  1545. //add in the where to the query
  1546. if (!empty($sql) && $startWithWhere) {
  1547. array_unshift($sql, 'WHERE');
  1548. }
  1549. if (!empty($prefilters) && $startWithWhere) {
  1550. array_unshift($prefilters, 'WHERE');
  1551. }
  1552. $sql = implode($sql, ' ');
  1553. $prefilters = implode($prefilters, ' ');
  1554. return array($prefilters, $sql);
  1555. }
  1556. /**
  1557. * parse the filter array and return an array of words that will make up part of the filter query
  1558. * @param array $filters
  1559. * @param string $type * = filters, 'prefilter' = get prefilter only
  1560. * @return array words making up sql query.
  1561. */
  1562. private function _groupFilterSQL(&$filters, $type = '*')
  1563. {
  1564. $groupedCount = 0;
  1565. $ingroup = false;
  1566. $sql= array();
  1567. // $$$ rob keys may no longer be in asc order as we may have filtered out some in _buildQueryPrefilterWhere()
  1568. $vkeys = array_keys(JArrayHelper::getValue($filters, 'key', array()));
  1569. foreach ($vkeys as $i) {
  1570. //for ($i = 0; $i < count(JArrayHelper::getValue($filters, 'key', array())); $i ++) {
  1571. // $$$rob - prefilter with element that is not published so ignore
  1572. $condition = strtoupper(JArrayHelper::getValue($filters['condition'], $i, ''));
  1573. if (JArrayHelper::getValue($filters['sqlCond'], $i, '') == '' && ($condition != 'IS NULL' && $condition != 'IS NOT NULL')) {
  1574. continue;
  1575. }
  1576. if ($filters['search_type'][$i] == 'prefilter' && $type == '*') {
  1577. continue;
  1578. }
  1579. if ($filters['search_type'][$i] != 'prefilter' && $type == 'prefilter') {
  1580. continue;
  1581. }
  1582. $n = $i +1;
  1583. $gstart = "";
  1584. $gend = "";
  1585. if ($condition == 'IS NULL' || $condition == 'IS NOT NULL') {
  1586. $filters['origvalue'][$i] = 'this is ignoerd i hope';
  1587. }
  1588. // $$$ rob added $filters['sqlCond'][$i] test so that you can test for an empty string
  1589. if ($filters['origvalue'][$i] != '' || $filters['sqlCond'][$i] != '') {
  1590. if (array_key_exists($n, $filters['grouped_to_previous'])) {
  1591. if ($filters['grouped_to_previous'][$n] == 1) {
  1592. if (!$ingroup) {
  1593. // search all filter after a prefilter - alter 'join' value to 'AND'
  1594. if ($i > 1 && JArrayHelper::getValue($filters['search_type'], $i-1) == 'prefilter' && JArrayHelper::getValue($filters['search_type'], $i) !== 'prefilter') {
  1595. $filters['join'][$i] = 'AND';
  1596. // $$$ hugh - if using a search form, with a multiselect object (like checkbox) and
  1597. // prefilters, the gstart is never getting set, so have unbalanced )
  1598. if ($filters['search_type'][$i] == 'search') {
  1599. $gstart = "(";
  1600. $groupedCount++;
  1601. }
  1602. } else {
  1603. $gstart = "(";
  1604. $groupedCount ++;
  1605. }
  1606. }
  1607. $ingroup = true;
  1608. } else {
  1609. if ($ingroup) {
  1610. $gend = ')';
  1611. $groupedCount --;//test
  1612. $ingroup = false;
  1613. }
  1614. }
  1615. } else {
  1616. if ($ingroup) {
  1617. $gend = ')';
  1618. $groupedCount --;
  1619. $ingroup = false;
  1620. }
  1621. }
  1622. $sql[] = empty($sql) ? $gstart : $filters['join'][$i].' '.$gstart;
  1623. $sql[] = $filters['sqlCond'][$i].$gend;
  1624. /*if ($filters['search_type'][$i] == 'prefilter') {
  1625. // $$$rob messed up with prefilters as defined in this thread
  1626. // http://fabrikar.com/forums/showthread.php?t=12251
  1627. //$sqlNoFilter[] = empty($sqlNoFilter ) ? $gstart : $gstart.$filters['join'][$i];
  1628. $sqlNoFilter[] = empty($sqlNoFilter ) ? $gstart : $filters['join'][$i].' '.$gstart;
  1629. $sqlNoFilter[] = $filters['sqlCond'][$i].$gend;
  1630. }*/
  1631. }
  1632. }
  1633. // $$$rob ensure opening and closing parathethis for prefilters are equal
  1634. //seems to occur if you have 3 prefilters with 2nd = grouped/AND and 3rd grouped/OR
  1635. if ($groupedCount > 0) {
  1636. $sql[] = str_pad('', (int)$groupedCount, ")");
  1637. }
  1638. //wrap in brackets
  1639. if (!empty($sql)) {
  1640. array_unshift($sql, '(');
  1641. $sql[] = ')';
  1642. }
  1643. return $sql;
  1644. }
  1645. /**
  1646. * get a list of the tables columns' order by field names
  1647. * @return array order by names
  1648. */
  1649. function getOrderByFields()
  1650. {
  1651. if (is_null($this->orderByFields)) {
  1652. $this->orderByFields = array();
  1653. }
  1654. $form =& $this->getFormModel();
  1655. $groups =& $form->getGroupsHiarachy();
  1656. foreach ($groups as $groupModel) {
  1657. $elementModels =& $groupModel->getPublishedElements();
  1658. foreach ($elementModels as $elementModel) {
  1659. $this->orderByFields[] = $elementModel->getOrderByName();
  1660. }
  1661. }
  1662. return $this->orderByFields;
  1663. }
  1664. function getSearchAllFields()
  1665. {
  1666. global $_PROFILER;
  1667. if (isset($this->searchAllAsFields)) {
  1668. return $this->searchAllAsFields;
  1669. }
  1670. $searchAllFields = array();
  1671. $this->searchAllAsFields = array();
  1672. $form =& $this->getFormModel();
  1673. $table =& $this->getTable();
  1674. $aJoinObjs =& $this->getJoins();
  1675. $groups =& $form->getGroupsHiarachy();
  1676. $gkeys = array_keys($groups);
  1677. $opts = array('inc_raw'=>false);
  1678. foreach ($gkeys as $x) {
  1679. $groupModel = $groups[$x];
  1680. // $$$ rob moved into elementModel::getAsField_html()
  1681. /*$table_name = $table->db_table_name;
  1682. $group =& $groupModel->getGroup();
  1683. if ($groupModel->isJoin()) {
  1684. foreach ($aJoinObjs as $join) {
  1685. //also ignore any joins that are elements
  1686. if (array_key_exists('group_id', $join) && $join->group_id == $group->id && $join->element_id == 0) {
  1687. $table_name = $join->table_join;
  1688. }
  1689. }
  1690. }*/
  1691. $elementModels =& $groupModel->getPublishedElements();
  1692. for ($ek = 0; $ek < count($elementModels); $ek ++) {
  1693. $elementModel = $elementModels[$ek];
  1694. if ($elementModel->getParams()->get('inc_in_search_all', true)) {
  1695. // boolean search doesnt seem possible on encrypted fields.
  1696. $p =& $elementModel->getParams();
  1697. $o = $p->get('encrypt');
  1698. $p->set('encrypt', false);
  1699. $elementModel->getAsField_html($this->searchAllAsFields, $searchAllFields, '', $opts);
  1700. $p->set('encrypt', $o);
  1701. }
  1702. }
  1703. }
  1704. $db = FabrikWorker::getDbo();
  1705. //if the group by element isnt in the fields (IE its not published) add it (otherwise group by wont work)
  1706. $longGroupBy = $db->NameQuote(FabrikString::safeColNameToArrayKey($table->group_by));
  1707. if (!in_array($longGroupBy, $searchAllFields) && trim($table->group_by) != '') {
  1708. $this->searchAllAsFields[] = FabrikString::safeColName($table->group_by) . " AS " . $longGroupBy;
  1709. $searchAllFields[] = $longGroupBy;
  1710. }
  1711. for ($x=0; $x < count($this->searchAllAsFields); $x ++) {
  1712. $match = ' AS '.$searchAllFields[$x];
  1713. if (array_key_exists($x, $this->searchAllAsFields)) {
  1714. $this->searchAllAsFields[$x] = trim(str_replace($match, '', $this->searchAllAsFields[$x]));
  1715. }
  1716. }
  1717. $this->searchAllAsFields = array_unique($this->searchAllAsFields);
  1718. return $this->searchAllAsFields;
  1719. }
  1720. /**
  1721. * get the part of the table sql statement that selects which fields to load
  1722. *
  1723. * @return array field names to select in getelement data sql query
  1724. */
  1725. function &getAsFields()
  1726. {
  1727. global $_PROFILER;
  1728. if (isset($this->asfields)) {
  1729. return $this->asfields;
  1730. }
  1731. $this->fields = array();
  1732. $this->asfields = array();
  1733. $db = FabrikWorker::getDbo(true);
  1734. $form = $this->getFormModel();
  1735. $table = $this->getTable();
  1736. $aJoinObjs = $this->getJoins();
  1737. $this->_temp_db_key_addded = false;
  1738. $groups =& $form->getGroupsHiarachy();
  1739. $gkeys = array_keys($groups);
  1740. foreach ($gkeys as $x) {
  1741. $groupModel = $groups[$x];
  1742. $elementModels = $groupModel->getPublishedElements();
  1743. foreach ($elementModels as $elementModel) {
  1744. $method = "getAsField_" . $this->_outPutFormat;
  1745. if (!method_exists($elementModel, $method)) {
  1746. $method = "getAsField_html";
  1747. }
  1748. $elementModel->$method($this->asfields, $this->fields);
  1749. }
  1750. }
  1751. //temporaraily add in the db key so that the edit links work, must remove it before final return
  1752. // of getData();
  1753. JDEBUG ? $_PROFILER->mark('getAsFields: starting to test if a view') : null;
  1754. if (!$this->isView()) {
  1755. if (!$this->_temp_db_key_addded && $table->db_primary_key != '') {
  1756. $str = FabrikString::safeColName($table->db_primary_key)." AS ".FabrikString::safeColNameToArrayKey($table->db_primary_key);
  1757. $this->fields[] = $db->nameQuote(FabrikString::safeColNameToArrayKey($table->db_primary_key));
  1758. }
  1759. }
  1760. JDEBUG ? $_PROFILER->mark('getAsFields: end of view test') : null;
  1761. //for raw data in packages
  1762. if ($this->_outPutFormat == 'raw') {
  1763. $str = FabrikString::safeColName($table->db_primary_key)." AS __pk_val";
  1764. $this->fields[] = $str;
  1765. }
  1766. $this->_group_by_added = false;
  1767. //if the group by element isnt in the fields (IE its not published) add it (otherwise group by wont work)
  1768. $longGroupBy = $db->NameQuote(FabrikString::safeColNameToArrayKey($table->group_by));
  1769. if (!in_array($longGroupBy, $this->fields) && trim($table->group_by) != '') {
  1770. $this->asfields[] = FabrikString::safeColName($table->group_by) . " AS " . $longGroupBy;
  1771. $this->fields = $longGroupBy;
  1772. $this->_group_by_added = true;
  1773. }
  1774. return $this->asfields;
  1775. }
  1776. /**
  1777. * checks if the params object has been created and if not creates and returns it
  1778. * @return object params
  1779. */
  1780. function &getParams()
  1781. {
  1782. $table =& $this->getTable();
  1783. if (!isset($this->_params)) {
  1784. $this->_params = new fabrikParams($table->params, JPATH_SITE . '/administrator/components/com_fabrik/models/table.xml', 'component');
  1785. }
  1786. return $this->_params;
  1787. }
  1788. /**
  1789. * Method to set the table id
  1790. *
  1791. * @access public
  1792. * @param int table ID number
  1793. */
  1794. function setId($id)
  1795. {
  1796. $this->setState('list.id', $id);
  1797. // $$$ rob not sure why but we need this getState() here
  1798. // when assinging id from admin view
  1799. $this->getState();
  1800. }
  1801. function getId()
  1802. {
  1803. return $this->getState('list.id');
  1804. }
  1805. /**
  1806. * get the table object for the models _id
  1807. *
  1808. * @param bool force load the table
  1809. * @return object table
  1810. */
  1811. function getTable($force = false)
  1812. {
  1813. if ($force || is_null($this->_table) || !is_object($this->_table)) {
  1814. JTable::addIncludePath(JPATH_ADMINISTRATOR.DS.'components'.DS.'com_fabrik'.DS.'tables');
  1815. $this->_table = FabTable::getInstance('List', 'FabrikTable');
  1816. $id = $this->getId();
  1817. if ($id !== 0) {
  1818. $this->_table->load($id);
  1819. }
  1820. $this->_table->db_primary_key = FabrikString::safeColName($this->_table->db_primary_key);
  1821. }
  1822. return $this->_table;
  1823. }
  1824. function setTable($table)
  1825. {
  1826. $this->_table = $table;
  1827. }
  1828. /**
  1829. * load the database associated with the table
  1830. *@return object database
  1831. */
  1832. function &getDb()
  1833. {
  1834. return $this->getConnection()->getDb();
  1835. }
  1836. /**
  1837. * function get the tables connection object
  1838. * sets $this->_oConn to the tables connection
  1839. * @return object connection
  1840. */
  1841. function &getConnection()
  1842. {
  1843. $config = JFactory::getConfig();
  1844. if (!isset($this->_oConn)) {
  1845. $table =& $this->getTable();
  1846. $connectionModel = JModel::getInstance('connection', 'FabrikFEModel');
  1847. $jform = JRequest::getVar('jform', array(), 'post');
  1848. $connId = is_null($table->connection_id) ? JArrayHelper::getValue($jform, 'connection_id', null) : $table->connection_id;
  1849. $connectionModel->setId($connId);
  1850. if ($connId == '' || is_null($connId) || $connId == '-1') { //-1 for creating new table
  1851. $connectionModel->loadDefaultConnection();
  1852. $connectionModel->setId($connectionModel->getConnection()->id);
  1853. }
  1854. $connection =& $connectionModel->getConnection();
  1855. $this->_oConn =& $connectionModel;
  1856. if (JError::isError($this->_oConn)) {
  1857. JError::handleEcho($this->_oConn);
  1858. }
  1859. }
  1860. return $this->_oConn;
  1861. }
  1862. /**
  1863. * is the table published
  1864. * Dates are stored as UTC so we can compare them against a date with no offset applied
  1865. * @return bol published state
  1866. */
  1867. function canPublish()
  1868. {
  1869. $item =& $this->getTable();
  1870. $db = FabrikWorker::getDbo();
  1871. $nullDate = (method_exists($db, 'getNullDate')) ? $db->getNullDate() : $this->getNullDate();
  1872. $publishup =& JFactory::getDate($item->publish_up);
  1873. $publishup = $publishup->toUnix();
  1874. $publishdown =& JFactory::getDate($item->publish_down);
  1875. $publishdown = $publishdown->toUnix();
  1876. $jnow = JFactory::getDate();
  1877. $now = $jnow->toUnix();
  1878. if ($item->published == '1') {
  1879. if ($now >= $publishup || $item->publish_up == '' || $item->publish_up == $nullDate) {
  1880. if ($now <= $publishdown || $item->publish_down == '' || $item->publish_down == $nullDate) {
  1881. return true;
  1882. }
  1883. }
  1884. }
  1885. return false;
  1886. }
  1887. /**
  1888. * if you have koowa installed their db obj doesnt have a getNullDate function
  1889. * @return unknown_type
  1890. */
  1891. function getNullDate()
  1892. {
  1893. return '0000-00-00 00:00:00';
  1894. }
  1895. /**
  1896. * access control to determine if the current user has rights to drop data
  1897. * from the table
  1898. * @return bol yes/no
  1899. */
  1900. function canEmpty()
  1901. {
  1902. $params =& $this->getParams();
  1903. if (!is_object($this->_access) || !array_key_exists('allow_drop', $this->_access)) {
  1904. $user = JFactory::getUser();
  1905. $groups = $user->authorisedLevels();
  1906. $this->_access->allow_drop = in_array($this->getParams()->get('allow_drop'), $groups);
  1907. //$this->_access->allow_drop = $user->authorise('core.drop', 'com_fabrik.list.'.$this->getTable()->id);
  1908. }
  1909. return $this->_access->allow_drop;
  1910. }
  1911. /**
  1912. * check if the user can view the detailed records
  1913. *
  1914. * @return bol
  1915. */
  1916. function canViewDetails()
  1917. {
  1918. $params =& $this->getParams();
  1919. if (!is_object($this->_access) || !array_key_exists('viewdetails', $this->_access)) {
  1920. $user = JFactory::getUser();
  1921. $groups = $user->authorisedLevels();
  1922. $this->_access->viewdetails = in_array($this->getParams()->get('allow_view_details'), $groups);
  1923. }
  1924. return $this->_access->viewdetails;
  1925. }
  1926. /**
  1927. * checks user access for editing records
  1928. * @param object row of data currently active
  1929. * @return bol access allowed
  1930. */
  1931. function canEdit($row = null)
  1932. {
  1933. $params =& $this->getParams();
  1934. $canUserDo = $this->canUserDo($row, 'allow_edit_details2');
  1935. // $$$ hugh - AAAAAAGHHHH!!! This one took a while ...
  1936. // canUserDo() returns true, false, or -1 ... when "loose" testing with !=
  1937. // then true is the same as -1. But we want strict testing, with !==
  1938. // so it isn't the same!
  1939. // Hmmm - I just noticed canDelete() already has a !== here.
  1940. //if ($canUserDo != -1) {
  1941. if ($canUserDo !== -1) {
  1942. return $canUserDo;
  1943. }
  1944. // $$$ hugh - FIXME - we really need to split out a onCanEditRow method, rather than overloading
  1945. // onCanEdit for both table and per-row contexts. At the moment, we calling per-row plugins with
  1946. // null $row when canEdit() is called in a table context.
  1947. $canEdit = $this->getPluginManager()->runPlugins('onCanEdit', $this, 'list', $row);
  1948. if (in_array(false, $canEdit)) {
  1949. return false;
  1950. }
  1951. if (!is_object($this->_access) || !array_key_exists('edit', $this->_access)) {
  1952. $user = JFactory::getUser();
  1953. $groups = $user->authorisedLevels();
  1954. $this->_access->edit = in_array($this->getParams()->get('allow_edit_details'), $groups);
  1955. //$this->_access->edit = $user->authorise('core.edit', 'com_fabrik.list.'.$this->getTable()->id);
  1956. }
  1957. return $this->_access->edit;
  1958. }
  1959. /**
  1960. * checks if any one row is editalbe = used to get the correct headings
  1961. */
  1962. protected function canEditARow()
  1963. {
  1964. $data = $this->getData();
  1965. foreach ($data as $rows) {
  1966. foreach ($rows as $row) {
  1967. if ($this->canEdit($row)) {
  1968. return true;
  1969. }
  1970. }
  1971. }
  1972. return false;
  1973. }
  1974. /**
  1975. * access control function for determining if the user can perform
  1976. * a designated function on a specific row
  1977. * @param object $row data
  1978. * @param string $col access control setting to compare against
  1979. * @return mixed - if ACL setting defined here return blo, otherwise return -1 to contiune with default acl setting
  1980. */
  1981. function canUserDo($row, $col)
  1982. {
  1983. if (!is_null($row)) {
  1984. $params =& $this->getParams();
  1985. $user = JFactory::getUser();
  1986. $usercol =$params->get($col, '');
  1987. if ($usercol != '') {
  1988. $usercol = FabrikString::safeColNameToArrayKey($usercol);
  1989. if (!array_key_exists($usercol, $row)) {
  1990. return false;
  1991. } else {
  1992. if (array_key_exists($usercol . "_raw", $row)) {
  1993. $usercol .= "_raw";
  1994. }
  1995. $myid = $user->get('id');
  1996. //-1 for menu items that link to their own reocrds
  1997. // $$$ hugh - TODO - test - something doesn't look right about this logic!!
  1998. // $$$ hugh - was $row->$usercol, but $row is an array not an object!
  1999. // $$$ hugh - oops, it's an array when coming here from form, object when coming from table!
  2000. if (is_array($row)) {
  2001. $usercol_val = $row[$usercol];
  2002. }
  2003. else {
  2004. $usercol_val = $row->$usercol;
  2005. }
  2006. if (empty($usercol_val) && empty($myid)) {
  2007. return false;
  2008. }
  2009. if (intVal($usercol_val) === intVal($myid) || JRequest::getVar('rowid') == -1) {
  2010. return true;
  2011. }
  2012. # $$$ hugh - testing making the "or use field" truly an OR, so they can edit
  2013. # if they either have usercol privs or the regular ACL. i.e. if this test fails,
  2014. # don't reurn false, rather drop through and test regular ACL.
  2015. /*
  2016. else {
  2017. return false;
  2018. }
  2019. */
  2020. }
  2021. }
  2022. }
  2023. return -1;
  2024. }
  2025. /**
  2026. * checks user access for deleting records
  2027. * @param object row of data currently active
  2028. * @return bol access allowed
  2029. */
  2030. function canDelete($row = null)
  2031. {
  2032. $canUserDo = $this->canUserDo($row, 'allow_delete2');
  2033. if ($canUserDo !== -1) {
  2034. if ($canUserDo === true) {
  2035. $this->_access->deletePossible = true;
  2036. }
  2037. return $canUserDo;
  2038. }
  2039. if (!is_object($this->_access) || !array_key_exists('delete', $this->_access)) {
  2040. $user = JFactory::getUser();
  2041. $groups = $user->authorisedLevels();
  2042. $this->_access->delete = in_array($this->getParams()->get('allow_delete'), $groups);
  2043. //$this->_access->delete = $user->authorise('core.delete', 'com_fabrik.list.'.$this->getTable()->id);
  2044. }
  2045. return $this->_access->delete;
  2046. }
  2047. /**
  2048. * determin if any record can be deleted - used to see if we include the
  2049. * delete button in the table view
  2050. * @return bol
  2051. */
  2052. function deletePossible()
  2053. {
  2054. if (is_object($this->_access)) {
  2055. if (array_key_exists('deletePossible', $this->_access)) {
  2056. return $this->_access->deletePossible;
  2057. }
  2058. }
  2059. return $this->canDelete();
  2060. }
  2061. /**
  2062. * checks user access for importing csv
  2063. *
  2064. * @return bol access allowed
  2065. */
  2066. public function canCSVImport()
  2067. {
  2068. if (!is_object($this->_access) || !array_key_exists('csvimport', $this->_access)) {
  2069. $user = JFactory::getUser();
  2070. $groups = $user->authorisedLevels();
  2071. $this->_access->csvimport = in_array($this->getParams()->get('csv_import_frontend'), $groups);
  2072. }
  2073. return $this->_access->csvimport;
  2074. }
  2075. /**
  2076. * checks user access for exporting csv
  2077. *
  2078. * @return bol access allowed
  2079. */
  2080. public function canCSVExport()
  2081. {
  2082. if (!is_object($this->_access) || !array_key_exists('csvexport', $this->_access)) {
  2083. $user = JFactory::getUser();
  2084. $groups = $user->authorisedLevels();
  2085. $this->_access->csvexport = in_array($this->getParams()->get('csv_export_frontend'), $groups);
  2086. }
  2087. return $this->_access->csvexport;
  2088. }
  2089. /**
  2090. * checks user access for front end group by
  2091. *
  2092. * @return bol access allowed
  2093. */
  2094. public function canGroupBy()
  2095. {
  2096. if (!is_object($this->_access) || !array_key_exists('groupby', $this->_access)) {
  2097. $user = JFactory::getUser();
  2098. $groups = $user->authorisedLevels();
  2099. $this->_access->groupby = in_array($this->getParams()->get('group_by_access'), $groups);
  2100. }
  2101. return $this->_access->groupby;
  2102. }
  2103. /**
  2104. * checks user access for adding records
  2105. *
  2106. * @return bol access allowed
  2107. */
  2108. function canAdd()
  2109. {
  2110. $params =& $this->getParams();
  2111. if (!is_object($this->_access) || !array_key_exists('add', $this->_access)) {
  2112. $user = JFactory::getUser();
  2113. $groups = $user->authorisedLevels();
  2114. $this->_access->add = in_array($this->getParams()->get('allow_add'), $groups);
  2115. }
  2116. return $this->_access->add;
  2117. }
  2118. /**
  2119. * check use can view the table
  2120. * @return bol can view or not
  2121. */
  2122. function canView()
  2123. {
  2124. if (!is_object($this->_access) || !array_key_exists('view', $this->_access)) {
  2125. $user = JFactory::getUser();
  2126. $groups = $user->authorisedLevels();
  2127. //$this->_access->view = $user->authorise('core.view', 'com_fabrik.list.'.$this->getTable()->id);
  2128. $this->_access->view = in_array($this->getTable()->access, $groups);
  2129. }
  2130. return $this->_access->view;
  2131. }
  2132. /**
  2133. * load the table from the form_id value
  2134. * @param int $formId (jos_fabrik_forms.id)
  2135. * @return object table row
  2136. */
  2137. function loadFromFormId($formId)
  2138. {
  2139. JTable::addIncludePath(JPATH_ADMINISTRATOR.DS.'components'.DS.'com_fabrik'.DS.'table');
  2140. $row = FabTable::getInstance('List', 'FabrikTable');
  2141. $row->load(array('form_id'=>$formId));
  2142. $this->_table = $row;
  2143. $this->setId($row->id);
  2144. $this->setState('list.id', $row->id);
  2145. return $row;
  2146. }
  2147. /**
  2148. * like getJoins() but exclude cascading dropdown joins
  2149. * seems to be needed when calculating related table's record counts.
  2150. * This is called frm within _buildQueryJoin()
  2151. * and fired if this is done:
  2152. * $listModel->set('includeCddInJoin', false);
  2153. * as in tableModel::getRecordCounts()
  2154. * @return array join objects (table rows - not table objects or models)
  2155. */
  2156. function getJoinsNoCdd()
  2157. {
  2158. if (!isset($this->_joinsNoCdd)) {
  2159. $form =& $this->getFormModel();
  2160. $form->getGroupsHiarachy();
  2161. $ignore = array('plgFabrik_ElementCascadingdropdown');
  2162. $ids = $form->getElementIds($ignore);
  2163. $db = FabrikWorker::getDbo(true);
  2164. $id = (int)$this->getId();
  2165. $sql = "SELECT * FROM #__{package}_joins WHERE list_id = ".$id;
  2166. if (!empty($ids)) {
  2167. $sql .= " OR element_id IN ( ".implode(", ", $ids).")";
  2168. }
  2169. //maybe we will have to order by element_id asc to ensure that table joins are loaded
  2170. //before element joins (if an element join is in a table join then its 'join_from_table' key needs to be updated
  2171. $sql .= " ORDER BY id";
  2172. $db->setQuery($sql);
  2173. $this->_joinsNoCdd = $db->loadObjectList();
  2174. if ($db->getErrorNum()) {
  2175. JError::raiseError(500, $db->stderr());
  2176. }
  2177. $this->_makeJoinAliases($this->_joinsNoCdd);
  2178. }
  2179. return $this->_joinsNoCdd;
  2180. }
  2181. /**
  2182. * @return array join objects (table rows - not table objects or models)
  2183. */
  2184. function &getJoins()
  2185. {
  2186. if (!isset($this->_aJoins)) {
  2187. $form =& $this->getFormModel();
  2188. $form->getGroupsHiarachy();
  2189. $ids = $form->getElementIds();
  2190. $db = FabrikWorker::getDbo(true);
  2191. $id = (int)$this->getId();
  2192. $sql = "SELECT * FROM #__{package}_joins WHERE list_id = ".$id;
  2193. if (!empty($ids)) {
  2194. $sql .= " OR element_id IN ( ".implode(", ", $ids).")";
  2195. }
  2196. //maybe we will have to order by element_id asc to ensure that table joins are loaded
  2197. //before element joins (if an element join is in a table join then its 'join_from_table' key needs to be updated
  2198. $sql .= " ORDER BY id";
  2199. $db->setQuery($sql);
  2200. $this->_aJoins = $db->loadObjectList();
  2201. if ($db->getErrorNum()) {
  2202. JError::raiseError(500, $db->stderr());
  2203. }
  2204. $this->_makeJoinAliases($this->_aJoins);
  2205. foreach ($this->_aJoins as &$join) {
  2206. if (!isset($join->_params)) {
  2207. $join->_params = new fabrikParams($join->params);
  2208. }
  2209. }
  2210. }
  2211. return $this->_aJoins;
  2212. }
  2213. function _makeJoinAliases(&$joins)
  2214. {
  2215. $app = JFactory::getApplication();
  2216. $prefix = $app->getCfg('dbprefix');
  2217. $table =& $this->getTable();
  2218. $db = FabrikWorker::getDbo();
  2219. $aliases = array($table->db_table_name);
  2220. $tableGroups = array();
  2221. //build up the alias and $tableGroups array first
  2222. foreach ($joins as &$join) {
  2223. $join->canUse = true;
  2224. if ($join->table_join == '#__users' || $join->table_join == $prefix . 'users') {
  2225. if ($db != $this->getDb()) {
  2226. $join->canUse = false;
  2227. }
  2228. }
  2229. // $$$ rob = check for repeat elements In table view we dont need to add the join
  2230. // as the element data is concatenated into one row. see elementModel::getAsField_html()
  2231. $opts = json_decode($join->params);
  2232. if (isset($opts->type) && $opts->type == 'repeatElement') {
  2233. //if ($join->list_id != 0 && $join->element_id != 0) {
  2234. $join->canUse = false;
  2235. }
  2236. $tablejoin = str_replace('#__', $prefix, $join->table_join);
  2237. if (in_array($tablejoin, $aliases)) {
  2238. $base = $tablejoin;
  2239. $a = $base;
  2240. $c = 0;
  2241. while (in_array($a, $aliases)) {
  2242. $a = "{$base}_{$c}";
  2243. $c ++;
  2244. }
  2245. $join->table_join_alias = $a;
  2246. } else {
  2247. $join->table_join_alias = $tablejoin;
  2248. }
  2249. $aliases[] = str_replace('#__', $prefix, $join->table_join_alias);
  2250. if (!array_key_exists($join->group_id, $tableGroups)) {
  2251. if ($join->element_id == 0) {
  2252. $tableGroups[$join->group_id] = $join->table_join_alias;
  2253. }
  2254. }
  2255. }
  2256. foreach ($joins as &$join) {
  2257. //if they are element joins add in this tables name as the calling joining table.
  2258. if ($join->join_from_table == '') {
  2259. $join->join_from_table = $table->db_table_name;
  2260. }
  2261. // test case:
  2262. /*
  2263. * you have a talbe that joins to a 2nd table
  2264. * in that 2nd table there is a database join element
  2265. * that 2nd elements key needs to point to the 2nd tables name and not the first
  2266. *
  2267. * e.g. when you want to create a n-n relationship
  2268. *
  2269. * events -> (table join) events_artists -> (element join) artist
  2270. */
  2271. $join->keytable = $join->join_from_table;
  2272. if (!array_key_exists($join->group_id, $tableGroups)) {
  2273. } else {
  2274. if ($join->element_id != 0) {
  2275. $join->keytable = $tableGroups[$join->group_id];
  2276. //test
  2277. $join->join_from_table = $join->keytable;
  2278. }
  2279. }
  2280. }
  2281. FabrikHelperHTML::debug($joins, 'joins');
  2282. }
  2283. /**
  2284. * gets the field names for the given table
  2285. * @param string table name
  2286. * @param string field to key return array on
  2287. * @return array table fields
  2288. */
  2289. function getDBFields($tbl = null, $key = null)
  2290. {
  2291. if (is_null($tbl)) {
  2292. $table =& $this->getTable();
  2293. $tbl = $table->db_table_name;
  2294. }
  2295. if ($tbl == '') {
  2296. return array();
  2297. }
  2298. $sig = $tbl.$key;
  2299. $tbl = FabrikString::safeColName($tbl);
  2300. if (!isset($this->_dbFields[$sig])) {
  2301. $db = $this->getDb();
  2302. $tbl =FabrikString::safeColName($tbl);
  2303. $db->setQuery("DESCRIBE ".$tbl);
  2304. $this->_dbFields[$sig] = $db->loadObjectList($key);
  2305. if ($db->getErrorNum()) {
  2306. JError::raiseWarning(500, $db->getErrorMsg());
  2307. $this->_dbFields[$sig] = array();
  2308. }
  2309. }
  2310. return $this->_dbFields[$sig];
  2311. }
  2312. /**
  2313. * called at the end of saving an element
  2314. * if a new element it will run the sql to add to field,
  2315. * if existing element and name changed will create query to be used later
  2316. * @param object $elementModel
  2317. * @param string $origColName
  2318. * @return array($update, $q, $oldName, $newdesc, $origDesc, $dropKey)
  2319. */
  2320. public function shouldUpdateElement(&$elementModel, $origColName = null)
  2321. {
  2322. $db = FabrikWorker::getDbo();
  2323. $return = array(false, '', '', '', '', false);
  2324. $element =& $elementModel->getElement();
  2325. $pluginManager =& $this->getPluginManager();
  2326. $basePlugIn =& $pluginManager->getPlugIn($element->plugin, 'element');
  2327. $fbConfig =& JComponentHelper::getParams('com_fabrik');
  2328. $fabrikDb = $this->getDb();
  2329. $group =& $elementModel->getGroup();
  2330. $dropKey = false;
  2331. //$$$ rob - replaced this with getting the table from the group as if we moved the element
  2332. //from one group to another $this->getTable gives you the old group's table, where as we want
  2333. // the new group's table
  2334. //$table =& $this->getTable();
  2335. $table =& $group->getlistModel()->getTable();
  2336. // $$$ rob - if we are saving an element that wasn't attached to a group then we should
  2337. // get the table id from the group's table
  2338. if ($table->id == '') {
  2339. $table =& $group->getlistModel()->getTable();
  2340. }
  2341. // $$$ hugh - if this is a table-less form ... not much point going any
  2342. // further 'cos things will go BANG
  2343. if (empty($table->id)) {
  2344. return $return;
  2345. }
  2346. if ($this->isView()) {
  2347. return $return;
  2348. }
  2349. if ($group->isJoin()) {
  2350. $tableName = $group->getJoinModel()->getJoin()->table_join;
  2351. $keydata = $keydata[0];
  2352. $primaryKey = $keydata['colname'];
  2353. } else {
  2354. $tableName = $table->db_table_name;
  2355. $primaryKey = $table->db_primary_key;
  2356. }
  2357. $keydata = $this->getPrimaryKeyAndExtra($tableName);
  2358. // $$$ rob base plugin needs to know group info for date fields in non-join repeat groups
  2359. $basePlugIn->_group =& $elementModel->_group;
  2360. $objtype = $elementModel->getFieldDescription(); //the element type AFTER saving
  2361. $dbdescriptions = $this->getDBFields($tableName, 'Field');
  2362. if (!$this->canAlterFields()) {
  2363. $objtype = $dbdescriptions[$origColName]->Type;
  2364. }
  2365. if (is_null($objtype)) {
  2366. return $return;
  2367. }
  2368. $existingfields = array_keys($dbdescriptions);
  2369. $lastfield = $existingfields[count($existingfields)-1];
  2370. $tableName = FabrikString::safeColName($tableName);
  2371. $lastfield = FabrikString::safeColName($lastfield);
  2372. $altered = false;
  2373. if (!array_key_exists($element->name, $dbdescriptions)) {
  2374. if ($origColName == '') {
  2375. $fabrikDb->setQuery("ALTER TABLE $tableName ADD COLUMN ".FabrikString::safeColName($element->name)." $objtype AFTER $lastfield");
  2376. if (!$fabrikDb->query()) {
  2377. return JError::raiseError(500, 'alter structure: ' . $fabrikDb->getErrorMsg());
  2378. }
  2379. $altered = true;
  2380. }
  2381. // commented out as it stops the update when changing an element name
  2382. //return $return;
  2383. }
  2384. $thisFieldDesc = JArrayHelper::getValue($dbdescriptions, $origColName, new stdClass());
  2385. // $$$ rob the Default property for timestamps when they are set to CURRENT_TIMESTAMP
  2386. // doesn't show up from getDBFields() - so presuming a timestamp field will always default
  2387. // to the current timestamp (update of the field's data controller in the Extra property (on update CURRENT_TIMESTAMP)
  2388. $existingDef = '';
  2389. if (isset($thisFieldDesc->Type)) {
  2390. $existingDef = $thisFieldDesc->Type;
  2391. if ($thisFieldDesc->Type == 'timestamp') {
  2392. $existingDef .= $thisFieldDesc->Null = 'YES' ? ' NULL' : ' NOT NULL';
  2393. $existingDef .= ' DEFAULT CURRENT_TIMESTAMP';
  2394. $existingDef .= ' ' . $thisFieldDesc->Extra;
  2395. }
  2396. }
  2397. //if its the primary 3.0
  2398. for ($k = 0; $k < count($keydata); $k++) {
  2399. if ($keydata[$k]['colname'] == $origColName) {
  2400. $existingDef .= " ".$keydata[$k]['extra'];
  2401. }
  2402. }
  2403. if (!is_null($objtype)) {
  2404. $lowerobjtype= strtolower(trim($objtype));
  2405. $lowerobjtype = str_replace(' not null', '', $lowerobjtype);
  2406. if ($element->name == $origColName && strtolower(trim($existingDef)) == $lowerobjtype) {
  2407. //no chanages to the element name or field type
  2408. return $return;
  2409. }
  2410. $return[4] = $existingDef;
  2411. $existingfields = array_keys($dbdescriptions);
  2412. $lastfield = $existingfields[count($existingfields)-1];
  2413. $element->name = FabrikString::safeColName($element->name);
  2414. $tableName = FabrikString::safeColName($tableName);
  2415. $lastfield = FabrikString::safeColName($lastfield);
  2416. // $$$ rob this causes issues when renaming an element with the same name but different upper/lower case
  2417. //if (empty($origColName) || !in_array(strtolower($origColName ), $existingfields)) {
  2418. if (empty($origColName) || !in_array(($origColName), $existingfields)) {
  2419. if (!$altered) {
  2420. $fabrikDb->setQuery("ALTER TABLE $tableName ADD COLUMN $element->name $objtype AFTER $lastfield");
  2421. if (!$fabrikDb->query()) {
  2422. return JError::raiseError(500, 'alter structure: ' . $fabrikDb->getErrorMsg());
  2423. }
  2424. }
  2425. } else {
  2426. // $$$ rob don't alter it yet - lets defer this and give the user the choice if they
  2427. // really want to do this
  2428. if ($this->canAlterFields()) {
  2429. if ($origColName == null) {
  2430. $origColName = $element->name;
  2431. } else {
  2432. $origColName = $fabrikDb->nameQuote($origColName);
  2433. }
  2434. if (strtolower($objtype) == 'blob') {
  2435. $dropKey = true;
  2436. }
  2437. $q = "ALTER TABLE $tableName CHANGE $origColName $element->name $objtype ";
  2438. if ($primaryKey == $fabrikDb->NameQuote($tableName) . "." . $element->name && $table->auto_inc) {
  2439. if (!strstr($q, 'NOT NULL AUTO_INCREMENT')) {
  2440. $q .= " NOT NULL AUTO_INCREMENT ";
  2441. }
  2442. }
  2443. $origColName = FabrikString::safeColName($origColName);
  2444. $return[0] = true;
  2445. $return[1] = $q;
  2446. $return[2] = $origColName;
  2447. $return[3] = $objtype;
  2448. $return[5] = $dropKey;
  2449. return $return;
  2450. }
  2451. }
  2452. }
  2453. return $return;
  2454. }
  2455. /**
  2456. * add or update a database column via sql
  2457. * @param object element plugin
  2458. * @param string origional field name
  2459. */
  2460. function alterStructure(&$elementModel, $origColName = null)
  2461. {
  2462. $db = FabrikWorker::getDbo();
  2463. $element =& $elementModel->getElement();
  2464. $pluginManager =& $this->getPluginManager();
  2465. $basePlugIn =& $pluginManager->getPlugIn($element->plugin, 'element');
  2466. $fbConfig =& JComponentHelper::getParams('com_fabrik');
  2467. $fabrikDb = $this->getDb();
  2468. $table =& $this->getTable();
  2469. $tableName = $table->db_table_name;
  2470. // $$$ rob base plugin needs to know group info for date fields in non-join repeat groups
  2471. $basePlugIn->_group =& $elementModel->_group;
  2472. $objtype = $elementModel->getFieldDescription();
  2473. $dbdescriptions = $this->getDBFields($tableName);
  2474. if (!$this->canAlterFields()) {
  2475. foreach ($dbdescriptions as $f) {
  2476. if ($f->Field == $origColName) {
  2477. $objtype = $f->Type;
  2478. }
  2479. }
  2480. }
  2481. if (!is_null($objtype)) {
  2482. foreach ($dbdescriptions as $dbdescription) {
  2483. $fieldname = strtolower($dbdescription->Field);
  2484. if (strtolower($element->name) == $fieldname && strtolower($dbdescription->Type) == strtolower($objtype)) {
  2485. return;
  2486. }
  2487. $existingfields[] = $fieldname;
  2488. }
  2489. $lastfield = $fieldname;
  2490. $element->name = FabrikString::safeColName($element->name);
  2491. $tableName = FabrikString::safeColName($tableName);
  2492. $lastfield = FabrikString::safeColName($lastfield);
  2493. // @TODO - Rob, please sanity check this!
  2494. // $$$ hugh - erm, this if statement MUST be wrong! Otherwise we can never change an element name,
  2495. // it'll always create a new colum.
  2496. // if (!in_array(strtolower($name ), $existingfields) || !in_array(strtolower($origColName ), $existingfields)) {
  2497. if (empty($origColName) || !in_array(strtolower($origColName), $existingfields)) {
  2498. $fabrikDb->setQuery("ALTER TABLE $tableName ADD COLUMN $element->name $objtype AFTER $lastfield");
  2499. if (!$fabrikDb->query()) {
  2500. return JError::raiseError(500, 'alter structure: ' . $fabrikDb->getErrorMsg());
  2501. }
  2502. } else {
  2503. if ($this->canAlterFields()) {
  2504. if ($origColName == null) {
  2505. $origColName = $element->name;
  2506. }
  2507. $origColName = FabrikString::safeColName($origColName);
  2508. $fabrikDb->setQuery("ALTER TABLE $tableName CHANGE $origColName $element->name $objtype");
  2509. if (!$fabrikDb->query()) {
  2510. return JError::raiseError(500, 'alter structure: ' . $fabrikDb->getErrorMsg());
  2511. }
  2512. }
  2513. }
  2514. }
  2515. return true;
  2516. }
  2517. /**
  2518. * can we alter this tables fields structure?
  2519. * @return bol
  2520. */
  2521. public function canAlterFields()
  2522. {
  2523. $fbConfig =& JComponentHelper::getParams('com_fabrik');
  2524. $params =& $this->getParams();
  2525. $alter = $params->get('alter_existing_db_cols', 'notset');
  2526. if ($alter == 'notset') {
  2527. //fall back to old global settting
  2528. $alter = $fbConfig->get('fbConf_alter_existing_db_cols', true);
  2529. }
  2530. return $alter;
  2531. }
  2532. /**
  2533. * if not loaded this loads in the table's form model
  2534. * also binds a reference of the table to the form.
  2535. * @return object form model with form table loaded
  2536. */
  2537. function &getFormModel()
  2538. {
  2539. if (!isset($this->_oForm)) {
  2540. $this->_oForm = JModel::getInstance('Form', 'FabrikFEModel');
  2541. $table =& $this->getTable();
  2542. $this->_oForm->setId($table->form_id);
  2543. $this->_oForm->getForm();
  2544. $this->_oForm->setListModel($this);
  2545. }
  2546. return $this->_oForm;
  2547. }
  2548. function setFormModel($model)
  2549. {
  2550. $this->_oForm = $model;
  2551. }
  2552. /**
  2553. * tests if the table is in fact a view
  2554. * @returns true if table is a view
  2555. */
  2556. function isView()
  2557. {
  2558. $params =& $this->getParams();
  2559. $isview = $params->get('isview', null);
  2560. // $$$ hugh - because querying INFORMATION_SCHEMA can be very slow (like minutes!) on
  2561. // a shared host, I made a small change. The edit table view now adds a hidden 'isview'
  2562. // param, defaulting to -1 on new tables. So the following code should only ever execute
  2563. // one time, when a new table is saved. Before this change, because 'isview' wasn't
  2564. // included on the edit view (because it's not a "real" user settable param), so didn't
  2565. // exist when we picked up the params from the submitted data, this code was running (twice!)
  2566. // every time a table was saved.
  2567. // http://fabrikar.com/forums/showthread.php?t=16622&page=6
  2568. if (is_null($isview) || (int)$isview < 0) {
  2569. if (isset($this->_isview)) {
  2570. return $this->_isview;
  2571. }
  2572. $db = FabrikWorker::getDbo();
  2573. $table =& $this->getTable();
  2574. $cn = $this->getConnection();
  2575. $c = $cn->getConnection();
  2576. $dbname = $c->database;
  2577. if ($table->db_table_name == '') {
  2578. return;
  2579. }
  2580. $sql = " SELECT table_name, table_type, engine FROM INFORMATION_SCHEMA.tables ".
  2581. "WHERE table_name = " . $db->Quote($table->db_table_name) ." AND table_type = 'view' AND table_schema = " . $db->Quote($dbname);
  2582. $db->setQuery($sql);
  2583. $row = $db->loadObjectList();
  2584. if (empty($row)) {
  2585. $isview = 0;
  2586. $this->_isview = 0;
  2587. } else {
  2588. // $$$ hugh - not quite sure why we are testing empty($row) again??
  2589. $isview = empty($row) ? false : true;
  2590. $this->_isview = $isview ? 1 : 0;
  2591. }
  2592. //store and save param for following tests
  2593. $params->set('isview', $isview);
  2594. $table->store();
  2595. }
  2596. return $isview;
  2597. }
  2598. /**
  2599. * store filters in the registry
  2600. * @param array filters to store
  2601. * @return null
  2602. */
  2603. function storeRequestData($request)
  2604. {
  2605. $app = JFactory::getApplication();
  2606. $session = JFactory::getSession();
  2607. $registry =& $session->get('registry');
  2608. $tid = 'list'.$this->getId();
  2609. //make sure that we only store data thats been entered from this page first test we aren't in a plugin
  2610. if (JRequest::getCmd('option') == 'com_fabrik' && is_object($registry)) {
  2611. // dont do this when you are viewing a form or details page as it wipes out the table filters
  2612. $reg =& $registry->get('_registry');
  2613. if (isset($reg['com_fabrik']) && !in_array(JRequest::getCmd('view'), array('form', 'details'))) {
  2614. unset($reg['com_fabrik']['data']->$tid->filter);
  2615. }
  2616. }
  2617. //@TODO test for _clear_ in values and if so delete session data
  2618. foreach ($request as $key => $val) {
  2619. if (is_array($val)) {
  2620. $key = 'com_fabrik.'. $tid .'.filter.'.$key;
  2621. $app->setUserState($key, array_values($val));
  2622. }
  2623. }
  2624. if (isset($reg['com_fabrik']) && array_key_exists($tid, $reg['com_fabrik']['data'])) {
  2625. FabrikHelperHTML::debug($reg['com_fabrik']['data']->$tid, 'session filters saved as:');
  2626. }
  2627. else {
  2628. FabrikHelperHTML::debug('', 'session filters saved as: no filters to save!');
  2629. }
  2630. }
  2631. /**
  2632. * creates filter array (return existing if exists)
  2633. *@return array filters
  2634. */
  2635. function &getFilterArray()
  2636. {
  2637. if (isset($this->filters)) {
  2638. return $this->filters;
  2639. }
  2640. $filterModel =& $this->getFilterModel();
  2641. $db = FabrikWorker::getDbo();
  2642. $this->filters = array();
  2643. $user = JFactory::getUser();
  2644. $request = $this->getRequestData();
  2645. $this->storeRequestData($request);
  2646. FabrikHelperHTML::debug($request, 'filter:request');
  2647. $params =& $this->getParams();
  2648. $elements =& $this->getElements('id');
  2649. // $$$ rob prefilters loaded before anything to avoid issues where you filter on something and
  2650. // you have 2 prefilters with joined by an OR - this was incorrectly giving SQL of
  2651. // WHERE normal filter = x OR ( prefilter1 = y OR prefilter2 = x)
  2652. // this change changes the SQL to
  2653. // WHERE ( prefilter1 = y OR prefilter2 = x) AND normal filter = x
  2654. $this->getPrefilterArray($this->filters);
  2655. // these are filters created from a search form or normal search
  2656. $keys = array_keys($request);
  2657. $indexStep = count(JArrayHelper::getValue($this->filters, 'key', array()));
  2658. FabrikHelperHTML::debug($keys, 'filter:request keys');
  2659. foreach ($keys as $key) {
  2660. if (is_array($request[$key])) {
  2661. foreach ($request[$key] as $kk => $v) {
  2662. if (!array_key_exists($key, $this->filters) || !is_array($this->filters[$key])) {
  2663. $this->filters[$key] = array();
  2664. }
  2665. $this->filters[$key][$kk + $indexStep] = $v;
  2666. }
  2667. }
  2668. }
  2669. FabrikHelperHTML::debug($this->filters, 'tablemodel::getFilterArray middle');
  2670. $readOnlyValues = array();
  2671. $w = new FabrikWorker();
  2672. $noFiltersSetup = JArrayHelper::getValue($this->filters, 'no-filter-setup', array());
  2673. if (count($this->filters) == 0) {
  2674. $this->getPluginManager()->runPlugins('onFiltersGot', $this, 'list');
  2675. return $this->filters;
  2676. }
  2677. //get a list of plugins
  2678. $pluginKeys = $filterModel->getPluginFilterKeys();
  2679. $elementids = JArrayHelper::getValue($this->filters, 'elementid', array());
  2680. $sqlCond = JArrayHelper::getValue($this->filters, 'sqlCond', array());
  2681. $raws = JArrayHelper::getValue($this->filters, 'raw', array());
  2682. //for ($i=0; $i < count($this->filters['key']); $i++) {
  2683. foreach ($this->filters['key'] as $i => $keyval) {
  2684. $value = $this->filters['value'][$i];
  2685. $condition = strtolower($this->filters['condition'][$i]);
  2686. $key = $this->filters['key'][$i];
  2687. $filterEval = $this->filters['eval'][$i];
  2688. $elid = JArrayHelper::getValue($elementids, $i);
  2689. $key2 = array_key_exists('key2', $this->filters) ? JArrayHelper::getValue($this->filters['key2'], $i, '') : '';
  2690. // $$$ rob see if the key is a raw filter
  2691. // 20/12/2010 - think $key is never with _raw now as it is unset in tablefilter::getQuerystringFilters() although may be set elsewhere
  2692. // - if it is make a note and remove the _raw from the name
  2693. $raw = JArrayHelper::getValue($raws, $i, false);
  2694. if (substr($key, -5, 5) == '_raw`') {
  2695. $key = substr($key, 0, strlen($key) -5) . '`';
  2696. $raw = true;
  2697. }
  2698. if ($elid == -1) {
  2699. //bool match
  2700. $this->filters['origvalue'][$i] = $value;
  2701. $this->filters['sqlCond'][$i] = $key.' '.$condition.' ('.$db->Quote($value) . ' IN BOOLEAN MODE)';
  2702. continue;
  2703. }
  2704. //table plug-in filter found - it should have set its own sql in onGetPostFilter();
  2705. if (in_array($elid, $pluginKeys)) {
  2706. $this->filters['origvalue'][$i] = $value;
  2707. $this->filters['sqlCond'][$i] = $this->filters['sqlCond'][$i];
  2708. continue;
  2709. }
  2710. $elementModel = JArrayHelper::getValue($elements, $elid);
  2711. // $$$ rob key2 if set is in format `countries_0`.`label` rather than `countries`.`label`
  2712. // used for search all filter on 2nd db join element pointing to the same table
  2713. if (strval($key2) !== '') {
  2714. $key = $key2;
  2715. }
  2716. $eval = $this->filters['eval'][$i];
  2717. $fullWordsOnly = $this->filters['full_words_only'][$i];
  2718. $exactMatch = $this->filters['match'][$i];
  2719. if (!is_a($elementModel, 'plgFabrik_Element')) {
  2720. continue;
  2721. }
  2722. $elementModel->_rawFilter = $raw;
  2723. // $$ hugh - testing allowing {QS} replacements in pre-filter values
  2724. $w->replaceRequest($value);
  2725. $value = $this->_prefilterParse($value);
  2726. $value = $w->parseMessageForPlaceHolder($value);
  2727. if ($filterEval == '1') {
  2728. // $$$ rob hehe if you set $i in the eval'd code all sorts of chaos ensues
  2729. $origi = $i;
  2730. $value = stripslashes(htmlspecialchars_decode($value, ENT_QUOTES));
  2731. $value = @eval($value);
  2732. FabrikWorker::logEval($value, 'Caught exception on eval of tableModel::getFilterArray() '. $key . ': %s');
  2733. $i = $origi;
  2734. }
  2735. if ($condition == 'regexp') {
  2736. $condition = 'REGEXP';
  2737. // $$$ 30/06/2011 rob dont escape the search as it may contain \\\ from preg_escape (e.g. search all on 'c+b)
  2738. $value = $db->quote($value, false);
  2739. }
  2740. else if ($condition == 'like') {
  2741. $condition = 'LIKE';
  2742. $value = $db->Quote($value);
  2743. }else if ($condition == 'laterthisyear' || $condition == 'earlierthisyear') {
  2744. $value = $db->Quote($value);
  2745. }
  2746. if ($fullWordsOnly == '1') {
  2747. $condition = 'REGEXP';
  2748. }
  2749. $originalValue = $this->filters['value'][$i];
  2750. list($value, $condition) = $elementModel->getFilterValue($value, $condition, $eval);
  2751. if ($fullWordsOnly == '1') {
  2752. if (is_array($value)) {
  2753. foreach ($value as &$v) {
  2754. $v = "\"[[:<:]]" . $v . "[[:>:]]\"";
  2755. }
  2756. } else {
  2757. $value = "\"[[:<:]]" . $value . "[[:>:]]\"";
  2758. }
  2759. }
  2760. if (!array_key_exists($i, $sqlCond) || $sqlCond[$i] == '') {
  2761. $query = $elementModel->getFilterQuery($key, $condition, $value, $originalValue, $this->filters['search_type'][$i]);
  2762. $this->filters['sqlCond'][$i] = $query;
  2763. }
  2764. $this->filters['condition'][$i] = $condition;
  2765. $this->filters['origvalue'][$i] = $originalValue; //used when getting the selected dropdown filter value
  2766. $this->filters['value'][$i] = $value;
  2767. if (!array_key_exists($i, $noFiltersSetup)) {
  2768. $this->filters['no-filter-setup'][$i] = 0;
  2769. }
  2770. if ($this->filters['no-filter-setup'][$i] == 1) {
  2771. $tmpName = $elementModel->getFullName(false, true, false);
  2772. $tmpData = array($tmpName => $originalValue, $tmpName . "_raw" => $originalValue);
  2773. //set defaults to null to ensure we get correct value for 2nd dropdown search value (mutli dropdown from search form)
  2774. $elementModel->defaults = null;
  2775. if (array_key_exists($key, $readOnlyValues)) {
  2776. $readOnlyValues[$key][] = $elementModel->_getROElement($tmpData);
  2777. } else {
  2778. $readOnlyValues[$key] = array($elementModel->_getROElement($tmpData));
  2779. }
  2780. //set it back to null again so that in form view we dont return this value.
  2781. $elementModel->defaults = null;
  2782. // filter value assinged in readOnlyValues foreach loop towards end of this function
  2783. $this->filters['filter'][$i] = '';
  2784. } else {
  2785. //$$$rob not sure $value is the right var to put in here - or if its acutally used
  2786. // but without this line you get warnings about missing variable in the filter array
  2787. $this->filters['filter'][$i] = $value;
  2788. }
  2789. }
  2790. FabrikHelperHTML::debug($this->filters, 'end filters');
  2791. foreach ($readOnlyValues as $key => $val) {
  2792. foreach ($this->filters['key'] as $i => $fkey) {
  2793. if ($fkey === $key) {
  2794. $this->filters['filter'][$i] = implode("<br>", $val);
  2795. }
  2796. }
  2797. }
  2798. $this->getPluginManager()->runPlugins('onFiltersGot', $this, 'list');
  2799. FabrikHelperHTML::debug($this->filters, 'after plugins:onFiltersGot');
  2800. return $this->filters;
  2801. }
  2802. /**
  2803. * creates array of prefilters
  2804. * @param array filters
  2805. * @return array prefilters combinde with filters
  2806. */
  2807. function getPrefilterArray(&$filters)
  2808. {
  2809. if (!isset($this->prefilters)) {
  2810. $params =& $this->getParams();
  2811. $elements =& $this->getElements('filtername');
  2812. $afilterJoins = $params->get('filter-join', '', '_default', 'array');
  2813. $afilterFields = $params->get('filter-fields', '', '_default', 'array');
  2814. $afilterConditions = $params->get('filter-conditions', '', '_default', 'array');
  2815. $afilterValues = $params->get('filter-value', '', '_default', 'array');
  2816. $afilterAccess = $params->get('filter-access', '', '_default', 'array');
  2817. $afilterEval = $params->get('filter-eval', '', '_default', 'array');
  2818. $afilterGrouped = $params->get('filter-grouped', '', '_default', 'array');
  2819. $join = 'WHERE';
  2820. $w = new FabrikWorker();
  2821. for ($i=0; $i < count($afilterFields); $i++) {
  2822. if (!array_key_exists(0, $afilterJoins) || $afilterJoins[0] == '') {
  2823. $afilterJoins[0] = 'AND';
  2824. }
  2825. $join = $afilterJoins[$i];
  2826. if (trim(strtolower($join)) == 'where') {
  2827. $join = "AND";
  2828. }
  2829. $filter = $afilterFields[$i];
  2830. $condition = $afilterConditions[$i];
  2831. $selValue = JArrayHelper::getValue($afilterValues, $i, '');
  2832. $filterEval = JArrayHelper::getValue($afilterEval, $i, false);
  2833. $filterGrouped = $afilterGrouped[$i];
  2834. $selAccess = $afilterAccess[$i];
  2835. if (!$this->mustApplyFilter($selAccess)) {
  2836. continue;
  2837. }
  2838. $tmpfilter = strstr($filter, '_raw`') ? FabrikString::rtrimword( $filter, '_raw`').'`' : $filter;
  2839. $elementModel =& JArrayHelper::getValue($elements, FabrikString::safeColName($tmpfilter), false);
  2840. if ($elementModel === false) {
  2841. JError::raiseNotice(500, 'A prefilter has been set up on an unpublished element, and will not be applied:' . FabrikString::safeColName($tmpfilter));
  2842. continue;
  2843. }
  2844. $filters['join'][] = $join;
  2845. $filters['search_type'][] = 'prefilter';
  2846. $filters['key'][] = $filter;
  2847. $filters['value'][] = $selValue;
  2848. $filters['origvalue'][] = $selValue;
  2849. $filters['sqlCond'][] = '';
  2850. $filters['no-filter-setup'][] = null;
  2851. $filters['condition'][] = $condition;
  2852. $filters['grouped_to_previous'][] = $filterGrouped;
  2853. $filters['eval'][] = $filterEval;
  2854. $filters['match'][] = ($condition == 'equals') ? 1 : 0;
  2855. $filters['full_words_only'][] = 0;
  2856. $filters['label'][] = '';
  2857. $filters['access'][] = '';
  2858. $filters['key2'][] = '';
  2859. $filters['required'][] = 0;
  2860. $filters['hidden'][] = false;
  2861. $filters['elementid'][] = $elementModel !== false ? $elementModel->getElement()->id : 0;
  2862. $this->prefilters = true;
  2863. }
  2864. }
  2865. FabrikHelperHTML::debug($filters, 'prefilters');
  2866. }
  2867. /**
  2868. * get the total number of records in the table
  2869. * @return int total number of records
  2870. */
  2871. function getTotalRecords()
  2872. {
  2873. // $$$ rob ensure that the limits are set - otherwise can create monster query
  2874. $this->setLimits();
  2875. $session = JFactory::getSession();
  2876. $context = 'com_fabrik.table'. $this->getId().'.total';
  2877. if (isset($this->totalRecords)) {
  2878. $session->set($context, $this->totalRecords);
  2879. return $this->totalRecords;
  2880. }
  2881. // $$$ rob getData() should always be run first
  2882. if (is_null($this->_data)) {
  2883. $this->getData();
  2884. return $this->totalRecords;
  2885. }
  2886. if ($this->mergeJoinedData()) {
  2887. $this->totalRecords = $this->getJoinMergeTotalRecords();
  2888. $session->set($context, $this->totalRecords);
  2889. return $this->totalRecords;
  2890. }
  2891. }
  2892. /**
  2893. * modified version of getTotalRecords() for use when the table join data
  2894. * is to be merged on the main table's primary key
  2895. * @return int total records
  2896. */
  2897. protected function getJoinMergeTotalRecords()
  2898. {
  2899. $db = $this->getDb();
  2900. $table = $this->getTable();
  2901. $count = "DISTINCT " .$table->db_primary_key;
  2902. $totalSql = "SELECT COUNT(" . $count . ") AS t FROM ".$table->db_table_name." " . $this->_buildQueryJoin();
  2903. $totalSql .= " " . $this->_buildQueryWhere(JRequest::getVar('incfilters', 1));
  2904. $totalSql .= " " . $this->_buildQueryGroupBy();
  2905. $totalSql = $this->pluginQuery($totalSql);
  2906. $db->setQuery($totalSql);
  2907. FabrikHelperHTML::debug($db->getQuery(), 'table getJoinMergeTotalRecords');
  2908. $total = $db->loadResult();
  2909. return $total;
  2910. }
  2911. /**
  2912. * load in the elements for the table's form
  2913. * If no form loaded for the table object then one is loaded
  2914. * @return array element objects
  2915. */
  2916. function getFormGroupElementData()
  2917. {
  2918. return $this->getFormModel()->getGroupsHiarachy();
  2919. }
  2920. /**
  2921. * require the correct pagenav class based on template
  2922. *
  2923. * @param int total
  2924. * @param int start
  2925. * @param int length
  2926. * @return object pageNav
  2927. */
  2928. function &getPagination($total = 0, $limitstart = 0, $limit = 0)
  2929. {
  2930. $db = FabrikWorker::getDbo();
  2931. if (!isset($this->nav)) {
  2932. if ($this->randomRecords) {
  2933. $limitstart = $this->getRandomLimitStart();
  2934. }
  2935. $params =& $this->getParams();
  2936. $this->nav = new FPagination($total, $limitstart, $limit);
  2937. // $$$ rob set the nav link urls to the table action to avoid messed up url links when
  2938. // doing ranged filters via the querystring
  2939. $this->nav->url = $this->getTableAction();
  2940. $this->nav->showAllOption = $params->get('showall-records', false);
  2941. $this->nav->setId($this->getId());
  2942. $this->nav->showTotal = $params->get('show-total', false);
  2943. $this->nav->showDisplayNum = $params->get('show_displaynum', true);
  2944. }
  2945. return $this->nav;
  2946. }
  2947. /**
  2948. * get the random lmit start val
  2949. * @return int limit start
  2950. */
  2951. protected function getRandomLimitStart()
  2952. {
  2953. if (isset($this->randomLimitStart)) {
  2954. return $this->randomLimitStart;
  2955. }
  2956. $db =& $this->getDb();
  2957. $table =& $this->getTable();
  2958. // $$$ rob @todo - do we need to add the join in here as well?
  2959. // added + 1 as with 4 records to show 3 4th was not shown
  2960. $db->setQuery("SELECT FLOOR(RAND() * COUNT(*) + 1) AS ".$db->nameQuote('offset')." FROM ". $db->nameQuote($table->db_table_name) . " " . $this->_buildQueryWhere());
  2961. $limitstart = $db->loadResult();
  2962. //$$$ rob 11/01/2011 cant do this as we dont know what the total is yet
  2963. //$$$ rob ensure that the limitstart + limit isn't greater than the total
  2964. /*if ($limitstart + $limit > $total) {
  2965. $limitstart = $total - $limit;
  2966. }*/
  2967. // $$$ rob 25/02/2011 if you only have say 3 reocrds then above random will show 1 2 or 3 records
  2968. // so decrease the random start num by the table row dispaly num
  2969. // going to favour records at the beginning of the table though
  2970. $limitstart -= $table->rows_per_page;
  2971. if ($limitstart < 0) { $limitstart = 0;}
  2972. $this->randomLimitStart = $limitstart;
  2973. return $limitstart;
  2974. }
  2975. /**
  2976. * used to determine which filter action to use
  2977. *if a filter is a range then override tables setting with onsubmit
  2978. */
  2979. function getFilterAction()
  2980. {
  2981. if (!isset($this->_real_filter_action)) {
  2982. $form =& $this->getFormModel();
  2983. $table =& $this->getTable();
  2984. $this->_real_filter_action = $table->filter_action;
  2985. $groups =& $form->getGroupsHiarachy();
  2986. foreach ($groups as $groupModel) {
  2987. $elementModels = $groupModel->getPublishedElements();
  2988. foreach ($elementModels as $elementModel) {
  2989. $element = $elementModel->getElement();
  2990. if (isset($element->filter_type) && $element->filter_type <> '') {
  2991. if ($elementModel->canView() && $elementModel->canUseFilter() && $element->show_in_list_summary == '1') {
  2992. //if ($element->filter_type == 'range' || $element->filter_type == 'auto-complete') {
  2993. if ($element->filter_type == 'range') {
  2994. $this->_real_filter_action = 'submitform';
  2995. return $this->_real_filter_action;
  2996. }
  2997. }
  2998. }
  2999. }
  3000. }
  3001. }
  3002. return $this->_real_filter_action;
  3003. }
  3004. /**
  3005. * gets the part of a url to describe the key that the link links to
  3006. * if a table this is rowid=x
  3007. * if a view this is view_primary_key={where statement}
  3008. *
  3009. * @param object row $data
  3010. * @return string
  3011. */
  3012. function getKeyIndetifier($data)
  3013. {
  3014. return "&rowid=". $this->getSlug($data);
  3015. }
  3016. /**
  3017. * format the row id slug
  3018. * @param object $row data
  3019. * @return string formatted slug
  3020. */
  3021. protected function getSlug($row)
  3022. {
  3023. return empty($row->slug) ? '' : str_replace(' ', '-', $row->slug);
  3024. }
  3025. /**
  3026. * *get detailed info on each of the tables fields
  3027. *
  3028. * @return unknown
  3029. */
  3030. function _fetchFields()
  3031. {
  3032. $table =& $this->getTable();
  3033. $db = $this->getDb();
  3034. $db->setQuery("SELECT * FROM ".$db->nameQuote($table->db_table_name)." LIMIT 1");
  3035. if (!($result = $db->query())) {
  3036. return null;
  3037. }
  3038. $fields = array();
  3039. $num_fields = mysql_num_fields($result);
  3040. for ($i = 0; $i < $num_fields; $i++) {
  3041. $fields[] = mysql_fetch_field($result, $i);
  3042. }
  3043. return $fields;
  3044. }
  3045. /**
  3046. * @return array of element objects that are database joins and that
  3047. * use this table's key as their foregin key
  3048. */
  3049. function getJoinsToThisKey()
  3050. {
  3051. if (is_null($this->_joinsToThisKey)) {
  3052. $this->_joinsToThisKey = array();
  3053. $db = FabrikWorker::getDbo(true);
  3054. $table =& $this->getTable();
  3055. if ($table->id == 0) {
  3056. $this->_joinsToThisKey = array();
  3057. } else {
  3058. $usersConfig = JComponentHelper::getParams('com_fabrik');
  3059. $query = $db->getQuery(true);
  3060. // Select the required fields from the table.
  3061. $query->select(
  3062. "db_table_name,
  3063. name, plugin, l.label AS listlabel, l.id as list_id, \n
  3064. el.id AS element_id, el.label AS element_label, f.id AS form_id"
  3065. );
  3066. $query->from('#__{package}_elements AS el');
  3067. $query->join('LEFT', '#__{package}_formgroup AS fg ON fg.group_id = el.group_id');
  3068. $query->join('LEFT', '#__{package}_forms AS f ON f.id = fg.form_id');
  3069. $query->join('LEFT', '#__{package}_lists AS l ON l.form_id = f.id');
  3070. $query ->where('el.published = 1');
  3071. $query->where("(plugin = 'databasejoin' AND el.params like '%\"join_db_name\":\"".$table->db_table_name."\"%'
  3072. AND el.params like '%\"join_conn_id\":\"".$table->connection_id."%') OR (plugin = 'cascadingdropdown' AND \n" .
  3073. " el.params like '\"%cascadingdropdown_table\":\"".$table->id."\"%' \n" .
  3074. "AND el.params like '\"%cascadingdropdown_connection\":\"".$table->connection_id."\"%') ", "OR");
  3075. // load in user element links as well
  3076. //$$$rob - not convinced this is a good idea
  3077. if ($usersConfig->get('user_elements_as_related_data', false) == true) {
  3078. $query->where( "(plugin = 'user' AND
  3079. el.params like '%\"join_conn_id\":\"".$table->connection_id."%\"' )", "OR");
  3080. }
  3081. $db->setQuery($query);
  3082. $this->_joinsToThisKey = $db->loadObjectList();
  3083. if ($db->getErrorNum()) {
  3084. $this->_joinsToThisKey = array();
  3085. JError::raiseWarning(500, 'getJoinsToThisKey: ' . $db->getErrorMsg());
  3086. }
  3087. }
  3088. }
  3089. return $this->_joinsToThisKey;
  3090. }
  3091. /**
  3092. * get an array of elements that point to a form where their data will be filtered
  3093. * @return array
  3094. */
  3095. function getLinksToThisKey()
  3096. {
  3097. if (!is_null($this->aJoinsToThisKey)) {
  3098. return $this->aJoinsToThisKey;
  3099. }
  3100. $params =& $this->getParams();
  3101. $this->aJoinsToThisKey = array();
  3102. $facted = $params->get('factedlinks', new stdClass());
  3103. if (!isset($facted->linkedform)) {
  3104. return $this->aJoinsToThisKey;
  3105. }
  3106. $linkedForms = $facted->linkedform;
  3107. $aAllJoinsToThisKey = $this->getJoinsToThisKey();
  3108. foreach ($aAllJoinsToThisKey as $join) {
  3109. $key = "{$join->list_id}-{$join->form_id}-{$join->element_id}";
  3110. if (isset($linkedForms->$key)) {
  3111. $this->aJoinsToThisKey[] = $join;
  3112. }else{
  3113. // $$$ rob required for releated form links. otherwise links for forms not listed first in the admin options wherent being rendered
  3114. $this->aJoinsToThisKey[] = false;
  3115. }
  3116. }
  3117. return $this->aJoinsToThisKey;
  3118. }
  3119. public function getEmptyDataMsg()
  3120. {
  3121. if (isset($this->emptyMsg)){
  3122. return $this->emptyMsg;
  3123. }
  3124. $params =& $this->getParams();
  3125. return $params->get('empty_data_msg', JText::_('COM_FABRIK_LIST_NO_DATA_MSG'));
  3126. }
  3127. /**
  3128. * have all the required filters been met?
  3129. *
  3130. * @return bol true if they have if false we shouldnt show the table data
  3131. */
  3132. function getRequiredFiltersFound()
  3133. {
  3134. if (isset($this->requiredFilterFound)) {
  3135. return $this->requiredFilterFound;
  3136. }
  3137. $filters =& $this->getFilterArray();
  3138. $elements =& $this->getElements();
  3139. $required = array();
  3140. foreach ($elements as $kk => $val2) {
  3141. $elementModel = $elements[$kk]; //dont do with =& as this foobars up the last elementModel
  3142. $element =& $elementModel->getElement();
  3143. if ($element->filter_type <> '' && $element->filter_type != 'null') {
  3144. if ($elementModel->canView() && $elementModel->canUseFilter()) {
  3145. //force the correct group model into the element model to ensure no wierdness in getting the element name
  3146. if ($elementModel->getParams()->get('filter_required') == 1) {
  3147. $name = FabrikString::safeColName($elementModel->getFullName(false, false, false));
  3148. if (array_key_exists('key', $filters) && is_array($filters['key'])) {
  3149. reset($filters['key']);
  3150. $found = false;
  3151. while (list($key, $val) = each($filters['key'])) {
  3152. if ($val == $name) {
  3153. $found = true;
  3154. break;
  3155. }
  3156. }
  3157. if (!$found || $filters['origvalue'][$key] == '') {
  3158. $this->emptyMsg = JText::_('COM_FABRIK_PLEASE_SELECT_ALL_REQUIRED_FILTERS');
  3159. return false;
  3160. }
  3161. }
  3162. else {
  3163. // $$$ hugh ... if $filters doesn't exist, then by definition
  3164. // the required filter isn't there?
  3165. if (empty($filters)) {
  3166. $this->emptyMsg = JText::_('COM_FABRIK_PLEASE_SELECT_ALL_REQUIRED_FILTERS');
  3167. return false;
  3168. }
  3169. }
  3170. }
  3171. }
  3172. }
  3173. }
  3174. return true;
  3175. }
  3176. /**
  3177. *
  3178. * @param string $container
  3179. * @param string $type
  3180. * @return array filters
  3181. */
  3182. function getFilters($container = 'listform_1', $type = 'list', $id = '')
  3183. {
  3184. if (!isset($this->viewfilters)) {
  3185. global $_PROFILER;
  3186. $params =& $this->getParams();
  3187. $this->viewfilters = array();
  3188. JDEBUG ? $_PROFILER->mark('fabrik makeFilters start') : null;
  3189. $modelFilters =& $this->makeFilters($container, $type, $id);
  3190. JDEBUG ? $_PROFILER->mark('fabrik makeFilters end') : null;
  3191. foreach ($modelFilters as $name => $filter) {
  3192. $f = new stdClass();
  3193. $f->label = $filter->label;
  3194. $f->element = $filter->filter;
  3195. $f->required = array_key_exists('required', $filter) ? $filter->required : '';
  3196. $this->viewfilters[$filter->name] = $f;
  3197. }
  3198. $this->getPluginManager()->runPlugins('onMakeFilters', $this, 'list');
  3199. // moved advanced filters to table settings
  3200. if ($params->get('advanced-filter', '0')) {
  3201. $f = new stdClass();
  3202. $f->element = $this->getAdvancedSearchLink();
  3203. $f->label = '';
  3204. $f->required = '';
  3205. $this->viewfilters['fabrik_advanced_search'] = $f;
  3206. }
  3207. }
  3208. return $this->viewfilters;
  3209. }
  3210. /**
  3211. * creates an array of html code for each filter
  3212. * Also adds in JS code to manage filters
  3213. * @param string $container
  3214. * @param string $type
  3215. * @return array of html code for each filter
  3216. */
  3217. function &makeFilters($container = 'listform_1', $type = 'list', $id = '')
  3218. {
  3219. $aFilters = array();
  3220. $table =& $this->getTable();
  3221. $opts = new stdClass();
  3222. $opts->container = $container;
  3223. $opts->type = $type;
  3224. $opts->id = $type === 'list' ? $this->getId() : $id; //only used in tables
  3225. $opts = json_encode($opts);
  3226. $fscript = "
  3227. var filter_{$container} = new FbListFilter($opts);\n";
  3228. $app = JFactory::getApplication();
  3229. $filters =& $this->getFilterArray();
  3230. $params = $this->getParams();
  3231. if ($params->get('search-mode', 'AND') == 'OR') {
  3232. //test new option to have one field to search them all
  3233. $key = 'com_fabrik.table'. $table->id.'.searchall';
  3234. $v = $app->getUserStateFromRequest($key, 'fabrik_list_filter_all');
  3235. if (trim($v) == '') {
  3236. $fromFormId = $app->getUserState('com_fabrik.searchform.fromForm');
  3237. if ($fromFormId != $this->getFormModel()->getForm()->id) {
  3238. $v = $app->getUserState('com_fabrik.searchform.form'.$fromFormId.'.searchall');
  3239. }
  3240. }
  3241. $v = htmlspecialchars($v, ENT_QUOTES);
  3242. $o = new stdClass();
  3243. $o->filter = "<input size=\"20\" value=\"$v\" class=\"fabrik_filter\" name=\"fabrik_list_filter_all\" />";
  3244. if ($params->get('search-mode-advanced') == 1) {
  3245. $opts = array();
  3246. $opts[] = JHTML::_('select.option', 'all', JText::_('COM_FABRIK_ALL_OF_THESE_TERMS'));
  3247. $opts[] = JHTML::_('select.option', 'any', JText::_('COM_FABRIK_ANY_OF_THESE_TERMS'));
  3248. $opts[] = JHTML::_('select.option', 'exact', JText::_('COM_FABRIK_EXACT_TERMS'));
  3249. $opts[] = JHTML::_('select.option', 'none', JText::_('COM_FABRIK_NONE_OF_THESE_TERMS'));
  3250. $mode = $app->getUserStateFromRequest('com_fabrik.table'. $table->id.'.searchallmode', 'search-mode-advanced');
  3251. $o->filter .= '&nbsp;'.JHTML::_('select.genericList', $opts, 'search-mode-advanced', "class='fabrik_filter'", 'value', 'text', $mode);
  3252. }
  3253. $o->name = 'all';
  3254. $o->label = $params->get('search-all-label', JText::_('COM_FABRIK_ALL'));
  3255. $aFilters[] = $o;
  3256. }
  3257. $counter = 0;
  3258. // $$$ hugh - another one of those weird ones where if we use =& the foreach loop
  3259. // will sometimes skip a group
  3260. //$groups =& $this->getFormGroupElementData();
  3261. $groups = $this->getFormGroupElementData();
  3262. foreach ($groups as &$groupModel) {
  3263. $g =& $groupModel->getGroup();
  3264. $elementModels = null;
  3265. $elementModels =& $groupModel->getPublishedElements();
  3266. /*foreach ($elementModels as $kk => $val2) {
  3267. $elementModel = $elementModels[$kk]; //dont do with =& as this foobars up the last elementModel*/
  3268. // $$$ rob changed from above 2 lines to 2 below as I think the form_id test inside here fixes things???
  3269. foreach ($elementModels as &$elementModel) {
  3270. $element =& $elementModel->getElement();
  3271. //$$ rob added as some filter_types were null, have to double check that this doesnt
  3272. // mess with showing the readonly values from search forms
  3273. if (isset($element->filter_type) && $element->filter_type <> '' && $element->filter_type != 'null') {
  3274. if ($elementModel->canView() && $elementModel->canUseFilter()) {
  3275. // $$$ rob in facted browsing somehow (not sure how!) some elements from the facted table get inserted into elementModels
  3276. // with their form id set - so test if its been set and if its not the same as the current form id
  3277. // if so then ignore
  3278. if (isset($element->form_id) && (int)$element->form_id !== 0 && $element->form_id !== $this->getFormModel()->_id) {
  3279. continue;
  3280. }
  3281. //force the correct group model into the element model to ensure no wierdness in getting the element name
  3282. $elementModel->_group =& $groupModel;
  3283. $o = new stdClass();
  3284. $o->name = $elementModel->getFullName(false, true, false);
  3285. //global $_PROFILER;
  3286. //JDEBUG ? $_PROFILER->mark('About to getFilter for:' . $o->name) : null;
  3287. $o->filter = $elementModel->getFilter($counter, true);
  3288. $fscript .= $elementModel->_filterJS(true, $container);
  3289. $o->required = $elementModel->getParams()->get('filter_required');
  3290. $o->label = $elementModel->getParams()->get('alt_list_heading') == '' ? $element->label : $elementModel->getParams()->get('alt_list_heading');
  3291. $aFilters[] = $o;
  3292. $counter ++;
  3293. }
  3294. }
  3295. }
  3296. }
  3297. $fscript .= "filter_{$container}.update();\n";
  3298. //$fscript .= "});";
  3299. $this->filterJs = $fscript;
  3300. //check for search form filters - if they exists create hidden elements for them
  3301. $keys = JArrayHelper::getValue($filters, 'key', array());
  3302. foreach ($keys as $i => $key) {
  3303. if ($filters['no-filter-setup'][$i] == '1' && !in_array($filters['search_type'][$i], array('searchall', 'advanced'))) {
  3304. $o = new stdClass();
  3305. // $$$ rob - we are now setting read only filters 'filter' var to the elements read only
  3306. // label for the passed in filter value
  3307. //$o->filter = $value;
  3308. $o->filter = $filters['filter'][$i];
  3309. $o->name = $filters['key'][$i];
  3310. $o->label = $filters['label'][$i];
  3311. $aFilters[] = $o;
  3312. }
  3313. }
  3314. return $aFilters;
  3315. }
  3316. /**
  3317. * build the advanced search link
  3318. * @return string <a href...> link
  3319. */
  3320. function getAdvancedSearchLink()
  3321. {
  3322. FabrikHelperHTML::mocha('a.popupwin');
  3323. $table =& $this->getTable();
  3324. $url = COM_FABRIK_LIVESITE."index.php?option=com_fabrik&amp;view=list&amp;layout=_advancedsearch&amp;tmpl=component&amp;listid=".$table->id."&amp;nextview=".JRequest::getVar('view');
  3325. return "<a rel=\"{id:'advanced-search-win',width:690,loadMethod:'xhr',title:'".JText::_('COM_FABRIK_ADVANCED_SEARCH')."',maximizable:1}\" href=\"$url\" class=\"popupwin\">". JText::_('COM_FABRIK_ADVANCED_SEARCH') ."</a>";
  3326. }
  3327. /**
  3328. * called from index.php?option=com_fabrik&view=list&layout=_advancedsearch&tmpl=component&listid=4
  3329. * advanced serach popup view
  3330. */
  3331. function getAdvancedSearchOpts()
  3332. {
  3333. $list =& $this->getTable();
  3334. $opts = new stdClass();
  3335. $opts->conditionList = FabrikHelperHTML::conditonList($this->getId(), '');
  3336. list($fieldNames, $firstFilter) = $this->getAdvancedSearchElementList();
  3337. $statements = $this->getStatementsOpts();
  3338. $opts->elementList = JHTML::_('select.genericlist', $fieldNames, 'fabrik___filter[list_'.$this->getId().'][key][]', "class=\"inputbox key\" size=\"1\" ",'value', 'text');
  3339. $opts->statementList = JHTML::_('select.genericlist', $statements, 'fabrik___filter[list_'.$this->getId().'][condition][]', "class=\"inputbox\" size=\"1\" ",'value', 'text');
  3340. $opts->listid = $list->id;
  3341. $opts->counter = count($this->getadvancedSearchRows()) - 1;
  3342. $elements =& $this->getElements();
  3343. $arr = array();
  3344. foreach ($elements as $e) {
  3345. $key = FabrikString::safeColName($e->getFullName(false, false, false));
  3346. $arr[$key] = array('id'=>$e->_id, 'plugin'=>$e->getElement()->plugin);
  3347. }
  3348. $opts->elementMap = $arr;
  3349. $opts = json_encode($opts);
  3350. $script = "head.ready(function() {new Fabrik.AdvancedSearch($opts);});";
  3351. FabrikHelperHTML::addScriptDeclaration($script);
  3352. }
  3353. private function getAdvancedSearchElementList()
  3354. {
  3355. $first = false;
  3356. $fieldNames[] = JHTML::_('select.option', '', JText::_('COM_FABRIK_PLEASE_SELECT'));
  3357. $elementModels =& $this->getElements();
  3358. foreach ($elementModels as $elementModel) {
  3359. $element =& $elementModel->getElement();
  3360. $elParams =& $elementModel->getParams();
  3361. if ($elParams->get('inc_in_adv_search', 1)) {
  3362. $elName = FabrikString::safeColName($elementModel->getFullName(false, false, false));
  3363. if (!$first) {
  3364. $first = true;
  3365. $firstFilter =& $elementModel->getFilter(0, false);
  3366. }
  3367. $fieldNames[] = JHTML::_('select.option', $elName, $element->label);
  3368. }
  3369. }
  3370. return array($fieldNames, $firstFilter);
  3371. }
  3372. /**
  3373. * get a list of advanced search options
  3374. * @return array of JHTML options
  3375. */
  3376. private function getStatementsOpts()
  3377. {
  3378. $statements = array();
  3379. $statements[] = JHTML::_('select.option', '=', JText::_('COM_FABRIK_EQUALS'));
  3380. $statements[] = JHTML::_('select.option', '<>', JText::_('COM_FABRIK_NOT_EQUALS'));
  3381. $statements[] = JHTML::_('select.option', 'BEGINS WITH', JText::_('COM_FABRIK_BEGINS_WITH'));
  3382. $statements[] = JHTML::_('select.option', 'CONTAINS', JText::_('COM_FABRIK_CONTAINS'));
  3383. $statements[] = JHTML::_('select.option', 'ENDS WITH', JText::_('COM_FABRIK_ENDS_WITH'));
  3384. $statements[] = JHTML::_('select.option', '>', JText::_('COM_FABRIK_GREATER_THAN'));
  3385. $statements[] = JHTML::_('select.option', '<', JText::_('COM_FABRIK_LESS_THAN'));
  3386. return $statements;
  3387. }
  3388. /**
  3389. * get a list of submitted advanced filters
  3390. * @return array advanced filter values
  3391. */
  3392. private function getAdvancedFilterValues()
  3393. {
  3394. $filters =& $this->getFilterArray();
  3395. $advanced = array();
  3396. for ($i = 0; $i < count(JArrayHelper::getValue($filters, 'key', array())); $i++) {
  3397. if ($filters['search_type'][$i] == 'advanced') {
  3398. $tmp = array();
  3399. foreach (array_keys($filters ) as $k) {
  3400. if (array_key_exists($k, $advanced)) {
  3401. $advanced[$k][] = ($filters[$k][$i]);
  3402. } else {
  3403. $advanced[$k] = array_key_exists($i, $filters[$k]) ? array(($filters[$k][$i])) : '';
  3404. }
  3405. }
  3406. }
  3407. }
  3408. return $advanced;
  3409. }
  3410. /**
  3411. * build an array of html data that gets inserted into the advanced search popup view
  3412. * @return array html lists/fields
  3413. */
  3414. public function getAdvancedSearchRows()
  3415. {
  3416. if (isset($this->advancedSearchRows)) {
  3417. return $this->advancedSearchRows;
  3418. }
  3419. $statements = $this->getStatementsOpts();
  3420. $rows = array();
  3421. $first = false;
  3422. $elementModels =& $this->getElements();
  3423. list($fieldNames, $firstFilter) = $this->getAdvancedSearchElementList();
  3424. $type = "<input type=\"hidden\" name=\"fabrik___filter[list_{$this->getId()}][search_type][]\" value=\"advanced\" />";
  3425. $grouped = "<input type=\"hidden\" name=\"fabrik___filter[list_{$this->getId()}][grouped_to_previous][]\" value=\"0\" />";
  3426. $filters =& $this->getAdvancedFilterValues();
  3427. $counter = 0;
  3428. if (array_key_exists('key', $filters)) {
  3429. foreach ($filters['key'] as $key) {
  3430. foreach ($elementModels as $elementModel) {
  3431. $testkey = FabrikString::safeColName($elementModel->getFullName(false, false, false));
  3432. if ($testkey == $key) {
  3433. break;
  3434. }
  3435. }
  3436. $join = $filters['join'][$counter];
  3437. $condition = $filters['condition'][$counter];
  3438. $value = $filters['origvalue'][$counter];
  3439. $v2 = $filters['value'][$counter];
  3440. switch( $condition )
  3441. {
  3442. case "<>":
  3443. $jsSel = '<>';
  3444. break;
  3445. case "=":
  3446. $jsSel = 'EQUALS';
  3447. break;
  3448. case "<":
  3449. $jsSel = '<';
  3450. break;
  3451. case ">":
  3452. $jsSel = '>';
  3453. break;
  3454. default:
  3455. $firstChar = substr($v2, 1, 1);
  3456. $lastChar = substr($v2, -2, 1);
  3457. switch( $firstChar )
  3458. {
  3459. case "%":
  3460. $jsSel =( $lastChar == "%")? 'CONTAINS' : $jsSel = 'ENDS WITH';
  3461. break;
  3462. default:
  3463. if ($lastChar == "%") {
  3464. $jsSel = 'BEGINS WITH';
  3465. }
  3466. break;
  3467. }
  3468. break;
  3469. }
  3470. $value = trim(trim($value, '"'), "%");
  3471. if ($counter == 0) {
  3472. $join = JText::_('COM_FABRIK_WHERE') . "<input type=\"hidden\" value=\"WHERE\" name=\"fabrik___filter[list_{$this->getState('list.id')}][join][]\" />";
  3473. } else {
  3474. $join = FabrikHelperHTML::conditonList($this->getId(), $join);
  3475. }
  3476. $lineElname = FabrikString::safeColName($elementModel->getFullName(false, true, false));
  3477. $orig = JRequest::getVar($lineElname);
  3478. JRequest::setVar($lineElname, array('value' => $value));
  3479. $filter = & $elementModel->getFilter($counter, false);
  3480. JRequest::setVar($lineElname, $orig);
  3481. $key = JHTML::_('select.genericlist', $fieldNames, 'fabrik___filter[list_'.$this->getId().'][key][]', "class=\"inputbox key\" size=\"1\" ",'value', 'text', $key);
  3482. $jsSel = JHTML::_('select.genericlist', $statements, 'fabrik___filter[list_'.$this->getId().'][condition][]', "class=\"inputbox\" size=\"1\" ",'value', 'text', $jsSel);
  3483. $rows[] = array('join' => $join, 'element' => $key, 'condition' => $jsSel, 'filter' => $filter, 'type' => $type, 'grouped' => $grouped);
  3484. $counter ++;
  3485. }
  3486. }
  3487. if ($counter == 0) {
  3488. $join = JText::_('COM_FABRIK_WHERE') . "<input type=\"hidden\" name=\"fabrik___filter[list_{$this->getId()}][join][]\" value=\"WHERE\" />";
  3489. $key = JHTML::_('select.genericlist', $fieldNames, 'fabrik___filter[list_'.$this->getId().'][key][]', "class=\"inputbox key\" size=\"1\" ",'value', 'text', '');
  3490. $jsSel = JHTML::_('select.genericlist', $statements, 'fabrik___filter[list_'.$this->getId().'][condition][]', "class=\"inputbox\" size=\"1\" ",'value', 'text', '');
  3491. $rows[] = array('join' => $join, 'element' => $key, 'condition' => $jsSel, 'filter' => $firstFilter, 'type' => $type, 'grouped' => $grouped);
  3492. }
  3493. $this->advancedSearchRows =& $rows;
  3494. return $rows;
  3495. }
  3496. /**
  3497. * set the headings that should be shown in the csv export file
  3498. * @param unknown_type $headings
  3499. */
  3500. function setHeadingsForCSV($headings)
  3501. {
  3502. $asfields =& $this->getAsFields();
  3503. $newfields = array();
  3504. $this->_temp_db_key_addded = false;
  3505. // $$$ rob if no fields specified presume we are requesting CSV file from URL and return
  3506. // all fields otherwise set the fields to be those selected in fabrik window.
  3507. if (!empty($headings)) {
  3508. foreach ($headings as $name => $val) {
  3509. $elModel = $this->getFormModel()->getElement($name);
  3510. if (is_object($elModel)) {
  3511. $name = $elModel->getFullName(false, true, false);
  3512. foreach ($asfields as $f) {
  3513. // $$$ rob 04/08/2011' - need to end $name with db quote to stop comparisons being too l
  3514. if ((strstr($f, $name.'`') || strstr($f, ($name."_raw`"))) && $val == 1) {
  3515. $newfields[] = $f;
  3516. }
  3517. }
  3518. }
  3519. }
  3520. $this->asfields =& $newfields;
  3521. }
  3522. }
  3523. /**
  3524. * returns the table headings, seperated from writetable function as
  3525. * when group_by is selected mutliple tables are written
  3526. * 09/07/2011 moved headingClass into arry rather than string
  3527. * @return array(table headings, array columns, $aLinkElements)
  3528. */
  3529. function getHeadings()
  3530. {
  3531. $table =& $this->getTable();
  3532. $table->order_dir = strtolower($table->order_dir);
  3533. $aTableHeadings = array();
  3534. $headingClass = array();
  3535. $cellClass = array();
  3536. $params =& $this->getParams();
  3537. $w = new FabrikWorker();
  3538. $session = JFactory::getSession();
  3539. $formModel = $this->getFormModel();
  3540. $linksToForms = $this->getLinksToThisKey();
  3541. $groups =& $formModel->getGroupsHiarachy();
  3542. $groupHeadings = array();
  3543. $orderbys = json_decode($table->order_by, true);
  3544. foreach ($groups as $groupModel) {
  3545. $groupHeadingKey = $w->parseMessageForPlaceHolder($groupModel->getGroup()->label, array(), false);
  3546. $groupHeadings[$groupHeadingKey] = 0;
  3547. $elementModels =& $groupModel->getPublishedTableElements();
  3548. foreach ($elementModels as $key => $elementModel) {
  3549. $viewLinkAdded = false;
  3550. $element =& $elementModel->getElement();
  3551. $groupHeadings[$groupHeadingKey] ++;
  3552. $key = $elementModel->getFullName(false, true, false);
  3553. $orderKey = $elementModel->getOrderbyFullName(false, false);
  3554. $elementParams =& $elementModel->getParams();
  3555. $label = $elementParams->get('alt_list_heading');
  3556. if ($label == '') {
  3557. $label = $element->label;
  3558. }
  3559. $label = $w->parseMessageForPlaceHolder($label, array());
  3560. if ($elementParams->get('can_order') == '1' && $this->_outPutFormat != 'csv') {
  3561. $context = 'com_fabrik.table' . $this->getId() . '.order.' . $element->id;
  3562. $orderDir = $session->get($context);
  3563. $class = "";
  3564. $currentOrderDir = $orderDir;
  3565. $tmpl = $this->getTmpl();
  3566. switch ($orderDir) {
  3567. case "desc":
  3568. $orderDir = "-";
  3569. $class = "class=\"fabrikorder-desc\"";
  3570. $img = FabrikHelperHTML::image('orderdesc.png', 'list', $tmpl, JText::_('COM_FABRIK_ORDER'));
  3571. break;
  3572. case "asc":
  3573. $orderDir = "desc";
  3574. $class = "class=\"fabrikorder-asc\"";
  3575. $img = FabrikHelperHTML::image('orderasc.png', 'list', $tmpl, JText::_('COM_FABRIK_ORDER'));
  3576. break;
  3577. case "":
  3578. case "-":
  3579. $orderDir = "asc";
  3580. $class = "class=\"fabrikorder\"";
  3581. $img = FabrikHelperHTML::image('ordernone.png', 'list', $tmpl, JText::_('COM_FABRIK_ORDER'));
  3582. break;
  3583. }
  3584. if ($class === '') {
  3585. if (in_array($key, $orderbys)) {
  3586. if ($table->order_dir === 'desc') {
  3587. $class = "class=\"fabrikorder-desc\"";
  3588. $img = FabrikHelperHTML::image('orderdesc.png', 'list', $tmpl, JText::_('COM_FABRIK_ORDER'));
  3589. }
  3590. }
  3591. }
  3592. $heading = '<a '.$class.' href="#">'.$img.$label.'</a>';
  3593. } else {
  3594. $heading = $label;
  3595. }
  3596. $aTableHeadings[$key] = $heading;
  3597. $headingClass[$key] = array('class' => 'fabrik_ordercell '.$key.' '.$element->id.'_order '.$elementParams->get('tablecss_header_class'),
  3598. 'style' => $elementParams->get('tablecss_header'));
  3599. $cellClass[$key] = array('class' => "{$key} fabrik_element " . $elementParams->get('tablecss_cell_class'),
  3600. 'style' => $elementParams->get('tablecss_cell'));
  3601. }
  3602. if ($groupHeadings[$groupHeadingKey] == 0) {
  3603. unset ($groupHeadings[$groupHeadingKey]);
  3604. }
  3605. }
  3606. if (!in_array($this->_outPutFormat, array('pdf','csv'))) {
  3607. //@TODO check if any plugins need to use the selector as well!
  3608. if ($this->canSelectRows()) {
  3609. $select = '<input type="checkbox" name="checkAll" class="list_' . $this->getId() . '_checkAll" />';
  3610. $aTableHeadings['fabrik_select'] = $select;
  3611. $headingClass['fabrik_select'] = array('class' => 'fabrik_ordercell fabrik_select', 'style' => '');
  3612. $cellClass['fabrik_select'] = array('class' => 'fabrik_select fabrik_element'); //needed for ajax filter/nav
  3613. }
  3614. $viewLinkAdded = false;
  3615. //if no elements linking to the edit form add in a edit column (only if we have the right to edit/view of course!)
  3616. // 3.0 actions now go in one column
  3617. if ($this->actionHeading == true) {
  3618. if ($this->deletePossible()) {
  3619. $aTableHeadings['fabrik_actions'] = '<ul class="fabrik_action">'.$this->deleteButton().'</ul>';
  3620. } else {
  3621. $aTableHeadings['fabrik_actions'] = '';
  3622. }
  3623. $headingClass['fabrik_actions'] = array('class' => 'fabrik_ordercell fabrik_actions', 'style' => '');
  3624. $cellClass['fabrik_actions'] = array('class' => 'fabrik_actions fabrik_element'); //needed for ajax filter/nav
  3625. }
  3626. // create columns containing links which point to tables associated with this table
  3627. $factedlinks = $params->get('factedlinks');
  3628. $joinsToThisKey = $this->getJoinsToThisKey();
  3629. $f = 0;
  3630. foreach ($joinsToThisKey as $join) {
  3631. $key = $join->list_id.'-'.$join->form_id.'-'.$join->element_id;
  3632. if (is_object($join) && isset($factedlinks->linkedlist->$key)) {
  3633. $linkedTable = $factedlinks->linkedlist->$key;
  3634. $heading = $factedlinks->linkedlistheader->$key;
  3635. if ($linkedTable != '0') {
  3636. $prefix = $join->element_id."___".$linkedTable;
  3637. $aTableHeadings[$prefix . "_list_heading"] = empty($heading) ? $join->listlabel . " " . JText::_('COM_FABRIK_LIST') : $heading;
  3638. $headingClass[$prefix . "_list_heading"] = array('class' => 'fabrik_ordercell '.$prefix.'_list_heading related', 'style' => '');
  3639. $cellClass[$prefix . "_list_heading"] = array('class' => $prefix.'_list_heading fabrik_element related');
  3640. }
  3641. }
  3642. $f ++;
  3643. }
  3644. $f = 0;
  3645. foreach ($linksToForms as $join) {
  3646. $key = $join->list_id.'-'.$join->form_id.'-'.$join->element_id;
  3647. $linkedForm = $factedlinks->linkedform->$key;
  3648. if ($linkedForm != '0') {
  3649. $heading = $factedlinks->linkedformheader->$key;
  3650. $prefix = $join->db_table_name . "___" . $join->name;
  3651. $aTableHeadings[$prefix . "_form_heading"] = empty($heading) ? $join->listlabel . " " . JText::_('COM_FABRIK_FORM') : $heading;
  3652. $headingClass[$prefix . "_form_heading"] = array('class' => 'fabrik_ordercell '.$prefix.'_form_heading related', 'style' => '');
  3653. $cellClass[$prefix . "_form_heading"] = array('class' => $prefix.'_form_heading fabrik_element related');
  3654. }
  3655. $f ++;
  3656. }
  3657. }
  3658. if ($this->canSelectRows()) {
  3659. $groupHeadings[''] = '';
  3660. }
  3661. $args['tableHeadings'] =& $aTableHeadings;
  3662. $args['groupHeadings'] =& $groupHeadings;
  3663. $args['headingClass'] =& $headingClass;
  3664. $args['cellClass'] =& $cellClass;
  3665. $this->getPluginManager()->runPlugins('onGetPluginRowHeadings', $this, 'list', $args);
  3666. return array($aTableHeadings, $groupHeadings, $headingClass, $cellClass);
  3667. }
  3668. /**
  3669. * can the user select the specified row
  3670. * @param object row
  3671. * @return bool
  3672. */
  3673. function canSelectRow($row)
  3674. {
  3675. $canSelect = $this->getPluginManager()->runPlugins('onCanSelectRow', $this, 'list', $row);
  3676. if (in_array(false, $canSelect)) {
  3677. return false;
  3678. }
  3679. if ($this->canDelete($row)) {
  3680. $this->canSelectRows = true;
  3681. return true;
  3682. }
  3683. $params = $this->getParams();
  3684. $usedPlugins = (array)$params->get('plugins');
  3685. if (empty($usedPlugins)) {
  3686. return false;
  3687. }
  3688. $pluginManager =& $this->getPluginManager();
  3689. $tableplugins =& $pluginManager->getPlugInGroup('list');
  3690. $v = in_array(true, $pluginManager->runPlugins('canSelectRows', $this, 'list'));
  3691. if ($v) {
  3692. $this->canSelectRows = true;
  3693. }
  3694. return $v;
  3695. }
  3696. /**
  3697. * can the user select ANY row?
  3698. * If you can delete then true returned, if not then check
  3699. * available table plugins to see if they allow for row selection
  3700. * if so a checkbox column appears in the table
  3701. * @return bool
  3702. */
  3703. function canSelectRows()
  3704. {
  3705. if (!is_null($this->canSelectRows)) {
  3706. return $this->canSelectRows;
  3707. }
  3708. if ($this->canDelete()) {
  3709. $this->canSelectRows = true;
  3710. return $this->canSelectRows;
  3711. }
  3712. $params =& $this->getParams();
  3713. $usedPlugins = (array)$params->get('plugin');
  3714. if (empty($usedPlugins)) {
  3715. $this->canSelectRows = false;
  3716. return $this->canSelectRows;
  3717. }
  3718. $pluginManager =& $this->getPluginManager();
  3719. $pluginManager->getPlugInGroup('list');
  3720. $this->canSelectRows = in_array(true, $pluginManager->runPlugins('canSelectRows', $this, 'list'));
  3721. return $this->canSelectRows;
  3722. }
  3723. function clearCalculations()
  3724. {
  3725. unset($this->_aRunCalculations);
  3726. }
  3727. /**
  3728. * return mathematical column calculations (run at doCalculations() on for submission)
  3729. */
  3730. function getCalculations()
  3731. {
  3732. if (!empty($this->_aRunCalculations)) {
  3733. return $this->_aRunCalculations;
  3734. }
  3735. $user = JFactory::getUser();
  3736. $aclGroups = $user->authorisedLevels();
  3737. $aCalculations = array();
  3738. $formModel =& $this->getFormModel();
  3739. $aAvgs = array();
  3740. $aSums = array();
  3741. $aMedians = array();
  3742. $aCounts = array();
  3743. $groups =& $formModel->getGroupsHiarachy();
  3744. foreach ($groups as $groupModel) {
  3745. $elementModels =& $groupModel->getPublishedElements();
  3746. foreach ($elementModels as $elementModel) {
  3747. $params = $elementModel->getParams();
  3748. $elName = $elementModel->getFullName(false, true, false);
  3749. $sum = $params->get('sum_on', '0');
  3750. $avg = $params->get('avg_on', '0');
  3751. $median = $params->get('median_on', '0');
  3752. $countOn = $params->get('count_on', '0');
  3753. $sumAccess = $params->get('sum_access', 0);
  3754. $avgAccess = $params->get('avg_access', 0);
  3755. $medianAccess = $params->get('median_access', 0);
  3756. $countAccess = $params->get('count_access', 0);
  3757. if (in_array($sumAccess, $aclGroups) && $params->get('sum_value', '') != '') {
  3758. $aSums[$elName] = $params->get('sum_value', '');
  3759. $ser = $params->get('sum_value_serialized');
  3760. if (is_string($ser)) { //if group gone from repeat to none repeat could be array
  3761. $aSums[$elName . "_obj"] = unserialize($ser);
  3762. }
  3763. }
  3764. if (in_array($avgAccess, $aclGroups) && $params->get('avg_value', '') != '') {
  3765. $aAvgs[$elName] = $params->get('avg_value', '');
  3766. $ser = $params->get('avg_value_serialized');
  3767. if (is_string($ser)) {
  3768. $aAvgs[$elName."_obj"] = unserialize($ser);
  3769. }
  3770. }
  3771. if (in_array($medianAccess, $aclGroups) && $params->get('median_value', '') != '') {
  3772. $aMedians[$elName] = $params->get('median_value', '');
  3773. $ser = $params->get('median_value_serialized', '');
  3774. if (is_string($ser)) {
  3775. $aMedians[$elName . "_obj"] = unserialize($ser);
  3776. }
  3777. }
  3778. if (in_array($countAccess, $aclGroups) && $params->get('count_value', '') != '') {
  3779. $aCounts[$elName] = $params->get('count_value', '');
  3780. $ser = $params->get('count_value_serialized');
  3781. if (is_string($ser)) {
  3782. $aCounts[$elName."_obj"] = unserialize($ser);
  3783. }
  3784. }
  3785. }
  3786. }
  3787. $aCalculations['sums'] = $aSums;
  3788. $aCalculations['avgs'] = $aAvgs;
  3789. $aCalculations['medians'] = $aMedians;
  3790. $aCalculations['count'] = $aCounts;
  3791. $this->_aRunCalculations = $aCalculations;
  3792. return $aCalculations;
  3793. }
  3794. /**
  3795. * get table headings to pass into table js oject
  3796. *
  3797. * @return string headings tablename___name
  3798. */
  3799. function _jsonHeadings()
  3800. {
  3801. $aHeadings = array();
  3802. $table =& $this->getTable();
  3803. $formModel =& $this->getFormModel();
  3804. $groups =& $formModel->getGroupsHiarachy();
  3805. foreach ($groups as $groupModel) {
  3806. $elementModels =& $groupModel->getPublishedElements();
  3807. foreach ($elementModels as $elementModel) {
  3808. $element =& $elementModel->getElement();
  3809. if ($element->show_in_list_summary) {
  3810. $aHeadings[] = $table->db_table_name.'___'.$element->name;
  3811. }
  3812. }
  3813. }
  3814. return "['" . implode("','", $aHeadings) . "']";
  3815. }
  3816. /**
  3817. * when form saved (and set to record in database)
  3818. * this is run to see if there is any table join data,
  3819. * if there is it stores it in $this->_joinsToProcess
  3820. *
  3821. * @return array [joinid] = array(join, group array);
  3822. */
  3823. function preProcessJoin()
  3824. {
  3825. if (!isset($this->_joinsToProcess)) {
  3826. $this->_joinsToProcess = array();
  3827. $formModel = $this->getFormModel();
  3828. $groups =& $formModel->getGroupsHiarachy();
  3829. foreach ($groups as $groupModel) {
  3830. $group =& $groupModel->getGroup();
  3831. if ($groupModel->isJoin()) {
  3832. $joinModel =& $groupModel->getJoinModel();
  3833. $join =& $joinModel->getJoin();
  3834. if (!array_key_exists($join->id, $this->_joinsToProcess)) {
  3835. $this->_joinsToProcess[$join->id] = array("join" => $join, "groups" => array($groupModel));
  3836. } else {
  3837. $this->_joinsToProcess[$join->id]["groups"][] = $groupModel;
  3838. }
  3839. }
  3840. $elements = $groupModel->getPublishedElements();
  3841. $c = count($elements);
  3842. for($x = 0; $x < $c; $x ++){
  3843. $elementModel = $elements[$x];
  3844. if ($elementModel->isJoin()) {
  3845. $joinModel =& $elementModel->getJoinModel();
  3846. $join =& $joinModel->getJoin();
  3847. if (!array_key_exists( $join->id, $this->_joinsToProcess )) {
  3848. $this->_joinsToProcess[$join->element_id] = array( "join" => $join, "elements" => array($elementModel) );
  3849. } else {
  3850. $this->_joinsToProcess[$join->element_id]["elements"][] = $elementModel;
  3851. }
  3852. }
  3853. }
  3854. }
  3855. }
  3856. return $this->_joinsToProcess;
  3857. }
  3858. /**
  3859. * check to see if a table exists
  3860. * @param string name of table (ovewrites form_id val to test)
  3861. * @param object database that contains the table if null then default $db object used
  3862. * @return boolean false if no table fodund true if table found
  3863. */
  3864. function databaseTableExists($tableName = null, $fabrikDatabase = null)
  3865. {
  3866. $db = FabrikWorker::getDbo();
  3867. if ($tableName === '') {
  3868. return false;
  3869. }
  3870. $table =& $this->getTable();
  3871. if (is_null($tableName)) {
  3872. $tableName = $table->db_table_name;
  3873. }
  3874. $sql = "SHOW TABLES LIKE ".$db->Quote($tableName);
  3875. /* use the default Joomla database if no table database specified */
  3876. if (is_null($fabrikDatabase) || !is_object($fabrikDatabase)) {
  3877. $fabrikDatabase = $this->getDb();
  3878. }
  3879. $fabrikDatabase->setQuery($sql);
  3880. $total = $fabrikDatabase->loadResult();
  3881. echo $fabrikDatabase->getError();
  3882. return ($total == "") ? false : true;
  3883. }
  3884. /**
  3885. * strip the table names from the front of the key
  3886. * @param array data to strip
  3887. * @return array stripped data
  3888. */
  3889. function removeTableNameFromSaveData($data, $split='___')
  3890. {
  3891. foreach ($data as $key=>$val) {
  3892. $akey = explode($split, $key);
  3893. if (count($akey) > 1) {
  3894. $newKey = $akey[1];
  3895. unset($data[$key]);
  3896. } else {
  3897. $newKey = $akey[0];
  3898. }
  3899. $data[$newKey] = $val;
  3900. }
  3901. return $data;
  3902. }
  3903. /**
  3904. * saves posted form data into a table
  3905. * data should be keyed on short name
  3906. * @param array data to save
  3907. * @param int row id to edit/updated
  3908. * @param bol is the data being saved into a join table
  3909. * @param object joined group table
  3910. * @return bol true if saved ok
  3911. */
  3912. function storeRow($data, $rowId, $isJoin = false, $joinGroupTable = null)
  3913. {
  3914. $origRowId = $rowId;
  3915. //dont save a record if no data collected
  3916. //if ($isJoin && implode($data) == '') { //raises notice on save of joined data from csv import
  3917. if ($isJoin && empty($data)) {
  3918. return;
  3919. }
  3920. $fabrikDb = $this->getDb();
  3921. $table =& $this->getTable();
  3922. $formModel =& $this->getFormModel();
  3923. if ($isJoin) {
  3924. $this->getFormGroupElementData();
  3925. }
  3926. $oRecord = new stdClass();
  3927. $aBindData = array();
  3928. $noRepeatFields = array();
  3929. $c = 0;
  3930. $groups =& $formModel->getGroupsHiarachy();
  3931. foreach ($groups as $groupModel) {
  3932. $group =& $groupModel->getGroup();
  3933. // $$$rob this following if statement avoids this scenario from happening:
  3934. /*
  3935. * you have a form with joins to two other tables
  3936. * each joined group has a field called 'password'
  3937. * first group's password is set to password plugin, second to field
  3938. * on update if no password entered for first field data should not be updated as recordInDatabase() return false
  3939. * however, as we were iterating over all groups, the 2nd password field's data is used instead!
  3940. * this if statement ensures we only look at the correct group
  3941. */
  3942. if ($isJoin == false || $group->id == $joinGroupTable->id) {
  3943. if (($isJoin && $groupModel->isJoin()) || (!$isJoin && !$groupModel->isJoin())) {
  3944. $elementModels =& $groupModel->getPublishedElements();
  3945. foreach ($elementModels as $elementModel) {
  3946. $element = $elementModel->getElement();
  3947. $key = $element->name;
  3948. $fullkey = $elementModel->getFullName(false, true, false);
  3949. //for radio buttons and dropdowns otherwise nothing is stored for them??
  3950. $postkey = array_key_exists($key ."_raw", $data) ? $key . "_raw" : $key;
  3951. //if the user cant use or view dont update this element's value
  3952. //read only data should be added in _addDefaultDataFromRO
  3953. if (!$elementModel->canUse() && !$elementModel->canView() && !$formModel->updatedByPlugin($fullkey)) {
  3954. continue;
  3955. }
  3956. //@TODO similar check (but not quiet the same performed in formModel _removeIgnoredData() - should merge into one place
  3957. if ($elementModel->recordInDatabase($data)) {
  3958. if (array_key_exists($key, $data) && !in_array($key, $noRepeatFields)) {
  3959. $noRepeatFields[] = $key;
  3960. $lastKey = $key;
  3961. $val = $elementModel->storeDatabaseFormat($data[$postkey], $data, $key);
  3962. $elementModel->updateRowId($rowId);
  3963. if (array_key_exists('fabrik_copy_from_table', $data)) {
  3964. $val = $elementModel->onCopyRow($val);
  3965. }
  3966. if (array_key_exists('Copy', $data)) {
  3967. $val = $elementModel->onSaveAsCopy($val);
  3968. }
  3969. //test for backslashed quotes
  3970. if (get_magic_quotes_gpc()) {
  3971. if (!$elementModel->_is_upload) {
  3972. $val = stripslashes($val);
  3973. }
  3974. }
  3975. $oRecord->$key = $val;
  3976. $aBindData[$key] = $val;
  3977. if ($elementModel->isJoin()){
  3978. //add in params object set by element plugin - eg fileupload element rotation/scale
  3979. $oRecord->params = JArrayHelper::getValue($data, 'params');
  3980. $aBindData[$key] = $oRecord->params;
  3981. }
  3982. $c++;
  3983. }
  3984. }
  3985. }
  3986. }
  3987. }
  3988. }
  3989. $this->_addDefaultDataFromRO($aBindData, $oRecord, $isJoin, $rowId);
  3990. $primaryKey = FabrikString::shortColName($this->getTable()->db_primary_key);
  3991. if ($rowId != '' && $c == 1 && $lastKey == $primaryKey) {
  3992. return;
  3993. }
  3994. /*
  3995. * $$$ rob - correct rowid is now inserted into the form's rowid hidden field
  3996. * even when useing usekey and -1, we just need to check if we are adding a new record and if so set rowid to 0
  3997. */
  3998. if (JRequest::getVar('usekey_newrecord', false)) {
  3999. $rowId = 0;
  4000. $origRowId = 0;
  4001. }
  4002. $primaryKey = str_replace("`", "", $primaryKey);
  4003. // $$$ hugh - if we do this, CSV importing can't maintain existing keys
  4004. if (!$this->_importingCSV) {
  4005. //if its a repeat group which is also the primary group $primaryKey was not set.
  4006. if ($primaryKey) {
  4007. $oRecord->$primaryKey = $rowId;
  4008. }
  4009. }
  4010. if ($origRowId == '' || $origRowId == 0) {
  4011. // $$$ rob added test for auto_inc as sugarid key is set from storeDatabaseFormat() and needs to be maintained
  4012. // $$$ rob don't do this when importing via CSV as we want to maintain existing keys (hence check on task var
  4013. if (($primaryKey !== '' && $this->getTable()->auto_inc == true) && JRequest::getCmd('task') !== 'doImport') {
  4014. unset($oRecord->$primaryKey);
  4015. }
  4016. $ok = $this->insertObject($table->db_table_name, $oRecord, $primaryKey, false);
  4017. } else {
  4018. $ok = $this->updateObject($table->db_table_name, $oRecord, $primaryKey, false);
  4019. }
  4020. $this->_tmpSQL = $fabrikDb->getQuery();
  4021. if (!$ok) {
  4022. $q = JDEBUG ? $fabrikDb->getQuery() : '';
  4023. return JError::raiseWarning(500, 'Store row failed: ' . $q . "<br>" . $fabrikDb->getErrorMsg());
  4024. } else {
  4025. // Clean the cache.
  4026. JFactory::getCache('com_fabrik')->clean();
  4027. // $$$ rob new as if you update a record the insertid() returns 0
  4028. $this->lastInsertId = ($rowId == '' || $rowId == 0) ?$fabrikDb->insertid() : $rowId;
  4029. return true;
  4030. }
  4031. }
  4032. /**
  4033. * hack! copied from mysqli db driver to enable AES_ENCRYPT calls
  4034. *
  4035. * @access public
  4036. * @param [type] $updateNulls
  4037. */
  4038. function updateObject($table, &$object, $keyName, $updateNulls=true)
  4039. {
  4040. $db =& $this->getDb();
  4041. $secret = JFactory::getConfig()->getValue('secret');
  4042. $fmtsql = 'UPDATE '.$db->nameQuote($table).' SET %s WHERE %s';
  4043. $tmp = array();
  4044. foreach (get_object_vars($object) as $k => $v) {
  4045. if( is_array($v) or is_object($v) or $k[0] == '_') { // internal or NA field
  4046. continue;
  4047. }
  4048. if( $k == $keyName) { // PK not to be updated
  4049. $where = $keyName . '=' . $db->Quote($v);
  4050. continue;
  4051. }
  4052. if ($v === null)
  4053. {
  4054. if ($updateNulls) {
  4055. $val = 'NULL';
  4056. } else {
  4057. continue;
  4058. }
  4059. } else {
  4060. $val = $db->isQuoted($k) ? $db->Quote($v) : (int) $v;
  4061. }
  4062. if (in_array($k, $this->encrypt)) {
  4063. $val = "AES_ENCRYPT($val, '$secret')";
  4064. }
  4065. $tmp[] = $db->nameQuote($k) . '=' . $val;
  4066. }
  4067. $db->setQuery(sprintf($fmtsql, implode(",", $tmp) , $where));
  4068. return $db->query();
  4069. }
  4070. /**
  4071. * hack! copied from mysqli db driver to enable AES_ENCRYPT calls
  4072. * Inserts a row into a table based on an objects properties
  4073. *
  4074. * @access public
  4075. * @param string The name of the table
  4076. * @param object An object whose properties match table fields
  4077. * @param string The name of the primary key. If provided the object property is updated.
  4078. */
  4079. function insertObject($table, &$object, $keyName = NULL)
  4080. {
  4081. $db =& $this->getDb();
  4082. $secret = JFactory::getConfig()->getValue('secret');
  4083. $fmtsql = 'INSERT INTO '.$db->nameQuote($table).' ( %s ) VALUES ( %s ) ';
  4084. $fields = array();
  4085. foreach (get_object_vars($object) as $k => $v) {
  4086. if (is_array($v) or is_object($v) or $v === NULL) {
  4087. continue;
  4088. }
  4089. if ($k[0] == '_') { // internal field
  4090. continue;
  4091. }
  4092. $fields[] = $db->nameQuote($k);
  4093. $val = $db->isQuoted($k) ? $db->Quote($v) : (int) $v;
  4094. if (in_array($k, $this->encrypt)) {
  4095. $val = "AES_ENCRYPT($val, '$secret')";
  4096. }
  4097. $values[] = $val;
  4098. }
  4099. $db->setQuery(sprintf($fmtsql, implode(",", $fields) , implode(",", $values)));
  4100. if (!$db->query()) {
  4101. return false;
  4102. }
  4103. $id = $db->insertid();
  4104. if ($keyName && $id) {
  4105. $object->$keyName = $id;
  4106. }
  4107. return true;
  4108. }
  4109. /**
  4110. * If an element is set to readonly, and has a default value selected then insert this
  4111. * data into the array that is to be bound to the table record
  4112. * @since 1.0.6
  4113. * @param array data
  4114. * @param object to bind to table row
  4115. * @param int is record join record
  4116. */
  4117. function _addDefaultDataFromRO(&$data, &$oRecord, $isJoin, $rowid)
  4118. {
  4119. jimport('joomla.utilities.simplecrypt');
  4120. // $$$ rob since 1.0.6 : 10 June 08
  4121. // get the current record - not that which was posted
  4122. $formModel =& $this->getFormModel();
  4123. $table =& $this->getTable();
  4124. if (is_null($this->_origData)) {
  4125. if (empty($rowid)) {
  4126. $this->_origData = $origdata = array();
  4127. }
  4128. else {
  4129. $sql = $formModel->_buildQuery();
  4130. $db =& $this->getDb();
  4131. $db->setQuery($sql);
  4132. $origdata = $db->loadObject();
  4133. $origdata = JArrayHelper::fromObject($origdata);
  4134. $origdata = is_array($origdata) ? $origdata : array();
  4135. $this->_origData =& $origdata;
  4136. }
  4137. } else {
  4138. $origdata =& $this->_origData;
  4139. }
  4140. $form =& $formModel->getForm();
  4141. $groups =& $formModel->getGroupsHiarachy();
  4142. $gcounter = 0;
  4143. $repeatGroupCounts = JRequest::getVar('fabrik_repeat_group', array());
  4144. foreach ($groups as $groupModel) {
  4145. if (($isJoin && $groupModel->isJoin()) || (!$isJoin && !$groupModel->isJoin())) {
  4146. $elementModels =& $groupModel->getPublishedElements();
  4147. foreach ($elementModels as $elementModel) {
  4148. // $$$ rob 25/02/2011 unviewable elements are now also being encrypted
  4149. //if (!$elementModel->canUse() && $elementModel->canView()) {
  4150. if (!$elementModel->canUse()) {
  4151. $element =& $elementModel->getElement();
  4152. $fullkey = $elementModel->getFullName(false, true, false);
  4153. $key = $element->name;
  4154. // $$$ hugh - allow submission plugins to override RO data
  4155. // TODO - test this for joined data
  4156. if ($formModel->updatedByPlugin($fullkey)) {
  4157. continue;
  4158. }
  4159. //force a reload of the default value with $origdata
  4160. unset($elementModel->defaults);
  4161. $default = array();
  4162. foreach ($repeatGroupCounts as $groupId => $repeatCount) {
  4163. $def = $elementModel->getValue($origdata, $repeatCount);
  4164. // $$$ rob 26/04/2011 encodeing done at the end
  4165. //if its a dropdown radio etc
  4166. /*if (is_array($def)) {
  4167. $def = json_encode($def);
  4168. }*/
  4169. $default[] = $def;
  4170. }
  4171. $default = count($default) == 1 ? $default[0] : json_encode($default);
  4172. $data[$key] = $default;
  4173. $oRecord->$key = $default;
  4174. }
  4175. }
  4176. }
  4177. $gcounter ++;
  4178. }
  4179. $copy = JRequest::getBool('Copy');
  4180. //check crypted querystring vars (encrypted in form/view.html.php ) _cryptQueryString
  4181. if (array_key_exists('fabrik_vars', $_REQUEST) && array_key_exists('querystring', $_REQUEST['fabrik_vars'])) {
  4182. $crypt = new JSimpleCrypt();
  4183. foreach ($_REQUEST['fabrik_vars']['querystring'] as $key => $encrypted) {
  4184. // $$$ hugh - allow submission plugins to override RO data
  4185. // TODO - test this for joined data
  4186. if ($formModel->updatedByPlugin($key)) {
  4187. continue;
  4188. }
  4189. $key = FabrikString::shortColName($key);
  4190. // $$$ hugh - trying to fix issue where encrypted elements from a main group end up being added to
  4191. // a joined group's field list for the update/insert on the joined row(s).
  4192. if (!array_key_exists($key,$data)) {
  4193. continue;
  4194. }
  4195. foreach ($groups as $groupModel) {
  4196. $elementModels =& $groupModel->getPublishedElements();
  4197. foreach ($elementModels as $elementModel) {
  4198. $element =& $elementModel->getElement();
  4199. if ($element->name == $key) {
  4200. //dont overwrite if something has been entered
  4201. // $$$ rob 25/02/2011 unviewable elements are now also being encrypted
  4202. //if (!$elementModel->canUse() && $elementModel->canView()) {
  4203. if (!$elementModel->canUse()) {
  4204. //repeat groups no join:
  4205. if (is_array($encrypted)) {
  4206. $v = array();
  4207. foreach ($encrypted as $e) {
  4208. $v[] = empty($e)? '' : $crypt->decrypt($e);
  4209. }
  4210. $v = json_encode($v);
  4211. } else {
  4212. $v = !empty($encrypted) ? $crypt->decrypt($encrypted) : '';
  4213. }
  4214. if ($copy) {
  4215. $v = $elementModel->onSaveAsCopy( $v);
  4216. }
  4217. $data[$key] = $v;
  4218. $oRecord->$key = $v;
  4219. }
  4220. // $$$ hugh FIXME - is there some reason we don't break out back to the
  4221. // main querystring foreach at this point, rather than looping through
  4222. // all remaining elements and groups?
  4223. }
  4224. }
  4225. }
  4226. }
  4227. }
  4228. }
  4229. /**
  4230. * called when the form is submitted to perform calculations
  4231. */
  4232. function doCalculations()
  4233. {
  4234. $db = FabrikWorker::getDbo();
  4235. $formModel = $this->getFormModel();
  4236. $groups = $formModel->getGroupsHiarachy();
  4237. foreach ($groups as $groupModel) {
  4238. $elementModels =& $groupModel->getPublishedElements();
  4239. foreach ($elementModels as $elementModel) {
  4240. $element = $elementModel->getElement();
  4241. $params = $elementModel->getParams();
  4242. $update = false;
  4243. if ($params->get('sum_on', 0)) {
  4244. $aSumCals = $elementModel->sum($this);
  4245. $params->set('sum_value_serialized', serialize($aSumCals[1]));
  4246. $params->set('sum_value', $aSumCals[0]);
  4247. $update = true;
  4248. }
  4249. if ($params->get('avg_on', 0)) {
  4250. $aAvgCals = $elementModel->avg($this);
  4251. $params->set('avg_value_serialized', serialize($aAvgCals[1]));
  4252. $params->set('avg_value', $aAvgCals[0]);
  4253. $update = true;
  4254. }
  4255. if ($params->get('median_on', 0)) {
  4256. $medians = $elementModel->median($this);
  4257. $params->set('median_value_serialized', serialize($medians[1]));
  4258. $params->set('median_value', $medians[0]);
  4259. $update = true;
  4260. }
  4261. if ($params->get('count_on', 0)) {
  4262. $aCountCals = $elementModel->count($this);
  4263. $params->set('count_value_serialized', serialize($aCountCals[1]));
  4264. $params->set('count_value', $aCountCals[0]);
  4265. $update = true;
  4266. }
  4267. if ($update) {
  4268. $elementModel->storeAttribs();
  4269. }
  4270. }
  4271. }
  4272. }
  4273. /**
  4274. * check to see if prefilter should be applied
  4275. * @param int group id to check against
  4276. * @return bol must apply filter
  4277. */
  4278. function mustApplyFilter($gid)
  4279. {
  4280. return in_array($gid, JFactory::getUser()->authorisedLevels());
  4281. }
  4282. /**
  4283. * set the connection id - used when creating a new table
  4284. * @param int connection id
  4285. */
  4286. function setConnectionId($id)
  4287. {
  4288. $this->getTable()->connection_id = $id;
  4289. }
  4290. /**
  4291. * return the default set of attributes when creating a new
  4292. * fabrik table
  4293. *
  4294. * @return string json enocoded Params
  4295. */
  4296. function getDefaultParams()
  4297. {
  4298. $a = array('advanced-filter' => 0,
  4299. 'show-table-nav' => 1,
  4300. 'show-table-filters' => 1, 'show-table-add' => 1, 'require-filter' => 0);
  4301. $o = (object)$a;
  4302. $o->admin_template = 'admin';
  4303. $o->detaillink = 0;
  4304. $o->empty_data_msg = 'No data found';
  4305. $o->pdf = '';
  4306. $o->rss = 0;
  4307. $o->feed_title= '';
  4308. $o->feed_date= '';
  4309. $o->rsslimit= 150;
  4310. $o->rsslimitmax= 2500;
  4311. $o->csv_import_frontend= 3;
  4312. $o->csv_export_frontend = 3;
  4313. $o->csvfullname = 0;
  4314. $o->access = 1;
  4315. $o->allow_view_details = 1;
  4316. $o->allow_edit_details = 1;
  4317. $o->allow_add = 1;
  4318. $o->allow_delete = 1;
  4319. $o->group_by_order = '';
  4320. $o->group_by_order_dir = 'ASC';
  4321. $o->prefilter_query = '';
  4322. return json_encode($o);
  4323. }
  4324. public function getGroupBy()
  4325. {
  4326. $table =& $this->getTable();
  4327. return JRequest::getVar('group_by', $table->group_by);
  4328. }
  4329. /**
  4330. * test if the main J user can create mySQL tables
  4331. * @return bol
  4332. */
  4333. function canCreateDbTable()
  4334. {
  4335. return true;
  4336. }
  4337. /**
  4338. * Create a table to store the forms' data depending upon what groups are assigned to the form
  4339. * @param object form model
  4340. * @param string table name - taken from the table oject linked to the form
  4341. * @param obj list database object NOT USED!!!!
  4342. */
  4343. function createDBTable(&$formModel, $dbTableName = null, $fabrikDb = null)
  4344. {
  4345. $db = FabrikWorker::getDbo(true);
  4346. $fabrikDb = $this->getDb();
  4347. $user = JFactory::getUser();
  4348. $config = JFactory::getConfig();
  4349. if (is_null($dbTableName)) {
  4350. $dbTableName = $this->getTable()->db_table_name;
  4351. }
  4352. $sql = "CREATE TABLE IF NOT EXISTS ".$db->nameQuote($dbTableName)." ( ";
  4353. $post = JRequest::get('post');
  4354. if ($post['jform']['id'] == 0 && array_key_exists('current_groups', $post['jform'])) {
  4355. //saving a new form
  4356. $groupIds = $post['jform']['current_groups'];
  4357. } else {
  4358. $query = $db->getQuery(true);
  4359. $query->select('group_id')->from('#__{package}_formgroup')->where('form_id = '.(int)$formModel->id);
  4360. $db->setQuery($query);
  4361. $groupIds = $db->loadResultArray();
  4362. }
  4363. /* create elements for the internal id and time_date fields */
  4364. if ($this->makeIdElement($groupIds[0]) === false) {
  4365. return false;
  4366. }
  4367. if ($this->makeDateTimeElement($groupIds[0]) === false) {
  4368. return false;
  4369. }
  4370. //reset form and plugin manager to load up newly created elements
  4371. $formModel->groups = null;
  4372. $formModel->_loadGroupIds();
  4373. $pluginManager = $formModel->getPluginManager();
  4374. unset($pluginManager->formplugins);
  4375. $aGroups = $formModel->getGroupsHiarachy();
  4376. $arAddedObj = array();
  4377. foreach ($aGroups as $groupModel) {
  4378. $elementModels =& $groupModel->getMyElements();
  4379. foreach ($elementModels as $elementModel) {
  4380. $element = $elementModel->getElement();
  4381. /* replace all non alphanumeric characters with _ */
  4382. $objname = preg_replace("/[^A-Za-z0-9]/", "_", $element->name);
  4383. /* any elements that are names the same (eg radio buttons) can not be entered twice into the database */
  4384. if (!in_array($objname, $arAddedObj)) {
  4385. $arAddedObj[] = $objname;
  4386. $objtype = $elementModel->getFieldDescription();
  4387. if ($objname != "" && !is_null($objtype)) {
  4388. if (JString::stristr($objtype, 'not null')) {
  4389. $sql .= $db->nameQuote($objname) . " $objtype, ";
  4390. } else {
  4391. $sql .= $db->nameQuote($objname) . " $objtype null, ";
  4392. }
  4393. }
  4394. }
  4395. }
  4396. }
  4397. $sql .= " primary key (id))";
  4398. $sql .= " ENGINE = MYISAM ";
  4399. $fabrikDb->setQuery($sql);
  4400. if (!$fabrikDb->query()) {
  4401. JError::raiseError(500, $fabrikDb->getErrorMsg());
  4402. return false;
  4403. }
  4404. return true;
  4405. }
  4406. /**
  4407. * @since Fabrik 3.0
  4408. * make id element
  4409. * @param int $groupId
  4410. */
  4411. public function makeIdElement($groupId)
  4412. {
  4413. $now = JFactory::getDate()->toMySQL();
  4414. $dispatcher = JDispatcher::getInstance();
  4415. $elementModel = new plgFabrik_Element($dispatcher);
  4416. $user = JFactory::getUser();
  4417. $element = FabTable::getInstance('Element', 'FabrikTable');
  4418. $element->name = "id";
  4419. $element->label = "id";
  4420. $element->plugin = 'internalid';
  4421. $element->hidden = 1;
  4422. $element->group_id = $groupId;
  4423. $element->primary_key = 1;
  4424. $element->auto_increment = 1;
  4425. $element->created = $now;
  4426. $element->created_by = $user->get('id');
  4427. $element->created_by_alias = $user->get('username');
  4428. $element->published = '1';
  4429. $element->show_in_list_summary = '1';
  4430. $element->link_to_detail = '1';
  4431. $element->width = '3';
  4432. $element->ordering = 0;
  4433. $element->params = $elementModel->getDefaultAttribs();
  4434. if (!$element->store()) {
  4435. JError::raiseWarning(500, $element->getError());
  4436. return false;
  4437. }
  4438. return true;
  4439. }
  4440. /**
  4441. * @since Fabrik 3.0
  4442. * make foreign key element
  4443. * @param int $groupId
  4444. */
  4445. public function makeFkElement($groupId)
  4446. {
  4447. $now = JFactory::getDate()->toMySQL();
  4448. $dispatcher = JDispatcher::getInstance();
  4449. $elementModel = new plgFabrik_Element($dispatcher);
  4450. $user = JFactory::getUser();
  4451. $element = FabTable::getInstance('Element', 'FabrikTable');
  4452. $element->name = "parent_id";
  4453. $element->label = "parent_id";
  4454. $element->plugin = 'field';
  4455. $element->hidden = 1;
  4456. $element->group_id = $groupId;
  4457. $element->created = $now;
  4458. $element->created_by = $user->get('id');
  4459. $element->created_by_alias = $user->get('username');
  4460. $element->published = '1';
  4461. $element->width = '3';
  4462. $element->ordering = 2;
  4463. $element->params = $elementModel->getDefaultAttribs();
  4464. if (!$element->store()) {
  4465. JError::raiseWarning(500, $element->getError());
  4466. return false;
  4467. }
  4468. return true;
  4469. }
  4470. /**
  4471. * @since Fabrik 3.0
  4472. * make datetime element
  4473. * @param int $groupId
  4474. */
  4475. public function makeDateTimeElement($groupId)
  4476. {
  4477. $now = JFactory::getDate()->toMySQL();
  4478. $dispatcher = JDispatcher::getInstance();
  4479. $elementModel = new plgFabrik_Element($dispatcher);
  4480. $user = JFactory::getUser();
  4481. $element = FabTable::getInstance('Element', 'FabrikTable');
  4482. $element->name = "date_time";
  4483. $element->label = "date";
  4484. $element->plugin = 'date';
  4485. $element->hidden = 1;
  4486. $element->eval = 1;
  4487. $element->default = "return date('Y-m-d h:i:s');";
  4488. $element->group_id = $groupId;
  4489. $element->primary_key = 0;
  4490. $element->auto_increment = 0;
  4491. $element->created = $now;
  4492. $element->created_by = $user->get('id');
  4493. $element->created_by_alias = $user->get('username');
  4494. $element->published = '1';
  4495. $element->show_in_list_summary = '1';
  4496. $element->width = '10';
  4497. $element->ordering = 1;
  4498. $element->params = $elementModel->getDefaultAttribs();
  4499. if (!$element->store()) {
  4500. JError::raiseWarning(500, $element->getError());
  4501. return false;
  4502. }
  4503. return true;
  4504. }
  4505. /**
  4506. * updates the table record to point to the newly created form
  4507. * @params int form id
  4508. */
  4509. function _updateFormId($formId)
  4510. {
  4511. $item = $this->getTable();
  4512. $item->form_id = $formId;
  4513. if (!$item->store()) {
  4514. return JError::raiseWarning(500, $item->getError());
  4515. }
  4516. }
  4517. /**
  4518. * get the tables primary key and if the primary key is auto increment
  4519. * @param string optional table name (used when getting pk to joined tables
  4520. * @return mixed if ok returns array(key, extra, type, name) otherwise
  4521. * returns false
  4522. */
  4523. function getPrimaryKeyAndExtra($table = null)
  4524. {
  4525. $origColNames = $this->getDBFields($table);
  4526. $keys = array();
  4527. if (is_array($origColNames)) {
  4528. foreach ($origColNames as $origColName) {
  4529. $colName = $origColName->Field;
  4530. $key = $origColName->Key;
  4531. $extra = $origColName->Extra;
  4532. $type = $origColName->Type;
  4533. if ($key == "PRI") {
  4534. $keys[] = array("key" => $key, "extra" => $extra, "type" => $type, "colname" => $colName);
  4535. }
  4536. }
  4537. }
  4538. return empty($keys) ? false : $keys;
  4539. }
  4540. /**
  4541. * run the prefilter sql and replace any placeholders in the subsequent prefilter
  4542. *
  4543. * @param string/array prefilter value
  4544. * @return string/array prefilter value
  4545. */
  4546. function _prefilterParse($selValue)
  4547. {
  4548. $isstring = false;
  4549. if (is_string($selValue)) {
  4550. $isstring = true;
  4551. $selValue = array($selValue);
  4552. }
  4553. $preSQL = htmlspecialchars_decode($this->getParams()->get('prefilter_query'), ENT_QUOTES);
  4554. if (trim($preSQL) != '') {
  4555. $db = FabrikWorker::getDbo();
  4556. $w = new FabrikWorker();
  4557. $w->replaceRequest($preSQL);
  4558. $preSQL = $w->parseMessageForPlaceHolder($preSQL);
  4559. $db->setQuery($preSQL);
  4560. $q = $db->loadObjectList();
  4561. if (!empty($q)) {
  4562. $q = $q[0];
  4563. }
  4564. }
  4565. if (isset($q)) {
  4566. foreach ($q as $key=>$val) {
  4567. if (substr($key, 0, 1) != '_') {
  4568. $found = false;
  4569. for ($i=0; $i < count($selValue); $i++) {
  4570. if (strstr($selValue[$i], '{$q-&gt;'. $key)) {
  4571. $found = true;
  4572. $pattern = '{$q-&gt;'. $key. "}";
  4573. }
  4574. if (strstr($selValue[$i], '{$q->' . $key)) {
  4575. $found = true;
  4576. $pattern = '{$q->'. $key . "}";
  4577. }
  4578. if ($found) {
  4579. $selValue[$i] = str_replace($pattern, $val, $selValue[$i]);
  4580. }
  4581. }
  4582. }
  4583. }
  4584. } else {
  4585. //parse for default values only
  4586. $pattern = "/({[^}]+}).*}?/s";
  4587. for ($i=0; $i < count($selValue); $i++) {
  4588. $ok = preg_match($pattern, $selValue[$i], $matches);
  4589. foreach ($matches as $match) {
  4590. $matchx = substr($match, 1, strlen($match) - 2);
  4591. //a default option was set so lets use that
  4592. if (strstr($matchx, '|')) {
  4593. $bits = explode('|', $matchx);
  4594. $selValue[$i] = str_replace($match, $bits[1], $selValue[$i]);
  4595. }
  4596. }
  4597. }
  4598. }
  4599. return $isstring ? $selValue[0] : $selValue;
  4600. }
  4601. protected function getIndexes()
  4602. {
  4603. if (!isset($this->_indexes)) {
  4604. $db = $this->getDb();
  4605. $db->setQuery("SHOW INDEXES FROM " . $this->getTable()->db_table_name);
  4606. $this->_indexes = $db->loadObjectList();
  4607. }
  4608. return $this->_indexes;
  4609. }
  4610. /**
  4611. * add an index to the table
  4612. * @param string field name
  4613. * @param stirng index name prefix (allows you to differentiate between indexes created in
  4614. * different parts of fabrik)
  4615. * @param string index type
  4616. * @param int index length
  4617. */
  4618. public function addIndex($field, $prefix = '', $type = 'INDEX', $size = '')
  4619. {
  4620. $indexes =& $this->getIndexes();
  4621. if (is_numeric($field)) {
  4622. $el = $this->getFormModel()->getElement($field, true);
  4623. $field = $el->getFullName(false, true, false);
  4624. }
  4625. // $$$ hugh - @TODO $field is in 'table.element' format but $indexes
  4626. // has Column_name as just 'element' ... so we're always rebuilding indexes!
  4627. // I'm in the middle of fixing something else, must come back and fix this!!
  4628. // OK, moved these two lines from below to here
  4629. $field = str_replace('_raw', '', $field);
  4630. // $$$ rob 29/03/2011 ensure its in tablename___elementname format
  4631. $field = str_replace('.', '___', $field);
  4632. // $$$ rob 28/02/2011 if index in joined table we need to use that the make the key on
  4633. if (!strstr($field, '___')) {
  4634. $table = $this->getTable()->db_table_name;
  4635. } else {
  4636. $table = array_shift(explode('___', $field));
  4637. }
  4638. $field = FabrikString::shortColName($field);
  4639. FArrayHelper::filter($indexes, 'Column_name', $field);
  4640. if (!empty($indexes)) {
  4641. // an index already exists on that column name no need to add
  4642. return;
  4643. }
  4644. $db = $this->getDb();
  4645. if ($field == '') {
  4646. return;
  4647. }
  4648. if ($size != '') {
  4649. $size = "( $size )";
  4650. }
  4651. $this->dropIndex($field, $prefix, $type, $table);
  4652. $query = " ALTER TABLE ".$db->nameQuote($table)." ADD INDEX ".$db->nameQuote("fb_{$prefix}_{$field}_{$type}")." (".$db->nameQuote($field)." $size)";
  4653. $db->setQuery($query);
  4654. $db->query();
  4655. }
  4656. /**
  4657. * drop an index
  4658. * @param string field name
  4659. * @param stirng index name prefix (allows you to differentiate between indexes created in
  4660. * different parts of fabrik)
  4661. * @param string table name @since 29/03/2011
  4662. * @return string index type
  4663. */
  4664. public function dropIndex($field, $prefix = '', $type = 'INDEX', $table = '')
  4665. {
  4666. $db = $this->getDb();
  4667. $table = $table == '' ? $this->getTable()->db_table_name : $table;
  4668. $field = FabrikString::shortColName($field);
  4669. if ($field == '') {
  4670. return;
  4671. }
  4672. $db->setQuery("SHOW INDEX FROM ".$db->nameQuote($table));
  4673. $dbIndexes = $db->loadObjectList();
  4674. if (is_array($dbIndexes)) {
  4675. foreach ($dbIndexes as $index) {
  4676. if ($index->Key_name == "fb_{$prefix}_{$field}_{$type}") {
  4677. $db->setQuery(" ALTER TABLE ".$db->nameQuote($table)." DROP INDEX ".$db->nameQuote("fb_{$prefix}_{$field}_{$type}"));
  4678. $db->query();
  4679. break;
  4680. }
  4681. }
  4682. }
  4683. }
  4684. /**
  4685. * drop all indexes for a give element name
  4686. * required when encrypting text fileds whcih have a key on them , as blobs cant have keys
  4687. * @param string $field
  4688. * @param string $table
  4689. */
  4690. public function dropColumnNameIndex($field, $table = '')
  4691. {
  4692. $db = $this->getDb();
  4693. $table = $table == '' ? $this->getTable()->db_table_name : $table;
  4694. $field = FabrikString::shortColName($field);
  4695. if ($field == '') {
  4696. return;
  4697. }
  4698. $db->setQuery("SHOW INDEX FROM ".$db->nameQuote($table) . ' WHERE Column_name = ' . $db->Quote($field));
  4699. $dbIndexes = $db->loadObjectList();
  4700. foreach ($dbIndexes as $index) {
  4701. $db->setQuery(" ALTER TABLE ".$db->nameQuote($table)." DROP INDEX ".$db->nameQuote($index->Key_name));
  4702. $db->query();
  4703. }
  4704. }
  4705. /**
  4706. * delete joined records when deleting the main row
  4707. * @param string quoted primary key values from the main table's rows that are to be deleted
  4708. */
  4709. protected function deleteJoinedRows($val)
  4710. {
  4711. $db = $this->getDb();
  4712. $params = $this->getParams();
  4713. if ($params->get('delete-joined-rows', false)) {
  4714. $joins = $this->getJoins();
  4715. for ($i=0; $i<count($joins); $i++) {
  4716. $join = $joins[$i];
  4717. if ((int)$join->list_id !== 0) {
  4718. $sql = "DELETE FROM ".$db->nameQuote($join->table_join)." WHERE ".$db->nameQuote($join->table_join_key)." IN (".$val.")";
  4719. $db->setQuery($sql);
  4720. $db->query();
  4721. }
  4722. }
  4723. }
  4724. }
  4725. /**
  4726. * deletes records from a table
  4727. * @param string key value to delete
  4728. * @param string key to use (leave empty to default to the table's key)
  4729. * @return string error message
  4730. */
  4731. function deleteRows(&$ids, $key = '')
  4732. {
  4733. if (!is_array($ids)) {
  4734. $ids = array($ids);
  4735. }
  4736. $val = $ids;
  4737. $app =& JFactory::getApplication();
  4738. $table =& $this->getTable();
  4739. $db = $this->getDb();
  4740. $params =& $this->getParams();
  4741. if ($key == '') {
  4742. $key = $table->db_primary_key;
  4743. if ($key == '') {
  4744. return JError::raiseWarning(JText::_("COM_FABRIK_NO_KEY_FOUND_FOR_THIS_TABLE"));
  4745. }
  4746. }
  4747. $c = count($val);
  4748. foreach ($val as &$v) {
  4749. $v = $db->Quote($v);
  4750. }
  4751. $val = implode(",", $val);
  4752. // $$$ rob - if we are not deleting joined rows then onloy load in the first row
  4753. // otherwise load in all rows so we can apply onDeleteRows() to all the data
  4754. if ($this->getParams()->get('delete-joined-rows', false) == false) {
  4755. $nav =& $this->getPagination($c, 0, $c);
  4756. }
  4757. echo $val;
  4758. $this->_whereSQL['string'][true] = " WHERE ".$key." IN (".$val.")";
  4759. // $$$ hugh - need to clear cached data, 'cos we called getTotalRecords from the controller, which now
  4760. // calls getData(), and will have cached all rows on this page, not just the ones being deleted, which means
  4761. // things like form and element onDelete plugins will get handed a whole page of rows, not just the ones
  4762. // selected for delete! Ooops.
  4763. unset($this->_data);
  4764. $rows =& $this->getData();
  4765. // $$$ hugh - we need to check delete perms, see:
  4766. // http://fabrikar.com/forums/showthread.php?p=102670#post102670
  4767. // Short version, if user has access for a table plugin, they get a checkbox on the row, but may not have
  4768. // delete access on that row.
  4769. $removed_id = false;
  4770. foreach ($rows as &$group) {
  4771. foreach ($group as $group_key => $row) {
  4772. if (!$this->canDelete($row)) {
  4773. // Can't delete, so remove row data from $rows, and the id from $ids, and queue a message
  4774. foreach ($ids as $id_key => $id) {
  4775. if ($id == $row->__pk_val) {
  4776. unset($ids[$id_key]);
  4777. continue;
  4778. }
  4779. }
  4780. unset($group[$group_key]);
  4781. $app->enqueueMessage('NO PERMISSION TO DELETE ROW');
  4782. $removed_id = true;
  4783. }
  4784. }
  4785. }
  4786. // see if we have any rows left to delete after checking perms
  4787. if (empty($ids)) {
  4788. return;
  4789. }
  4790. // redo $val list of ids in case we zapped any on canDelete check
  4791. if ($removed_id) {
  4792. $val = $ids;
  4793. $c = count($val);
  4794. foreach ($val as &$v) {
  4795. $v = $db->Quote($v);
  4796. }
  4797. $val = implode(",", $val);
  4798. }
  4799. $this->_rowsToDelete =& $rows;
  4800. $groupModels =& $this->getFormGroupElementData();
  4801. foreach ($groupModels as $groupModel) {
  4802. $elementModels =& $groupModel->getPublishedElements();
  4803. foreach ($elementModels as $elementModel) {
  4804. $elementModel->onDeleteRows($rows);
  4805. }
  4806. }
  4807. $pluginManager = $this->getPluginManager();
  4808. // $$$ hugh - added onDeleteRowsForm plugin (needed it so fabrikjuser form plugin can delete users)
  4809. // NOTE - had to call it onDeleteRowsForm rather than onDeleteRows, otherwise runPlugins() automagically
  4810. // runs the element onDeleteRows(), which we already do above. And with the code as-is, that won't work
  4811. // from runPlugins() 'cos it won't pass it the $rows it needs. So i have to sidestep the issue by using
  4812. // a different trigger name. Added a default onDeleteRowsForm() to plugin-form.php, and implemented
  4813. // (and tested) user deletion in fabrikjuser.php using this trigger. All seems to work. 7/28/2009
  4814. if (in_array(false, $pluginManager->runPlugins('onDeleteRowsForm', $this->getFormModel(), 'form', $rows))) {
  4815. return;
  4816. }
  4817. $pluginManager->getPlugInGroup('list');
  4818. if (in_array(false, $pluginManager->runPlugins('onDeleteRows', $this, 'list'))) {
  4819. return;
  4820. }
  4821. $sql = "DELETE FROM ".$table->db_table_name." WHERE ".$key." IN (".$val.")";
  4822. $db->setQuery($sql);
  4823. if (!$db->query()) {
  4824. return JError::raiseWarning($db->getErrorMsg());
  4825. }
  4826. $this->deleteJoinedRows($val);
  4827. // Clean the cache.
  4828. $cache = JFactory::getCache(JRequest::getCmd('option'));
  4829. $cache->clean();
  4830. return true;
  4831. }
  4832. /**
  4833. * remove all records from the table
  4834. */
  4835. function dropData()
  4836. {
  4837. $db = $this->getDb();
  4838. $table =& $this->getTable();
  4839. $sql = "DELETE FROM ".$db->nameQuote($table->db_table_name);
  4840. $db->setQuery($sql);
  4841. $msg= '';
  4842. if (!$db->query()) {
  4843. return JError::raiseWarning(JText::_($db->getErrorMsg()));
  4844. }
  4845. return '';
  4846. }
  4847. /**
  4848. * drop the table containing the fabriktables data
  4849. */
  4850. function drop()
  4851. {
  4852. $db = $this->getDb();
  4853. $table =& $this->getTable();
  4854. $sql = "DROP TABLE IF EXISTS ".$db->nameQuote($table->db_table_name);
  4855. $db->setQuery($sql);
  4856. if (!$db->query()) {
  4857. return JError::raiseWarning(JText::_($db->getErrorMsg()));
  4858. }
  4859. return '';
  4860. }
  4861. function truncate()
  4862. {
  4863. $db = $this->getDb();
  4864. $table =& $this->getTable();
  4865. $db->setQuery("TRUNCATE ".$db->nameQuote($table->db_table_name));
  4866. $db->query();
  4867. // 3.0 clear filters (resets limitstart so that subsequently added records are shown.)
  4868. $this->getFilterModel()->clearFilters();
  4869. }
  4870. /**
  4871. * test if a field already exists in the database
  4872. *
  4873. * @param string $field
  4874. * @param array id's to ignore.
  4875. * @return bol
  4876. */
  4877. function fieldExists($field, $ignore = array())
  4878. {
  4879. $field = strtolower($field);
  4880. $groupModels =& $this->getFormGroupElementData();
  4881. foreach ($groupModels as $groupModel) {
  4882. if (!$groupModel->isJoin()) {//dont check groups that aren't in this table
  4883. $elementModels =& $groupModel->getMyElements();
  4884. foreach ($elementModels as $elementModel) {
  4885. $element =& $elementModel->getElement();
  4886. $n = strtolower($element->name);
  4887. if (strtolower($element->name) == $field && !in_array($element->id, $ignore)) {
  4888. return true;
  4889. }
  4890. }
  4891. }
  4892. }
  4893. return false;
  4894. }
  4895. /**
  4896. * Alter the forms' data collection table when the forms' groups and/or
  4897. * elements are altered
  4898. * @param object form
  4899. * @param string table name
  4900. * @param object database connection object
  4901. */
  4902. function ammendTable(&$formModel = null, $tableName = null, $fabrikDb = null)
  4903. {
  4904. $db = FabrikWorker::getDbo(true);
  4905. $user = JFactory::getUser();
  4906. $table =& $this->getTable();
  4907. $pluginManager = JModel::getInstance('Pluginmanager', 'FabrikFEModel');
  4908. $ammend = false;
  4909. if (is_null($formModel)) {
  4910. $formModel = $this->getFormModel();
  4911. }
  4912. if (is_null($tableName)) {
  4913. $tableName = $table->db_table_name;
  4914. }
  4915. if (is_null($fabrikDb) || !is_object($fabrikDb)) {
  4916. //$fabrikDb = $db;
  4917. $fabrikDb = $this->getDb();
  4918. }
  4919. $dbdescriptions = $this->getDBFields($tableName);
  4920. $existingfields = array();
  4921. //@TODO: test (was strtolower($dbdescription->Field)) if this is going to cause issues, think fields should be case insenitvely compared as some joomla core fields are mixed case
  4922. foreach ($dbdescriptions as $dbdescription) {
  4923. $existingfields[] = strtolower($dbdescription->Field);
  4924. }
  4925. $lastfield = $existingfields[count($existingfields)-1];
  4926. $sql = "ALTER TABLE ".$db->nameQuote($tableName)." ";
  4927. $sql_add = array();
  4928. if (!isset($_POST['current_groups_str'])) {
  4929. /* get a list of groups used by the form */
  4930. $groupsql = "SELECT group_id FROM #__{package}_formgroup WHERE form_id = ".(int)$formModel->id;
  4931. $db->setQuery($groupsql);
  4932. $groups = $db->loadObjectList();
  4933. if ($db->getErrorNum()) {
  4934. JError::raiseWarning(500, 'ammendTable: ' . $db->getErrorMsg());
  4935. }
  4936. $arGroups = array();
  4937. foreach ($groups as $g) {
  4938. $arGroups[] = $g->group_id;
  4939. }
  4940. } else {
  4941. $current_groups_str = JRequest::getVar('current_groups_str');
  4942. $arGroups = explode(",", $current_groups_str);
  4943. }
  4944. $arAddedObj = array();
  4945. foreach ($arGroups as $group_id) {
  4946. $group = FabTable::getInstance('Group', 'FabrikTable');
  4947. $group->load($group_id);
  4948. if ($group->is_join == '0') {
  4949. $groupsql = "SELECT * FROM #__{package}_elements WHERE group_id = ".(int)$group_id;
  4950. $db->setQuery($groupsql);
  4951. $elements = $db->loadObjectList();
  4952. foreach ($elements as $obj) {
  4953. // do this in the add element form (but in any event names should be quoted)
  4954. //$objname = strtolower(preg_replace("/[^A-Za-z0-9]/", "_", $obj->name));
  4955. $objname = $obj->name;
  4956. if (!in_array($objname, $existingfields)) {
  4957. /* make sure that the object is not already in the table*/
  4958. if (!in_array($objname, $arAddedObj)) {
  4959. /* any elements that are names the same (eg radio buttons) can not be entered twice into the database*/
  4960. $arAddedObj[] = $objname;
  4961. $objtypeid = $obj->plugin;
  4962. $pluginClassName = $obj->plugin;
  4963. $plugin = $pluginManager->getPlugIn($pluginClassName, 'element');
  4964. $plugin->setId($obj->id);
  4965. $objtype = $plugin->getFieldDescription();
  4966. if ($objname != "" && !is_null($objtype)) {
  4967. $ammend = true;
  4968. $sql_add[] = "ADD COLUMN ".$db->nameQuote($objname)." $objtype null AFTER ".$db->nameQuote($lastfield);
  4969. }
  4970. }
  4971. }
  4972. }
  4973. }
  4974. }
  4975. if ($ammend) {
  4976. $sql .= implode(', ', $sql_add);
  4977. $fabrikDb->setQuery($sql);
  4978. if (!$fabrikDb->query()) {
  4979. return JError::raiseWarning(500, 'amend table: ' . $fabrikDb->getErrorMsg());
  4980. }
  4981. }
  4982. }
  4983. /**
  4984. * @param int connection id to use
  4985. * @param string table to load fields for
  4986. * @param string show "please select" top option
  4987. * @param bol append field name values with table name
  4988. * @param string name of drop down
  4989. * @param string selected option
  4990. * @param string class name
  4991. * @return string html to be added to DOM
  4992. */
  4993. function getFieldsDropDown($cnnId, $tbl, $incSelect, $incTableName = false, $selectListName = 'order_by', $selected = null, $className = "inputbox")
  4994. {
  4995. $this->setConnectionId($cnnId);
  4996. $aFields = $this->getDBFields($tbl);
  4997. $fieldNames = array();
  4998. if ($incSelect != '') {
  4999. $fieldNames[] = JHTML::_('select.option', '', $incSelect);
  5000. }
  5001. if (is_array($aFields)) {
  5002. foreach ($aFields as $oField) {
  5003. if ($incTableName) {
  5004. $fieldNames[] = JHTML::_('select.option', $tbl . "___" . $oField->Field, $oField->Field);
  5005. } else {
  5006. $fieldNames[] = JHTML::_('select.option', $oField->Field);
  5007. }
  5008. }
  5009. }
  5010. $fieldDropDown = JHTML::_('select.genericlist', $fieldNames, $selectListName, "class=\"$className\" size=\"1\" ", 'value', 'text', $selected);
  5011. return str_replace("\n", "", $fieldDropDown);
  5012. }
  5013. /**
  5014. * create the RSS href link to go in the table template
  5015. * @return string RSS link
  5016. */
  5017. function getRSSFeedLink()
  5018. {
  5019. $app = JFactory::getApplication();
  5020. $link = '';
  5021. if ($this->getParams()->get('rss') == '1') {
  5022. //$$$ rob test fabriks own feed renderer
  5023. //$link = 'index.php?option=com_fabrik&view=table&listid=' . $this->getState('list.id'); . "&format=feed";
  5024. $link = 'index.php?option=com_fabrik&view=list&listid=' . $this->getId() . "&format=fabrikfeed";
  5025. if (!$app->isAdmin()) {
  5026. $link = JRoute::_($link);
  5027. }
  5028. }
  5029. return $link;
  5030. }
  5031. /**
  5032. * iterates through string to replace every
  5033. * {placeholder} with row data
  5034. * (added by hugh, does the same thing as parseMessageForPlaceHolder in parent
  5035. * class, but for rows instead of forms)
  5036. * @param string text to parse
  5037. * @param array of row data
  5038. * @param bool add slashes to the replaced data (default = false) set to true in fabrikcalc element
  5039. */
  5040. function parseMessageForRowHolder($msg, &$row, $addslashes = false)
  5041. {
  5042. $this->_aRow = $row;
  5043. if (!strstr($msg, '{')){
  5044. return $msg;
  5045. }
  5046. $this->_parseAddSlases = $addslashes;
  5047. $msg = FabrikWorker::_replaceWithUserData($msg);
  5048. $msg = FabrikWorker::_replaceWithGlobals($msg);
  5049. $msg = preg_replace("/{}/", "", $msg);
  5050. $this->_rowIdentifierAdded = false;
  5051. /* replace {element name} with form data */
  5052. // $$$ hugh - testing changing the regex so we don't blow away PHP structures! Added the \s so
  5053. // we only match non-space chars in {}'s. So unless you have some code like "if (blah) {foo;}", PHP
  5054. // block level {}'s should remain unmolested.
  5055. $msg = preg_replace_callback( "/{[^}\s]+}/i", array($this,'_replaceWithRowData'), $msg);
  5056. return $msg;
  5057. }
  5058. /**
  5059. * PRVIATE:
  5060. * called from parseMessageForRowHolder to iterate through string to replace
  5061. * {placeholder} with row data
  5062. * @param array matches found in parseMessageForRowHolder
  5063. * @return string posted data that corresponds with placeholder
  5064. */
  5065. function _replaceWithRowData($matches)
  5066. {
  5067. $match = $matches[0];
  5068. /* strip the {} */
  5069. $match = substr($match, 1, strlen($match) - 2);
  5070. // $$$ hugh - in case any {$my->foo} or {$_SERVER->FOO} paterns are left over, avoid 'undefined index' warnings
  5071. if (preg_match('#^\$#',$match)) {
  5072. return '';
  5073. }
  5074. $match = str_replace('.', '___', $match);
  5075. // $$$ hugh - allow use of {$rowpk} or {rowpk} to mean the rowid of the row within a table
  5076. if ($match == 'rowpk' || $match == '$rowpk' || $match == 'rowid')
  5077. {
  5078. $this->_rowIdentifierAdded = true;
  5079. $match = '__pk_val';
  5080. }
  5081. $match = preg_replace("/ /", "_", $match);
  5082. if ($match == 'formid') {
  5083. return $this->getFormModel()->getId();
  5084. }
  5085. $return = JArrayHelper::getValue($this->_aRow, $match);
  5086. if ($this->_parseAddSlases) {
  5087. $return = htmlspecialchars($return, ENT_QUOTES, 'UTF-8');
  5088. }
  5089. return $return;
  5090. }
  5091. /**
  5092. * 3.0 this is just way too confuins - view details link now always returns a view details link and not an edit link ?!!!
  5093. * get the link to view the records details
  5094. * @param object $row active table row
  5095. * @param string view 3.0 depreciated
  5096. * @return url of view details link
  5097. */
  5098. function viewDetailsLink(&$row, $view = null)
  5099. {
  5100. $app = JFactory::getApplication();
  5101. $menuItem = $app->getMenu('site')->getActive();
  5102. $Itemid = is_object($menuItem) ? $menuItem->id : 0;
  5103. $keyIdentifier = $this->getKeyIndetifier($row);
  5104. $params =& $this->getParams();
  5105. $table =& $this->getTable();
  5106. $link = '';
  5107. /*if (is_null($view)) {
  5108. $view = $this->canEdit($row) ? "form" : "details";
  5109. }*/
  5110. ///$customLink = $view == 'form' ? $this->getCustomLink('url', 'edit') : $this->getCustomLink('url', 'details');//$params->get('detailurl');
  5111. $view = 'details';
  5112. $customLink = $this->getCustomLink('url', 'details');
  5113. //$$$ rob check done outside of method - as we want to populate $row->fabrik_view_url and $row->fabrik_edit_url regardless
  5114. //$check = ($view == 'details') ? $this->canViewDetails() : $this->canEdit($row);
  5115. if (trim($customLink) === '') {
  5116. $link = '';
  5117. // $$$ hugh - if we don't do this on feeds, links with subfolders in root get screwed up because no BASE_HREF is set
  5118. if (JRequest::getvar('format', '') == 'fabrikfeed') {
  5119. $link .= COM_FABRIK_LIVESITE;
  5120. }
  5121. if ($app->isAdmin()) {
  5122. $link .= "index.php?option=com_fabrik&task=$view.view&formid=".$table->form_id."&listid=".$this->getId().$keyIdentifier;
  5123. } else {
  5124. $link .= "index.php?option=com_fabrik&view=$view&formid=".$table->form_id.$keyIdentifier;
  5125. }
  5126. if ($this->packageId !== 0) {
  5127. $link .= '&tmpl=component';
  5128. }
  5129. $link = JRoute::_($link);
  5130. } else {
  5131. //custom link
  5132. $link = $this->makeCustomLink($customLink, $row);
  5133. }
  5134. return $link;
  5135. }
  5136. /**
  5137. * create a custom edit/view details link
  5138. * @param string $link
  5139. * @param object $row
  5140. */
  5141. protected function makeCustomLink($link, $row)
  5142. {
  5143. $link = htmlspecialchars($link);
  5144. $keyIdentifier = $this->getKeyIndetifier($row);
  5145. $link = $this->parseMessageForRowHolder($link, JArrayHelper::fromObject($row));
  5146. if ($this->_rowIdentifierAdded === false) {
  5147. if (strstr($link,'?')) {
  5148. $link .= $keyIdentifier;
  5149. } else {
  5150. $link .= '?' . str_replace('&', '', $keyIdentifier);
  5151. }
  5152. }
  5153. $link = JRoute::_($link);
  5154. return $link;
  5155. }
  5156. protected function getCustomLink($type = 'url', $mode = 'edit')
  5157. {
  5158. $params =& $this->getParams();
  5159. if ($type === 'url') {
  5160. $str = ($mode == 'edit') ? $params->get('editurl') : $params->get('detailurl');
  5161. } else {
  5162. $str = ($mode == 'edit') ? $params->get('editurl_attribs') : $params->get('detailurl_attribs');
  5163. }
  5164. $w = new FabrikWorker();
  5165. return $w->parseMessageForPlaceHolder($str);
  5166. }
  5167. /**
  5168. * get the link to edit the records details
  5169. * @param object $row active table row
  5170. * @return url of view details link
  5171. */
  5172. function editLink(&$row)
  5173. {
  5174. $app = JFactory::getApplication();
  5175. $menuItem = $app->getMenu('site')->getActive();
  5176. $Itemid = is_object($menuItem) ? $menuItem->id : 0;
  5177. $keyIdentifier = $this->getKeyIndetifier($row);
  5178. $table =& $this->getTable();
  5179. $customLink = $this->getCustomLink('url', 'edit');
  5180. if ($customLink == '') {
  5181. if ($app->isAdmin()) {
  5182. $url = "index.php?option=com_fabrik&task=form.view&formid=" . $table->form_id . "$keyIdentifier";
  5183. } else {
  5184. $url = "index.php?option=com_fabrik&view=form&Itemid=$Itemid&formid=" . $table->form_id . "$keyIdentifier&listid=".$this->getId();
  5185. }
  5186. if ($this->packageId !== 0) {
  5187. $url .= '&tmpl=component';
  5188. }
  5189. $link = JRoute::_($url);
  5190. } else {
  5191. $link = $this->makeCustomLink($customLink, $row);
  5192. }
  5193. return $link;
  5194. }
  5195. /**
  5196. * make the drop sql statement for the table
  5197. * @return string drop table sql
  5198. */
  5199. function getDropTableSQL()
  5200. {
  5201. $db = FabrikWorker::getDbo();
  5202. $genTable = $this->getGenericTableName();
  5203. $sql = "DROP TABLE IF EXISTS ".$db->nameQuote($genTable);
  5204. return $sql;
  5205. }
  5206. function getGenericTableName()
  5207. {
  5208. $app = JFactory::getApplication();
  5209. $table =& $this->getTable();
  5210. return str_replace($app->getCfg('dbprefix'), '#__', $table->db_table_name);
  5211. }
  5212. /**
  5213. * make the create sql statement for the table
  5214. * @param bool ad 'if not exists' to query
  5215. * @param string table to get sql for(leave out to use models table)
  5216. * @return string sql to drop & or create table
  5217. */
  5218. function getCreateTableSQL($addIfNotExists = false, $table = null)
  5219. {
  5220. $addIfNotExists = $addIfNotExists ? 'IF NOT EXISTS ' : '';
  5221. if (is_null($table)) {
  5222. $table = $this->getGenericTableName();
  5223. }
  5224. $fields = $this->getDBFields($table);
  5225. $primaryKey = "";
  5226. $sql = "";
  5227. $table = FabrikString::safeColName($table);
  5228. if (is_array($fields)) {
  5229. $sql .= "CREATE TABLE $addIfNotExists" . $table ." (\n";
  5230. foreach ($fields as $field) {
  5231. $field->Field = FabrikString::safeColName($field->Field);
  5232. if ($field->Key == 'PRI' && $field->Extra == 'auto_increment') {
  5233. $primaryKey = "PRIMARY KEY ($field->Field)";
  5234. }
  5235. $sql .= "$field->Field ";
  5236. /*if ($field->Key == 'PRI') {
  5237. $sql .= ' INT(6) ';
  5238. } else {*/
  5239. $sql .= ' ' . $field->Type . ' ';
  5240. //}
  5241. if ($field->Null == '') {
  5242. $sql .= " NOT NULL ";
  5243. }
  5244. if ($field->Default != '' && $field->Key != 'PRI') {
  5245. if ($field->Default == 'CURRENT_TIMESTAMP') {
  5246. $sql .= "DEFAULT $field->Default";
  5247. } else {
  5248. $sql .= "DEFAULT '$field->Default'";
  5249. }
  5250. }
  5251. if ($field->Key == 'PRI') {
  5252. print_r($field);
  5253. //$sql .= " AUTO_INCREMENT ";
  5254. //$sql .= $field->Extra;
  5255. }
  5256. $sql .= $field->Extra . ",\n";
  5257. }
  5258. if ($primaryKey == '') {
  5259. $sql = rtrim($sql, ",\n");
  5260. }
  5261. $sql .= $primaryKey . ");";
  5262. }
  5263. //echo $sql;exit;
  5264. if ($table == '`pod_fabrik_notification_ratings`') {
  5265. $db = $this->getDb();
  5266. $db->setQuery("SHOW INDEX FROM ". $table);
  5267. $keys = $db->loadObjectList();
  5268. print_r($keys);
  5269. echo $sql;exit;
  5270. }
  5271. if ($table == '`pod_fabrik_digg`') {
  5272. echo $sql;
  5273. }
  5274. return $sql;
  5275. }
  5276. /**
  5277. * make the create sql statement for inserting the table data
  5278. * used in package export
  5279. * @param object exporter
  5280. * @return string sql to drop & or create table
  5281. */
  5282. function getInsertRowsSQL($oExporter)
  5283. {
  5284. @set_time_limit(300);
  5285. $table =& $this->getTable();
  5286. $memoryLimit = ini_get('memory_limit');
  5287. $db = $this->getDb();
  5288. //dont load in all the table data as on large tables this gives a memory error
  5289. //in fact this wasnt the problem, but rather the $sql var becomes too large to hold in memory
  5290. //going to try saving to a file on the server and then compressing that and sending it as a header for download
  5291. $query = $db->getQuery(true);
  5292. $query->select($table->db_primary_key)->from($table->db_table_name);
  5293. $db->setQuery($query);
  5294. $keys = $db->loadResultArray();
  5295. $sql = "";
  5296. $dump_buffer_len = 0;
  5297. if (is_array($keys)) {
  5298. foreach ($keys as $id) {
  5299. $db->setQuery("SELECT * FROM ".$table->db_table_name." WHERE $table->db_primary_key = $id");
  5300. $row = $db->loadObject();
  5301. $fmtsql = "\t<query>INSERT INTO ".$table->db_table_name." ( %s ) VALUES ( %s )</query>";
  5302. $values = array();
  5303. $fields = array();
  5304. foreach ($row as $k => $v) {
  5305. $fields[] = $db->NameQuote($k);
  5306. $values[] = $db->Quote($v);
  5307. }
  5308. $sql .= sprintf($fmtsql, implode(",", $fields) , implode(",", $values));
  5309. $sql .= "\n";
  5310. $dump_buffer_len += strlen($sql);
  5311. if ($dump_buffer_len > $memoryLimit) {
  5312. $oExporter->writeExportBuffer($sql);
  5313. $sql = "";
  5314. $dump_buffer_len = 0;
  5315. }
  5316. unset($values);
  5317. unset($fmtsql);
  5318. }
  5319. }
  5320. $oExporter->writeExportBuffer($sql);
  5321. }
  5322. /**
  5323. * get a row of data from the table
  5324. *
  5325. * @param int $id
  5326. * @param bool format the data
  5327. * @param bool load the rows joined data @since 2.0.5 (used in J Content plugin)
  5328. * @return object row
  5329. */
  5330. function getRow($id, $format = false, $loadJoin = false)
  5331. {
  5332. if (is_null($this->rows)) {
  5333. $this->rows = array();
  5334. }
  5335. $sig = $id.'.'.$format.'.'.$loadJoin;
  5336. if (array_key_exists($sig, $this->rows)) {
  5337. return $this->rows[$sig];
  5338. }
  5339. $fabrikDb = $this->getDb();
  5340. $formModel =& $this->getFormModel();
  5341. $formModel->_rowId = $id;
  5342. unset($formModel->query);
  5343. $sql = $formModel->_buildQuery();
  5344. $fabrikDb->setQuery($sql);
  5345. if (!$loadJoin) {
  5346. if ($format == true) {
  5347. $row = $fabrikDb->loadObject();
  5348. $row = array($row);
  5349. $this->formatData($row);
  5350. $this->rows[$sig] = $row[0][0];
  5351. } else {
  5352. $this->rows[$sig] = $fabrikDb->loadObject();
  5353. }
  5354. } else {
  5355. $rows = $fabrikDb->loadObjectList();
  5356. $formModel->setJoinData($rows);
  5357. $this->rows[$sig] = $rows[0];
  5358. }
  5359. return $this->rows[$sig];
  5360. }
  5361. /**
  5362. * try to find a row in the table that matches " key LIKE '%val' "
  5363. * @param string $key
  5364. * @param string $val
  5365. * @param bool $format
  5366. * @return object row
  5367. */
  5368. function findRow($key, $val, $format = false)
  5369. {
  5370. $usekey = JRequest::getVar('usekey');
  5371. $usekey_comparison = JRequest::getVar('usekey_comparison');
  5372. JRequest::setVar('usekey', $key);
  5373. JRequest::setVar('usekey_comparison', 'like');
  5374. $row = $this->getRow($val, $format);
  5375. JRequest::setVar('usekey', $usekey);
  5376. JRequest::setVar('usekey_comparison', $usekey_comparison);
  5377. return $row;
  5378. }
  5379. /**
  5380. * ajax get record specified by row id
  5381. */
  5382. function xRecord($mode = 'table')
  5383. {
  5384. $fabrikDb = $this->getDb();
  5385. $cursor = JRequest::getInt('cursor', 1);
  5386. $this->getConnection();
  5387. $this->_outPutFormat = 'json';
  5388. $nav =& $this->getPagination(1, $cursor, 1);
  5389. if ($mode == 'table') {
  5390. $query = $this->_buildQuery();
  5391. $this->setBigSelects();
  5392. $fabrikDb->setQuery($query, $this->limitStart, $this->limitLength);
  5393. $data = $fabrikDb->loadObjectList();
  5394. } else {
  5395. //get the row id
  5396. $table =& $this->getTable();
  5397. $order = $this->_buildQueryOrder();
  5398. $join = $this->_buildQueryJoin();
  5399. $query = "SELECT $table->db_primary_key FROM $table->db_table_name $join $order";
  5400. $fabrikDb->setQuery($query, $nav->limitstart, $nav->limit);
  5401. $rowid = $fabrikDb->loadResult();
  5402. JRequest::setVar('rowid', $rowid);
  5403. $app =& JFactory::getApplication();
  5404. $formid = JRequest::getInt('formid');
  5405. $app->redirect('index.php?option=com_fabrik&view=form&formid='.$formid.'&rowid='.$rowid.'&format=raw');
  5406. }
  5407. return json_encode($data);
  5408. }
  5409. /**
  5410. * ajax get next record
  5411. * @return string json object representing record/row
  5412. */
  5413. function nextRecord()
  5414. {
  5415. $cursor = JRequest::getInt('cursor', 1);
  5416. $this->getConnection();
  5417. $this->_outPutFormat = 'json';
  5418. $nav = $this->getPagination(1, $cursor, 1);
  5419. $data = $this->getData();
  5420. echo json_encode($data);
  5421. }
  5422. /**
  5423. * ajax get previous record
  5424. * @return string json object representing record/row
  5425. */
  5426. function previousRecord()
  5427. {
  5428. $cursor = JRequest::getInt('cursor', 1);
  5429. $this->getConnection();
  5430. $this->_outPutFormat = 'json';
  5431. $nav =& $this->getPagination(1, $cursor-2, 1);
  5432. $data = $this->getData();
  5433. return json_encode($data);
  5434. }
  5435. /**
  5436. * ajax get first record
  5437. * @return string json object representing record/row
  5438. */
  5439. function firstRecord()
  5440. {
  5441. $cursor = JRequest::getInt('cursor', 1);
  5442. $this->getConnection();
  5443. $this->_outPutFormat = 'json';
  5444. $nav =& $this->getPagination(1, 0, 1);
  5445. $data = $this->getData();
  5446. return json_encode($data);
  5447. }
  5448. /**
  5449. * ajax get last record
  5450. * @return string json object representing record/row
  5451. */
  5452. function lastRecord()
  5453. {
  5454. $total = JRequest::getInt('total', 0);
  5455. $this->getConnection();
  5456. $this->_outPutFormat = 'json';
  5457. $nav =& $this->getPagination(1, $total-1, 1);
  5458. $data = $this->getData();
  5459. return json_encode($data);
  5460. }
  5461. /**
  5462. * get a single column of data from the table, test for element filters
  5463. * @param string column to get
  5464. * @return array values for the column - empty array if no results found
  5465. */
  5466. function getColumnData($col)
  5467. {
  5468. $table =& $this->getTable();
  5469. $fbConfig =& JComponentHelper::getParams('com_fabrik');
  5470. $db = $this->getDb();
  5471. $el = $this->getFormModel()->getElement($col);
  5472. $col = FabrikString::safeColName($col);
  5473. $el->encryptFieldName($col);
  5474. $tablename = $table->db_table_name;
  5475. $tablename = FabrikString::safeColName($tablename);
  5476. $query = "SELECT DISTINCT($col) FROM " . $tablename . ' ' . $this->_buildQueryJoin();
  5477. $query .= $this->_buildQueryWhere(false);
  5478. $query .= " LIMIT " . $fbConfig->get('filter_list_max', 100);
  5479. $query = $this->pluginQuery($query);
  5480. $db->setQuery($query);
  5481. $res = $db->loadResultArray();
  5482. if ((int)$fbConfig->get('filter_list_max', 100) == count($res)) {
  5483. JError::raiseNotice(500, JText::sprintf('COM_FABRIK_FILTER_LIST_MAX_REACHED', $col));
  5484. }
  5485. FabrikHelperHTML::debug($query, 'filter:getColumnData query');
  5486. if (is_null($res)) {
  5487. $res = array();
  5488. }
  5489. return $res;
  5490. }
  5491. /**
  5492. * determine how the model does filtering and navigation
  5493. * @return string (ajax/post default post)
  5494. */
  5495. function isAjax()
  5496. {
  5497. $params = &$this->getParams();
  5498. if (is_null($this->ajax)) {
  5499. // $$$ rob 11/07/2011 if post method set to ajax in request use that over the list_nav option
  5500. if (JRequest::getVar('ajax', false) == '1') {
  5501. $this->ajax = true;
  5502. } else {
  5503. $this->ajax = $params->get('list_ajax', JRequest::getBool('ajax', false));
  5504. }
  5505. }
  5506. return (bool)$this->ajax;
  5507. }
  5508. /**
  5509. * get an array of the table's elements that match a certain plugin type
  5510. *
  5511. * @param string $plugin
  5512. * @return array matched element models
  5513. */
  5514. function getElementsOfType($plugin)
  5515. {
  5516. $found = array();
  5517. $groups =& $this->getFormGroupElementData();
  5518. foreach ($groups as $groupModel) {
  5519. $elementModels =& $groupModel->getMyElements();
  5520. foreach ($elementModels as $elementModel) {
  5521. $element =& $elementModel->getElement();
  5522. if ($element->plugin == $plugin) {
  5523. $found[] = $elementModel;
  5524. }
  5525. }
  5526. }
  5527. return $found;
  5528. }
  5529. /**
  5530. * get all the elements in the table
  5531. * @param string key to key returned array on, currently accepts null, '', 'id', or 'filtername'
  5532. * @param bol show in table default true
  5533. * @return array table element models
  5534. */
  5535. function getElements($key = 0, $showInTable = true)
  5536. {
  5537. if (!isset($this->elements)) {
  5538. $this->elements = array();
  5539. }
  5540. $sig = $key.'.'.(int)$showInTable;
  5541. if (!array_key_exists($sig, $this->elements)) {
  5542. $this->elements[$sig] = array();
  5543. $found = array();
  5544. $this->elements[$key] = array();
  5545. $groups = $this->getFormGroupElementData();
  5546. foreach (array_keys($groups) as $gid) {
  5547. //foreach ($groups as $groupModel) { // $$$ rob dont do this as for some reason only fist groups elements are got when applying filters
  5548. $groupModel = $groups[$gid];
  5549. $elementModels =& $groupModel->getMyElements();
  5550. foreach ($elementModels as $elementModel) {
  5551. $element =& $elementModel->getElement();
  5552. if ($element->published == 0) {
  5553. continue;
  5554. }
  5555. switch ($key) {
  5556. case 'filtername'://depreciated (except for querystring filters)
  5557. // used id instead for filters
  5558. // $$$ rob was incorrect for db joinelements with search type = field
  5559. //$key = $elementModel->getFullName(false, false, false);
  5560. // $$$ rob hack to ensure that querystring filters dont use the concat string when getting the
  5561. // dbkey for the element, otherwise related data doesn't work
  5562. $origconcat = $elementModel->getParams()->get('join_val_column_concat');
  5563. $elementModel->getParams()->set('join_val_column_concat', '');
  5564. $dbkey = trim($elementModel->getFilterFullName());
  5565. //$$$ rob if prefilter was using _raw field then we need to assign the model twice to both possible keys
  5566. if ($elementModel->getElement()->plugin == 'fabrikdatabasejoin') {
  5567. $dbkey2 = FabrikString::safeColName($elementModel->getFullName(false, false, false));
  5568. $this->elements[$sig][$dbkey2] = $elementModel;
  5569. }
  5570. $elementModel->getParams()->set('join_val_column_concat', $origconcat);
  5571. //$$$ rob moved this to individual element getFilterFullName() as db join may not use it (when concat option set)
  5572. //$dbkey = FabrikString::safeColName($dbkey);
  5573. $this->elements[$sig][$dbkey] = $elementModel;
  5574. break;
  5575. case 'id':
  5576. $this->elements[$sig][$element->id] = $elementModel;
  5577. break;
  5578. default:
  5579. $this->elements[$sig][] = $elementModel;
  5580. break;
  5581. }
  5582. }
  5583. }
  5584. }
  5585. return $this->elements[$sig];
  5586. }
  5587. /**
  5588. * determines if the talbe needs mocha js classes loaded
  5589. *
  5590. * @return bol true if required
  5591. */
  5592. function requiresMocha()
  5593. {
  5594. if ($this->canCSVExport()) {
  5595. return true;
  5596. }
  5597. $params =& $this->getParams();
  5598. if ($params->get('advanced-filter') == 1) {
  5599. return true;
  5600. }
  5601. $pluginManager =& $this->getPluginManager();
  5602. $activePlugins = (array)$params->get('plugins');
  5603. $tableplugins =& $pluginManager->getPlugInGroup('list');
  5604. foreach ($tableplugins as $name => $plugin) {
  5605. if (in_array($name, $activePlugins)) {
  5606. if ($plugin->requiresMocha()) {
  5607. return true;
  5608. }
  5609. }
  5610. }
  5611. return false;
  5612. }
  5613. /**
  5614. * does the table need to include the slimbox js code
  5615. *
  5616. * @return bol
  5617. */
  5618. function requiresSlimbox()
  5619. {
  5620. $form =& $this->getFormModel();
  5621. $groups =& $form->getGroupsHiarachy();
  5622. foreach ($groups as $group) {
  5623. $elements =& $group->getPublishedElements();
  5624. foreach ($elements as $elementModel) {
  5625. $element =& $elementModel->getElement();
  5626. if ($element->show_in_list_summary && $elementModel->requiresLightBox()) {
  5627. return true;
  5628. }
  5629. }
  5630. }
  5631. return false;
  5632. }
  5633. /**
  5634. * get pluginmanager (get reference to form's plugin manager
  5635. *
  5636. * @return object plugin manager model
  5637. */
  5638. function getPluginManager()
  5639. {
  5640. $form =& $this->getFormModel();
  5641. return $form->getPluginManager();
  5642. }
  5643. /**
  5644. * called via advanced search to load in a given element filter
  5645. * @return string html for filter
  5646. */
  5647. function getAdvancedElementFilter()
  5648. {
  5649. $element = JRequest::getVar('element');
  5650. $elementid = JRequest::getVar('elid');
  5651. $pluginManager =& $this->getPluginManager();
  5652. $className = JRequest::getVar('plugin');
  5653. $plugin =& $pluginManager->getPlugIn($className, 'element');
  5654. $plugin->setId($elementid);
  5655. $el =& $plugin->getElement();
  5656. return $plugin->getFilter(JRequest::getInt('counter', 0), false);
  5657. }
  5658. /**
  5659. * build the table's add record link
  5660. * if a querystring filter has been passed in to the table then apply this to the link
  5661. * this means that table->faceted table->add will auto select the data you browsed on
  5662. * @return string url
  5663. */
  5664. function getAddRecordLink()
  5665. {
  5666. $qs = array();
  5667. $app = JFactory::getApplication();
  5668. $menuItem = $app->getMenu('site')->getActive();
  5669. $Itemid = is_object($menuItem) ? $menuItem->id : 0;
  5670. $params =& $this->getParams();
  5671. $addurl = $params->get('addurl', '');
  5672. $addlabel = $params->get('addlabel', '');
  5673. $filters =& $this->getRequestData();
  5674. $keys = JArrayHelper::getValue($filters, 'key', array());
  5675. $vals = JArrayHelper::getValue($filters, 'value', array());
  5676. $types = JArrayHelper::getValue($filters, 'search_type', array());
  5677. for ($i = 0; $i < count($keys); $i++) {
  5678. if (JArrayHelper::getValue($types, $i, '') === 'querystring') {
  5679. $qs[FabrikString::safeColNameToArrayKey($keys[$i]) . '_raw'] = $vals[$i];
  5680. }
  5681. }
  5682. $addurl_url = '';
  5683. $addurl_qs = array();
  5684. if (!empty($addurl)) {
  5685. $addurl_parts = explode('?', $addurl);
  5686. if (count($addurl_parts) > 1) {
  5687. $addurl_url = $addurl_parts[0];
  5688. foreach(explode('&', $addurl_parts[1]) as $key => $val) {
  5689. $addurl_qs[$key] = $val;
  5690. }
  5691. }
  5692. }
  5693. // $$$ rob needs the item id for when sef urls are turned on
  5694. if (JRequest::getCmd('option') !== 'com_fabrik') {
  5695. $qs['Itemid'] = $Itemid;
  5696. }
  5697. if ($this->isAjax()) {
  5698. $qs['ajax'] = '1';
  5699. }
  5700. $formModel = $this->getFormModel();
  5701. $formid = $formModel->getForm()->id;
  5702. if ($this->packageId !== 0 || $this->isAjax()) {
  5703. $qs['tmpl'] = 'component';
  5704. }
  5705. $qs['option'] = 'com_fabrik';
  5706. if ($app->isAdmin()) {
  5707. $qs['task'] = 'form.view';
  5708. } else {
  5709. $qs['view'] = 'form';
  5710. }
  5711. $qs['formid'] = $this->getTable()->form_id;
  5712. $qs['rowid'] = '0';
  5713. $qs = array_merge($qs, $addurl_qs);
  5714. foreach ($qs as $key => $val) {
  5715. $qs_args[] = $key.'='.$val;
  5716. }
  5717. $qs = implode('&', $qs_args);
  5718. if (!empty($addurl)) {
  5719. return JRoute::_($addurl_url . '?' . $qs);
  5720. } else {
  5721. return JRoute::_("index.php?" . $qs);
  5722. }
  5723. }
  5724. function getElementJs()
  5725. {
  5726. $form =& $this->getFormModel();
  5727. $script = '';
  5728. $groups =& $form->getGroupsHiarachy();
  5729. $run = array();
  5730. foreach ($groups as $groupModel) {
  5731. $elementModels =& $groupModel->getPublishedElements();
  5732. foreach ($elementModels as $elementModel) {
  5733. $element = $elementModel->getElement();
  5734. if (!in_array($element->plugin, $run)) {
  5735. $run[] = $element->plugin;
  5736. $elementModel->tableJavascriptClass();
  5737. }
  5738. $script .= $elementModel->elementListJavascript();
  5739. }
  5740. }
  5741. if ($script !== '') {
  5742. $script = "head.ready(function() {\n". $script . "});\n";
  5743. FabrikHelperHTML::addScriptDeclaration($script);
  5744. }
  5745. }
  5746. /**
  5747. * return the url for the table's form - this url is used when submitting searches, and ordering
  5748. * @return string action url
  5749. */
  5750. function getTableAction()
  5751. {
  5752. if (isset($this->tableAction)) {
  5753. return $this->tableAction;
  5754. }
  5755. $option = JRequest::getCmd('option');
  5756. // Get the router
  5757. $app = &JFactory::getApplication();
  5758. $router = &$app->getRouter();
  5759. $uri = clone(JURI::getInstance());
  5760. // $$$ rob force these to be 0 once the menu item has been loaded for the first time
  5761. //subsequent loads of the link should have this set to 0. When the menu item is re-clicked
  5762. //rest filters is set to 1 again
  5763. //if ($router->getVar('resetfilters') == 1) {
  5764. $router->setVar('resetfilters', 0);
  5765. //}
  5766. if ($option !== 'com_fabrik') {
  5767. // $$$ rob these can't be set by the menu item, but can be set in {fabrik....}
  5768. $router->setVar('clearordering', 0);
  5769. $router->setVar('clearfilters', 0);
  5770. }
  5771. $queryvars = $router->getVars();
  5772. $form = $this->getFormModel();
  5773. $page = "index.php?";
  5774. foreach ($queryvars as $k => $v) {
  5775. $el = $form->getElement($k);
  5776. if (is_array($v)) {
  5777. // $$$ rob if you were using URL filters such as
  5778. //&jos_fabble_activity___create_date[value][]=now&jos_fabble_activity___create_date[value][]=%2B2%20week&jos_fabble_activity___create_date[condition]=BETWEEN
  5779. // then we don't want to re-add them to the table action.
  5780. // Instead they are aded to the filter sessions and reapplied that way
  5781. // otherwise we ended up with elementname=Array in the query string
  5782. if ($el === false) {
  5783. $qs[] = "$k=$v";
  5784. }
  5785. } else {
  5786. if ($el === false) {
  5787. $qs[] = "$k=$v";
  5788. } else {
  5789. //check if its a tag element if it is we want to clear that when we clear the form
  5790. // (if the filter was set via the url we generally want to keep it though
  5791. if($el->getElement()->plugin !== 'textarea' && $el->getParams()->get('textarea-tagify') !== true) {
  5792. $qs[] = "$k=$v";
  5793. }
  5794. }
  5795. }
  5796. }
  5797. $action = $page . implode("&amp;", $qs);
  5798. //limitstart gets added in the pageination model
  5799. $action = preg_replace("/limitstart{$this->getId()}=(.*)?(&|)/", "", $action);
  5800. $action = FabrikString::rtrimword($action, "&");
  5801. $this->tableAction = JRoute::_($action);
  5802. return $this->tableAction;
  5803. }
  5804. /** allow plugins to add arbitrary WHERE clauses. Gets checked in _buildQueryWhere().
  5805. * always gets added with AND to the end of any other where clauses
  5806. * @param string plugin name
  5807. * @param string where clause (WITHOUT prepended where/and etc)
  5808. * @return bol
  5809. */
  5810. function setPluginQueryWhere($pluginName, $whereClause)
  5811. {
  5812. // strip any prepended conditions off
  5813. $whereClause = preg_replace('#(^where |^and |^or )#','',$whereClause);
  5814. // only do anything if it's a different clause ...
  5815. // if it's the same, no need to clear the table data, can use cached
  5816. if (!array_key_exists($pluginName,$this->_pluginQueryWhere) || $whereClause != $this->_pluginQueryWhere[$pluginName]) {
  5817. // set the internal data, which will get used in _buildQueryWhere
  5818. $this->_pluginQueryWhere['chart'] = $whereClause;
  5819. // as we are modifying the main getData query, we need to make sure and
  5820. // clear table data, forcing next getData() to do the query again, no cache
  5821. $this->set('_data', NULL);
  5822. }
  5823. // return true just for the heck of it
  5824. return true;
  5825. }
  5826. /** plugins sometimes need to clear their where clauses
  5827. * @param string plugin name
  5828. * @return bol
  5829. */
  5830. function unsetPluginQueryWhere($pluginName)
  5831. {
  5832. if (array_key_exists($pluginName, $this->_pluginQueryWhere)) {
  5833. unset($this->_pluginQueryWhere[$pluginName]);
  5834. }
  5835. return true;
  5836. }
  5837. /**
  5838. * if all filters are set to read only then don't return a clear button
  5839. * otherwised do
  5840. * @return string clear filter button link
  5841. */
  5842. function getClearButton()
  5843. {
  5844. $filters = $this->getFilters('listform_'. $this->getId(), 'list');
  5845. return count($filters) > 0 || count($this->getAdvancedFilterValues()) > 0 ? '<a href="#" class="clearFilters">'.JText::_('COM_FABRIK_CLEAR').'</a>' : '';
  5846. }
  5847. /**
  5848. * get the join display mode - merge or normal
  5849. * @return bool true if merge
  5850. */
  5851. public function mergeJoinedData()
  5852. {
  5853. $params =& $this->getParams();
  5854. $fbConfig =& JComponentHelper::getParams('com_fabrik');
  5855. $display = $params->get('join-display', '');
  5856. $merge = $display == 'merge' ? true : false;
  5857. return $merge;
  5858. }
  5859. /**
  5860. * Collapses 'repeated joined' rows into a single row.
  5861. * If a group is not repeating we just use the first row's data (as subsequent rows will contain the same data
  5862. * Otherwise if the group is repeating we append each repeated record's data into the first row's data
  5863. * All rows execpt the first row for each group are then unset (as unique subsequent row's data will be contained within
  5864. * the first row)
  5865. * @param array $data
  5866. */
  5867. function formatForJoins(&$data)
  5868. {
  5869. $merge = $this->mergeJoinedData();
  5870. if (empty($merge)) {
  5871. return;
  5872. }
  5873. $listid = $this->getTable()->id;
  5874. $dbprimaryKey = FabrikString::safeColNameToArrayKey($this->getTable()->db_primary_key);
  5875. $formModel =& $this->getFormModel();
  5876. foreach ($data as $groupk => $group) {
  5877. $last_pk = '';
  5878. $last_i = 0;
  5879. $count = count($group);
  5880. $can_repeats = array();
  5881. for ($i = 0; $i < $count; $i++) {
  5882. // $$$rob if rendering J article in PDF format __pk_val not in pdf table view
  5883. //$next_pk = isset($data[$groupk][$i]->__pk_val) ? $data[$groupk][$i]->__pk_val : $data[$groupk][$i]->id;
  5884. $next_pk = isset($data[$groupk][$i]->__pk_val) ? $data[$groupk][$i]->__pk_val : $data[$groupk][$i]->$dbprimaryKey;
  5885. if (!empty($last_pk) && ($last_pk == $next_pk)) {
  5886. foreach ($data[$groupk][$i] as $key => $val) {
  5887. $origKey = $key;
  5888. $tmpkey = FabrikString::rtrimword($key, '_raw');
  5889. // $$$ hugh - had to cache this stuff, because if you have a lot of rows and a lot of elements,
  5890. // doing this many hundreds of times causes huge slowdown, exceeding max script execution time!
  5891. // And we really only need to do it once for the first row.
  5892. if (!isset($can_repeats[$tmpkey])) {
  5893. $elementModel =& $formModel->getElement($tmpkey);
  5894. $can_repeats[$tmpkey] = $elementModel ? $elementModel->getGroup()->canRepeat() : 0;
  5895. }
  5896. if (isset($data[$groupk][$last_i]->$key) && $can_repeats[$tmpkey]) {
  5897. // $$$ rob - what about data like yes/no where each viewable option needs to be shown?
  5898. // $$$ rob - yeah commenting this out, not a good idea - as other cols for this record may have
  5899. // different data so you end up with this col having 3 entries and the next col having four and you can't
  5900. // see the correlation between the two sets of data.
  5901. //if ($data[$groupk][$last_i]->$key != $val) {
  5902. // $$$ rob meant that only one link to details was shown in admin - dont see the point in that
  5903. //if (preg_match("#\W+fabrik___rowlink.*\W+listid=$listid\W#",$val)) {
  5904. //continue;
  5905. //}
  5906. if ($origKey == $tmpkey) {
  5907. $data[$groupk][$last_i]->$key .= "<br >\n" . $val;
  5908. } else {
  5909. $json = json_decode($data[$groupk][$last_i]->$origKey);
  5910. $json= $val;
  5911. $data[$groupk][$last_i]->$origKey = json_encode($json);
  5912. //$data[$groupk][$last_i]->$origKey .= GROUPSPLITTER.$val;
  5913. }
  5914. }
  5915. }
  5916. unset($data[$groupk][$i]);
  5917. continue;
  5918. }
  5919. else {
  5920. $last_i = $i;
  5921. // $$$rob if rendering J article in PDF format __pk_val not in pdf table view
  5922. $last_pk = $next_pk;
  5923. }
  5924. }
  5925. // $$$ rob ensure that we have a sequental set of keys otherwise ajax json will turn array into object
  5926. $data[$groupk] = array_values($data[$groupk]);
  5927. }
  5928. }
  5929. function noTable()
  5930. {
  5931. return empty($this->_id);
  5932. }
  5933. /**
  5934. *
  5935. * save an individual element value to the fabrik db
  5936. *
  5937. * @param string $rowId
  5938. * @param string $key
  5939. * @param string $value
  5940. */
  5941. public function storeCell($rowId, $key, $value)
  5942. {
  5943. $data[$key] = $value;
  5944. $this->storeRow($data, $rowId);
  5945. }
  5946. /**
  5947. *
  5948. * increment a value in a cell
  5949. * @param string $rowId
  5950. * @param strin $key
  5951. * @param string $dir -1/1 etc
  5952. */
  5953. public function incrementCell($rowId, $key, $dir)
  5954. {
  5955. $db = $this->getDb();
  5956. $table =& $this->getTable();
  5957. $query = "UPDATE $table->db_table_name SET $key = COALESCE($key,0) + $dir WHERE $table->db_primary_key = ".$db->Quote($rowId);
  5958. $db->setQuery($query);
  5959. return $db->query();
  5960. }
  5961. protected function populateState()
  5962. {
  5963. $app = JFactory::getApplication('site');
  5964. if (!$app->isAdmin()) {
  5965. // Load the menu item / component parameters.
  5966. $params = $app->getParams();
  5967. $this->setState('params', $params);
  5968. // Load state from the request.
  5969. $pk = JRequest::getInt('listid', $params->get('listid'));
  5970. } else {
  5971. $pk = JRequest::getInt('listid');
  5972. }
  5973. $this->setState('list.id', $pk);
  5974. $offset = JRequest::getInt('limitstart');
  5975. $this->setState('list.offset', $offset);
  5976. }
  5977. public function getOutPutFormat()
  5978. {
  5979. return $this->_outPutFormat;
  5980. }
  5981. /**
  5982. * update a series of rows with a key = val , works across joined tables
  5983. * Enter description here ...
  5984. * @param array $ids
  5985. * @param string $col
  5986. * @param string $val
  5987. */
  5988. public function updateRows($ids, $col, $val)
  5989. {
  5990. if ($col == '') {
  5991. return;
  5992. }
  5993. if (empty($ids)) {
  5994. return;
  5995. }
  5996. $db =& $this->getDb();
  5997. $nav =& $this->getPagination(1, 0, 1);
  5998. $data = $this->getData();
  5999. // $$$ rob dont unshift as this messes up for grouped data
  6000. //$data = array_shift($data);
  6001. $table =& $this->getTable();
  6002. $update = "$col = ".$db->Quote($val);
  6003. $tbl = array_shift(explode('.', $col));
  6004. $joinFound = false;
  6005. JArrayHelper::toInteger($ids);
  6006. $ids = implode(',', $ids);
  6007. $dbk = $k = $table->db_primary_key;
  6008. $joins =& $this->getJoins();
  6009. // if the update element is in a join replace the key and table name with the
  6010. // join table's name and key
  6011. foreach ($joins as $join) {
  6012. if ($join->table_join == $tbl) {
  6013. $joinFound = true;
  6014. $db->setQuery('DESCRIBE '.$tbl);
  6015. $fields = $db->loadObjectList('Key');
  6016. $k = $tbl.'___'.$fields['PRI']->Field;
  6017. $dbk = $tbl.'.'.$fields['PRI']->Field;
  6018. $db_table_name = $tbl;
  6019. $ids = array();
  6020. foreach ($data as $groupdata) {
  6021. foreach ($groupdata as $d) {
  6022. $v = $d->{$k.'_raw'};
  6023. if ($v != '') {
  6024. $ids[] = $v;
  6025. }
  6026. }
  6027. }
  6028. if (!empty($ids)) {
  6029. $ids = implode(',', $ids);
  6030. $db->setQuery("UPDATE $db_table_name SET $update WHERE $dbk IN ($ids)");
  6031. $db->query();
  6032. }
  6033. }
  6034. }
  6035. if (!$joinFound) {
  6036. $db_table_name = $table->db_table_name;
  6037. $db->setQuery("UPDATE $db_table_name SET $update WHERE $dbk IN ($ids)");
  6038. $db->query();
  6039. }
  6040. }
  6041. public function reset()
  6042. {
  6043. unset($this->_whereSQL);
  6044. unset($this->_table);
  6045. unset($this->filters);
  6046. unset($this->prefilters);
  6047. unset($this->_params);
  6048. // $$$ hugh - added some more stuff to clear, as per:
  6049. // http://fabrikar.com/forums/showthread.php?p=115122#post115122
  6050. unset($this->asfields);
  6051. unset($this->_oForm);
  6052. unset($this->filterModel);
  6053. unset($this->searchAllAsFields);
  6054. unset($this->_joinsSQL);
  6055. unset($this->_aJoins);
  6056. unset($this->_joinsNoCdd);
  6057. unset($this->elements);
  6058. }
  6059. /**
  6060. * @since 3.0
  6061. * get the table template
  6062. * @return string template name
  6063. */
  6064. public function getTmpl()
  6065. {
  6066. $app = JFactory::getApplication();
  6067. $item = $this->getTable();
  6068. $params = $this->getParams();
  6069. if ($app->isAdmin()) {
  6070. $tmpl = JRequest::getVar('layout', $params->get('admin_template'));
  6071. } else {
  6072. $tmpl = JRequest::getVar('layout', $item->template);
  6073. }
  6074. if ($tmpl == '') {
  6075. $tmpl = 'default';
  6076. }
  6077. // if we are mobilejoomla.com system plugin to detect smartphones
  6078. if (JRequest::getVar('mjmarkup') == 'iphone') {
  6079. $tmpl = 'iwebkit';
  6080. }
  6081. return $tmpl;
  6082. }
  6083. protected function setElementTmpl()
  6084. {
  6085. $tmpl = $this->getTmpl();
  6086. $groups = $this->getFormModel()->getGroupsHiarachy();
  6087. $params = $this->getParams();
  6088. foreach ($groups as $groupModel) {
  6089. if (($params->get('group_by_template') !== '' && $this->getGroupBy() != '') || $this->_outPutFormat == 'csv' || $this->_outPutFormat == 'feed') {
  6090. $elementModels =& $groupModel->getPublishedElements();
  6091. } else {
  6092. $elementModels =& $groupModel->getPublishedTableElements();
  6093. }
  6094. foreach ($elementModels as $elementModel) {
  6095. $elementModel->tmpl = $tmpl;
  6096. }
  6097. }
  6098. }
  6099. public function inJDb()
  6100. {
  6101. $config = JFactory::getConfig();
  6102. $cnn = $this->getConnection()->getConnection();
  6103. // if the table database is not the same as the joomla database then
  6104. // we should simply return a hidden field with the user id in it.
  6105. return $config->getValue('db') == $cnn->database;
  6106. }
  6107. /**
  6108. * @since 3.0 loads lists's css files
  6109. * Checks : J template html override css file then fabrik list tmpl template css file. Including them if found
  6110. */
  6111. public function getListCss()
  6112. {
  6113. $tmpl = $this->getTmpl();
  6114. $app = JFactory::getApplication();
  6115. /* check for a form template file (code moved from view) */
  6116. if ($tmpl != '') {
  6117. if (JFile::exists(JPATH_THEMES.'/'.$app->getTemplate().'/html/com_fabrik/list/'.$tmpl.'/template_css.php')) {
  6118. FabrikHelperHTML::stylesheet(COM_FABRIK_LIVESITE.'templates/'.$app->getTemplate().'/html/com_fabrik/list/'.$tmpl.'/template_css.php?c='.$this->getId());
  6119. } else {
  6120. FabrikHelperHTML::stylesheet(COM_FABRIK_LIVESITE."components/com_fabrik/views/list/tmpl/".$tmpl."/template_css.php?c=".$this->getId());
  6121. }
  6122. }
  6123. }
  6124. public function getGroupByHeadings()
  6125. {
  6126. $base = JURI::getInstance();
  6127. $base = $base->toString(array('scheme', 'user', 'pass', 'host', 'port', 'path'));
  6128. $base .= strpos($base, '?') ? '&' : '?';
  6129. $qs = $_SERVER['QUERY_STRING'];
  6130. $qs = urlencode(FabrikString::removeQSVar($qs, 'group_by'));
  6131. $url = $base.$qs;
  6132. $url .= strpos($url, '?') ? '&amp;' : '?';
  6133. $a = array();
  6134. list($h, $x, $b, $c) = $this->getHeadings();
  6135. $a[$url] = 'none';
  6136. foreach($h as $key => $v) {
  6137. if (!in_array($key, array('fabrik_select', 'fabrik_edit', 'fabrik_view', 'fabrik_delete', 'fabrik_actions'))) {
  6138. $thisurl = $url.'group_by='.$key;
  6139. $a[$thisurl] = strip_tags($v);
  6140. }
  6141. }
  6142. return $a;
  6143. }
  6144. }
  6145. ?>