PageRenderTime 76ms CodeModel.GetById 25ms 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

Large files files are truncated, but you can click here to view the full file

  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 setOr

Large files files are truncated, but you can click here to view the full file