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

/system/modules/generalDriver/GeneralControllerDefault.php

https://github.com/backbone87/metamodels-DC_General
PHP | 3451 lines | 2190 code | 518 blank | 743 comment | 447 complexity | a102491a343744dd43b95a222c7fa40d MD5 | raw file
  1. <?php
  2. /**
  3. * PHP version 5
  4. * @package generalDriver
  5. * @author Stefan Heimes <cms@men-at-work.de>
  6. * @copyright The MetaModels team.
  7. * @license LGPL.
  8. * @filesource
  9. */
  10. class GeneralControllerDefault extends Controller implements InterfaceGeneralController
  11. {
  12. /* /////////////////////////////////////////////////////////////////////
  13. * ---------------------------------------------------------------------
  14. * Vars
  15. * ---------------------------------------------------------------------
  16. * ////////////////////////////////////////////////////////////////// */
  17. // Objects -----------------------
  18. /**
  19. * Current DC General
  20. *
  21. * @var DC_General
  22. */
  23. protected $objDC = null;
  24. /**
  25. * Contao Encrypt class
  26. * @var Encryption
  27. */
  28. protected $objEncrypt = null;
  29. // Current -----------------------
  30. /**
  31. * A list with all current ID`s
  32. * @var array
  33. */
  34. protected $arrInsertIDs = array();
  35. // States ------------------------
  36. /**
  37. * State of Show/Close all
  38. * @var boolean
  39. */
  40. protected $blnShowAllEntries = false;
  41. // Misc. -------------------------
  42. /**
  43. * Error msg
  44. *
  45. * @var string
  46. */
  47. protected $notImplMsg = "<div style='text-align:center; font-weight:bold; padding:40px;'>The function/view &quot;%s&quot; is not implemented.<br />Please <a target='_blank' style='text-decoration:underline' href='http://now.metamodel.me/en/sponsors/become-one#payment'>support us</a> to add this important feature!</div>";
  48. /**
  49. * Field for the function sortCollection
  50. *
  51. * @var string $arrColSort
  52. */
  53. protected $arrColSort;
  54. /* /////////////////////////////////////////////////////////////////////
  55. * ---------------------------------------------------------------------
  56. * Magic functions
  57. * ---------------------------------------------------------------------
  58. * ////////////////////////////////////////////////////////////////// */
  59. public function __construct()
  60. {
  61. parent::__construct();
  62. // Import
  63. $this->import('Encryption');
  64. // Check some vars
  65. $this->blnShowAllEntries = ($this->Input->get('ptg') == 'all') ? 1 : 0;
  66. }
  67. public function __call($name, $arguments)
  68. {
  69. switch ($name)
  70. {
  71. default:
  72. throw new Exception("Error Processing Request: " . $name, 1);
  73. break;
  74. };
  75. }
  76. /* /////////////////////////////////////////////////////////////////////
  77. * ---------------------------------------------------------------------
  78. * Getter & Setter
  79. * ---------------------------------------------------------------------
  80. * ////////////////////////////////////////////////////////////////// */
  81. /**
  82. * Get DC General
  83. * @return DC_General
  84. */
  85. public function getDC()
  86. {
  87. return $this->objDC;
  88. }
  89. /**
  90. * Set DC General
  91. * @param DC_General $objDC
  92. */
  93. public function setDC($objDC)
  94. {
  95. $this->objDC = $objDC;
  96. }
  97. /**
  98. * Get filter for the data provider
  99. *
  100. * @todo Somtimes we don't need all filtersettings
  101. * @todo add new var like level = all, root, parent etc.
  102. * @todo check where we use this.
  103. * @todo it`s a nice function, maybe a core function ?
  104. *
  105. * @return array();
  106. */
  107. protected function getFilter()
  108. {
  109. $arrFilter = $this->getDC()->getFilter();
  110. if ($arrFilter)
  111. {
  112. return $arrFilter;
  113. }
  114. // Custom filter
  115. if (is_array($this->getDC()->arrDCA['list']['sorting']['filter']) && !empty($this->getDC()->arrDCA['list']['sorting']['filter']))
  116. {
  117. $arrFilters = array();
  118. foreach ($this->getDC()->arrDCA['list']['sorting']['filter'] as $filter)
  119. {
  120. $arrFilters[] = array('operation' => '=', 'property' => $filter[0], 'value' => $filter[1]);
  121. }
  122. if (count($arrFilters))
  123. {
  124. $this->getDC()->setFilter(array(array('operation' => 'AND', 'childs' => $arrFilters)));
  125. }
  126. }
  127. if (is_array($this->getDC()->arrDCA['list']['sorting']['root']) && !empty($this->getDC()->arrDCA['list']['sorting']['root']))
  128. {
  129. $arrFilters = array();
  130. foreach ($this->getDC()->arrDCA['list']['sorting']['root'] as $mixId)
  131. {
  132. $arrFilters[] = array('operation' => '=', 'property' => 'id', 'value' => $mixId);
  133. }
  134. if (count($arrFilters))
  135. {
  136. $this->getDC()->setFilter(array(array('operation' => 'OR', 'childs' => $arrFilters)));
  137. }
  138. }
  139. // TODO: we need to transport all the fields from the root conditions via the url and set filters accordingly here.
  140. // FIXME: this is only valid for mode 4 appearantly, fix for other views.
  141. if ($this->Input->get('table') && !is_null($this->getDC()->getParentTable()))
  142. {
  143. $objParentDP = $this->getDC()->getDataProvider('parent');
  144. $objParentItem = $objParentDP->fetch($objParentDP->getEmptyConfig()->setId(CURRENT_ID));
  145. $objCollection = $objParentDP->getEmptyCollection();
  146. // no parent item found, might have been deleted - we transparently create it for our filter to be able to filter to nothing.
  147. // TODO: shall we rather bail with "parent not found" than pushing all of this to the database?
  148. if (!$objParentItem)
  149. {
  150. $objParentItem = $objParentDP->getEmptyModel();
  151. $objParentItem->setID(CURRENT_ID);
  152. }
  153. $objCollection->add($objParentItem);
  154. // NOTE: we set the parent collection here, which will get used in the parentView() routine.
  155. $this->getDC()->setCurrentParentCollection($objCollection);
  156. $arrFilter = $this->getDC()->getChildCondition($objParentItem, 'self');
  157. $this->getDC()->setFilter($arrFilter);
  158. }
  159. // FIXME implement panel filter from session
  160. // FIXME all panels write into $this->getDC()->setFilter() or setLimit.
  161. return $this->getDC()->getFilter();
  162. }
  163. /**
  164. * Get limit for the data provider
  165. *
  166. * @return array
  167. */
  168. protected function calculateLimit()
  169. {
  170. // Get the limit form the DCA
  171. if (!is_null($this->getDC()->getLimit()))
  172. {
  173. return trimsplit(',', $this->getDC()->getLimit());
  174. }
  175. $arrSession = Session::getInstance()->getData();
  176. $strFilter = ($this->getDC()->arrDCA['list']['sorting']['mode'] == 4) ? $this->getDC()->getTable() . '_' . CURRENT_ID : $this->getDC()->getTable();
  177. // Load from Session - Set all
  178. if ($arrSession['filter'][$strFilter]['limit'] == 'all')
  179. {
  180. // Get max amount
  181. $objConfig = $this->getDC()->getDataProvider()->getEmptyConfig()->setFilter($this->getFilter());
  182. $intMax = $this->getDC()->getDataProvider()->getCount($objConfig);
  183. $this->getDC()->setLimit("0,$intMax");
  184. }
  185. // Load from Session
  186. else if (strlen($arrSession['filter'][$strFilter]['limit']) != 0)
  187. {
  188. $this->getDC()->setLimit($arrSession['filter'][$strFilter]['limit']);
  189. }
  190. // Check if the current limit is higher than the limit resultsPerPage
  191. $arrLimit = trimsplit(",", $this->getDC()->getLimit());
  192. $intMaxPerPage = $arrLimit[1] - $arrLimit[0];
  193. if ($intMaxPerPage > $GLOBALS['TL_CONFIG']['resultsPerPage'] && $arrSession['filter'][$strFilter]['limit'] != 'all')
  194. {
  195. $this->getDC()->setLimit($arrLimit[0] . ', ' . ($arrLimit[0] + $GLOBALS['TL_CONFIG']['resultsPerPage']));
  196. }
  197. // Fallback and limit check
  198. if (is_null($this->getDC()->getLimit()))
  199. {
  200. $this->getDC()->setLimit('0,' . $GLOBALS['TL_CONFIG']['resultsPerPage']);
  201. }
  202. return trimsplit(',', $this->getDC()->getLimit());
  203. }
  204. /**
  205. * Set the sorting and first sorting.
  206. * Use the default ones from DCA or the session values.
  207. *
  208. * @todo SH:CS: Add findInSet if we have the functions for foreignKey
  209. * @return void
  210. */
  211. protected function establishSorting()
  212. {
  213. // Get sorting fields
  214. $arrSortingFields = array();
  215. foreach ($this->getDC()->arrDCA['fields'] as $k => $v)
  216. {
  217. if ($v['sorting'])
  218. {
  219. if (is_null($v['flag']))
  220. {
  221. $arrSortingFields[$k] = DCGE::MODEL_SORTING_ASC;
  222. }
  223. else
  224. {
  225. $arrSortingFields[$k] = $v['flag'] % 2 ? DCGE::MODEL_SORTING_ASC : DCGE::MODEL_SORTING_DESC;
  226. }
  227. }
  228. }
  229. $this->getDC()->setSorting(array_keys($arrSortingFields));
  230. // Check if we have another sorting from session/panels
  231. $arrSession = Session::getInstance()->getData();
  232. $strSessionSorting = preg_replace('/\s+.*$/i', '', strval($arrSession['sorting'][$this->getDC()->getTable()]));
  233. if (isset($arrSortingFields[$strSessionSorting]))
  234. {
  235. $this->getDC()->setFirstSorting($strSessionSorting, $arrSortingFields[$strSessionSorting]);
  236. return;
  237. }
  238. // Set default values from DCA
  239. $arrSorting = (array) $this->getDC()->arrDCA['list']['sorting']['fields'];
  240. $strFirstSorting = preg_replace('/\s+.*$/i', '', strval($arrSorting[0]));
  241. if (!isset($this->getDC()->arrDCA['list']['sorting']['flag']))
  242. {
  243. $strFirstSortingOrder = DCGE::MODEL_SORTING_ASC;
  244. }
  245. else
  246. {
  247. $strFirstSortingOrder = $this->getDC()->arrDCA['list']['sorting']['flag'] % 2 ? DCGE::MODEL_SORTING_ASC : DCGE::MODEL_SORTING_DESC;
  248. }
  249. if (!strlen($strFirstSorting))
  250. {
  251. foreach (array('sorting', 'tstamp', 'pid', 'id') as $strField)
  252. {
  253. if ($this->getDC()->getDataProvider()->fieldExists($strField))
  254. {
  255. $strFirstSorting = $strField;
  256. break;
  257. }
  258. }
  259. }
  260. $this->getDC()->setFirstSorting($strFirstSorting, $strFirstSortingOrder);
  261. return;
  262. }
  263. /* /////////////////////////////////////////////////////////////////////
  264. * ---------------------------------------------------------------------
  265. * Core Support functions // Check Function
  266. * ---------------------------------------------------------------------
  267. * ////////////////////////////////////////////////////////////////// */
  268. /**
  269. * Redirects to the real back end module.
  270. */
  271. protected function redirectHome()
  272. {
  273. if ($this->Input->get('table') && $this->Input->get('id'))
  274. {
  275. $this->redirect(sprintf('contao/main.php?do=%s&table=%s&id=%s', $this->Input->get('do'), $this->getDC()->getTable(), $this->Input->get('id')));
  276. }
  277. $this->redirect('contao/main.php?do=' . $this->Input->get('do'));
  278. }
  279. /**
  280. * Check if the curren model support multi language.
  281. * Load the language from SESSION, POST or use a fallback.
  282. *
  283. * @return int return the mode multilanguage, singellanguage, see DCGE.php
  284. */
  285. protected function checkLanguage()
  286. {
  287. // Load basic informations
  288. $intID = $this->getDC()->getId();
  289. $objDataProvider = $this->getDC()->getDataProvider();
  290. // Check if current dataprovider supports multilanguage
  291. if (in_array('InterfaceGeneralDataMultiLanguage', class_implements($objDataProvider)))
  292. {
  293. $objLanguagesSupported = $this->getDC()->getDataProvider()->getLanguages($intID);
  294. }
  295. else
  296. {
  297. $objLanguagesSupported = null;
  298. }
  299. //Check if we have some languages
  300. if ($objLanguagesSupported == null)
  301. {
  302. return DCGE::LANGUAGE_SL;
  303. }
  304. // Load language from Session
  305. $arrSession = $this->Session->get("dc_general");
  306. if (!is_array($arrSession))
  307. {
  308. $arrSession = array();
  309. }
  310. // try to get the language from session
  311. if (isset($arrSession["ml_support"][$this->getDC()->getTable()][$intID]))
  312. {
  313. $strCurrentLanguage = $arrSession["ml_support"][$this->getDC()->getTable()][$intID];
  314. }
  315. else
  316. {
  317. $strCurrentLanguage = $GLOBALS['TL_LANGUAGE'];
  318. }
  319. // Make a array from the collection
  320. $arrLanguage = array();
  321. foreach ($objLanguagesSupported as $value)
  322. {
  323. $arrLanguage[$value->getID()] = $value->getProperty("name");
  324. }
  325. // Get/Check the new language
  326. if (strlen($this->Input->post("language")) != 0 && $_POST['FORM_SUBMIT'] == 'language_switch')
  327. {
  328. if (key_exists($this->Input->post("language"), $arrLanguage))
  329. {
  330. $strCurrentLanguage = $this->Input->post("language");
  331. $arrSession["ml_support"][$this->getDC()->getTable()][$intID] = $strCurrentLanguage;
  332. }
  333. else if (key_exists($strCurrentLanguage, $arrLanguage))
  334. {
  335. $arrSession["ml_support"][$this->getDC()->getTable()][$intID] = $strCurrentLanguage;
  336. }
  337. else
  338. {
  339. $objlanguageFallback = $objDataProvider->getFallbackLanguage();
  340. $strCurrentLanguage = $objlanguageFallback->getID();
  341. $arrSession["ml_support"][$this->getDC()->getTable()][$intID] = $strCurrentLanguage;
  342. }
  343. }
  344. $this->Session->set("dc_general", $arrSession);
  345. $objDataProvider->setCurrentLanguage($strCurrentLanguage);
  346. return DCGE::LANGUAGE_ML;
  347. }
  348. /**
  349. * Check if is editable AND not clodes
  350. */
  351. protected function checkIsWritable()
  352. {
  353. // Check if table is editable
  354. if (!$this->getDC()->isEditable())
  355. {
  356. $this->log('Table ' . $this->getDC()->getTable() . ' is not editable', 'DC_General - Controller - copy()', TL_ERROR);
  357. $this->redirect('contao/main.php?act=error');
  358. }
  359. // Check if table is editable
  360. if ((!$this->getDC()->getId()) && $this->getDC()->isClosed())
  361. {
  362. $this->log('Table ' . $this->getDC()->getTable() . ' is closed', 'DC_General - Controller - copy()', TL_ERROR);
  363. $this->redirect('contao/main.php?act=error');
  364. }
  365. }
  366. /* /////////////////////////////////////////////////////////////////////
  367. * ---------------------------------------------------------------------
  368. * Clipboard functions
  369. * ---------------------------------------------------------------------
  370. * ////////////////////////////////////////////////////////////////// */
  371. /**
  372. * Clear clipboard
  373. * @param boolean $blnRedirect True - redirect to home site
  374. */
  375. protected function resetClipboard($blnRedirect = false)
  376. {
  377. // Get clipboard
  378. $arrClipboard = $this->loadClipboard();
  379. $this->getDC()->setClipboardState(false);
  380. unset($arrClipboard[$this->getDC()->getTable()]);
  381. // Save
  382. $this->saveClipboard($arrClipboard);
  383. // Redirect
  384. if ($blnRedirect == true)
  385. {
  386. $this->redirectHome();
  387. }
  388. // Set DC state
  389. $this->getDC()->setClipboardState(false);
  390. }
  391. /**
  392. * Check clipboard state. Clear or save state of it.
  393. */
  394. protected function checkClipboard()
  395. {
  396. $arrClipboard = $this->loadClipboard();
  397. // Reset Clipboard
  398. if ($this->Input->get('clipboard') == '1')
  399. {
  400. $this->resetClipboard(true);
  401. }
  402. // Add new entry
  403. else if ($this->Input->get('act') == 'paste')
  404. {
  405. $this->getDC()->setClipboardState(true);
  406. $arrClipboard[$this->getDC()->getTable()] = array(
  407. 'id' => $this->Input->get('id'),
  408. 'source' => $this->Input->get('source'),
  409. 'childs' => $this->Input->get('childs'),
  410. 'mode' => $this->Input->get('mode'),
  411. 'pdp' => $this->Input->get('pdp'),
  412. 'cdp' => $this->Input->get('cdp'),
  413. );
  414. switch ($this->Input->get('mode'))
  415. {
  416. case 'cut':
  417. // Id Array
  418. $arrIDs = array();
  419. $arrIDs[] = $this->Input->get('source');
  420. switch ($this->arrDCA['list']['sorting']['mode'])
  421. {
  422. case 5:
  423. // Run each id
  424. for ($i = 0; $i < count($arrIDs); $i++)
  425. {
  426. // Get current model
  427. $objCurrentConfig = $this->getDC()->getDataProvider()->getEmptyConfig();
  428. $objCurrentConfig->setId($arrIDs[$i]);
  429. $objCurrentModel = $this->getDC()->getDataProvider()->fetch($objCurrentConfig);
  430. // Get the join field
  431. $arrJoinCondition = $this->getDC()->getChildCondition($objCurrentModel, 'self');
  432. $objChildConfig = $this->getDC()->getDataProvider()->getEmptyConfig();
  433. $objChildConfig->setFilter($arrJoinCondition);
  434. $objChildConfig->setIdOnly(true);
  435. $objChildCollection = $this->getDC()->getDataProvider()->fetchAll($objChildConfig);
  436. foreach ($objChildCollection as $key => $value)
  437. {
  438. if (!in_array($value, $arrIDs))
  439. {
  440. $arrIDs[] = $value;
  441. }
  442. }
  443. }
  444. break;
  445. }
  446. $arrClipboard[$this->getDC()->getTable()]['ignoredIDs'] = $arrIDs;
  447. break;
  448. }
  449. $this->getDC()->setClipboard($arrClipboard[$this->getDC()->getTable()]);
  450. }
  451. // Check clipboard from session
  452. else if (key_exists($this->getDC()->getTable(), $arrClipboard))
  453. {
  454. $this->getDC()->setClipboardState(true);
  455. $this->getDC()->setClipboard($arrClipboard[$this->getDC()->getTable()]);
  456. }
  457. $this->saveClipboard($arrClipboard);
  458. }
  459. protected function loadClipboard()
  460. {
  461. $arrClipboard = $this->Session->get('CLIPBOARD');
  462. if (!is_array($arrClipboard))
  463. {
  464. $arrClipboard = array();
  465. }
  466. return $arrClipboard;
  467. }
  468. protected function saveClipboard($arrClipboard)
  469. {
  470. if (is_array($arrClipboard))
  471. {
  472. $this->Session->set('CLIPBOARD', $arrClipboard);
  473. }
  474. }
  475. /* /////////////////////////////////////////////////////////////////////
  476. * ---------------------------------------------------------------------
  477. * Core Functions
  478. * ---------------------------------------------------------------------
  479. * ////////////////////////////////////////////////////////////////// */
  480. /**
  481. * Cut and paste
  482. *
  483. * <p>
  484. * -= GET Parameter =-<br/>
  485. * act - Mode like cut | copy | and co <br/>
  486. * <br/>
  487. * after - ID of target element to insert after <br/>
  488. * into - ID of parent element to insert into <br/>
  489. * <br/>
  490. * id - Parent child ID used for redirect <br/>
  491. * pid - ID of the parent used in list mode 4,5 <br/>
  492. * source - ID of the element which should moved <br/>
  493. * <br/>
  494. * pdp - Parent Data Provider real name <br/>
  495. * cdp - Current Data Provider real name <br/>
  496. * <br/>
  497. * -= Deprecated =-<br/>
  498. * mode - 1 Insert after | 2 Insert into (NEVER USED AGAIN - Deprecated) <br/>
  499. * </p>
  500. */
  501. public function cut()
  502. {
  503. // Checks
  504. $this->checkIsWritable();
  505. // Get vars
  506. $mixAfter = $this->Input->get('after');
  507. $mixInto = $this->Input->get('into');
  508. $intId = $this->Input->get('id');
  509. $mixPid = $this->Input->get('pid');
  510. $mixSource = $this->Input->get('source');
  511. $strPDP = $this->Input->get('pdp');
  512. $strCDP = $this->Input->get('cdp');
  513. // Deprecated
  514. $intMode = $this->Input->get('mode');
  515. $mixChild = $this->Input->get('child');
  516. // Check basic vars
  517. if (empty($mixSource) || ( is_null($mixAfter) && is_null($mixInto) ) || empty($strCDP))
  518. {
  519. $this->log('Missing parameter for cut in ' . $this->getDC()->getTable(), __CLASS__ . ' - ' . __FUNCTION__, TL_ERROR);
  520. $this->redirect('contao/main.php?act=error');
  521. }
  522. // Get current DataProvider
  523. if (!empty($strCDP))
  524. {
  525. $objCurrentDataProvider = $this->getDC()->getDataProvider($strCDP);
  526. }
  527. else
  528. {
  529. $objCurrentDataProvider = $this->getDC()->getDataProvider();
  530. }
  531. if ($objCurrentDataProvider == null)
  532. {
  533. throw new Exception('Could not load current data provider in ' . __CLASS__ . ' - ' . __FUNCTION__);
  534. }
  535. // Get parent DataProvider, if set
  536. $objParentDataProvider = null;
  537. if (!empty($strPDP))
  538. {
  539. $objParentDataProvider = $this->objDC->getDataProvider($strPDP);
  540. if ($objCurrentDataProvider == null)
  541. {
  542. throw new Exception('Could not load parent data provider ' . $strPDP . ' in ' . __CLASS__ . ' - ' . __FUNCTION__);
  543. }
  544. }
  545. // Load the source model
  546. $objSrcModel = $objCurrentDataProvider->fetch($objCurrentDataProvider->getEmptyConfig()->setId($mixSource));
  547. // Check mode
  548. switch ($this->getDC()->arrDCA['list']['sorting']['mode'])
  549. {
  550. case 0:
  551. $this->getNewPosition($objCurrentDataProvider, $objParentDataProvider, $objSrcModel, DCGE::INSERT_AFTER_END, null, 'cut');
  552. break;
  553. case 1:
  554. case 2:
  555. case 3:
  556. case 4:
  557. $this->getNewPosition($objCurrentDataProvider, $objParentDataProvider, $objSrcModel, $mixAfter, $mixInto, 'cut');
  558. break;
  559. case 5:
  560. switch ($intMode)
  561. {
  562. case 1: // insert after
  563. // we want a new item in $strCDP having an optional parent in $strPDP (with pid item $mixPid) just after $mixAfter (in child tree conditions).
  564. // sadly, with our complex rules an getParent() is IMPOSSIBLE (or in other words way too costly as we would be forced to iterate through all items and check if this item would end up in their child collection).
  565. // therefore we get the child we want to be next of and set all fields to the same values as in the sibling to end up in the same parent.
  566. $objOtherChild = $objCurrentDataProvider->fetch($objCurrentDataProvider->getEmptyConfig()->setId($mixAfter));
  567. $this->getDC()->setSameParent($objSrcModel, $objOtherChild, $strCDP);
  568. // Update sorting.
  569. $this->getNewPosition($objCurrentDataProvider, $objParentDataProvider, $objSrcModel, $mixAfter, $mixInto, 'cut');
  570. break;
  571. case 2: // insert into
  572. // we want a new item in $strCDP having an optional parent in $strPDP (with pid item $mixPid) just as child of $mixAfter (in child tree conditions).
  573. // now check if we want to be inserted as root in our own condition - this means either no "after".
  574. if (($mixAfter == 0))
  575. {
  576. $this->setRoot($objSrcModel, 'self');
  577. }
  578. else
  579. {
  580. // enforce the child condition from our parent.
  581. $objMyParent = $objCurrentDataProvider->fetch($objCurrentDataProvider->getEmptyConfig()->setId($mixAfter));
  582. $this->setParent($objSrcModel, $objMyParent, 'self');
  583. }
  584. // Update sorting.
  585. $this->getNewPosition($objCurrentDataProvider, $objParentDataProvider, $objSrcModel, $mixAfter, $mixInto, 'cut');
  586. break;
  587. default:
  588. $this->log('Unknown create mode for copy in ' . $this->getDC()->getTable(), 'DC_General - Controller - copy()', TL_ERROR);
  589. $this->redirect('contao/main.php?act=error');
  590. break;
  591. }
  592. break;
  593. default:
  594. return vsprintf($this->notImplMsg, 'cut - Mode ' . $this->getDC()->arrDCA['list']['sorting']['mode']);
  595. break;
  596. }
  597. // Save new sorting
  598. $objCurrentDataProvider->save($objSrcModel);
  599. // Reset clipboard + redirect
  600. $this->resetClipboard(true);
  601. }
  602. /**
  603. * Copy a entry and all childs
  604. *
  605. * @return string error msg for an unknown mode
  606. */
  607. public function copy()
  608. {
  609. // Check
  610. $this->checkIsWritable();
  611. switch ($this->getDC()->arrDCA['list']['sorting']['mode'])
  612. {
  613. case 0:
  614. case 1:
  615. case 2:
  616. case 3:
  617. $intId = $this->Input->get('id');
  618. $intPid = (strlen($this->Input->get('pid')) != 0)? $this->Input->get('pid') : 0;
  619. if (strlen($intId) == 0)
  620. {
  621. $this->log('Missing parameter for copy in ' . $this->getDC()->getTable(), 'DC_General - Controller - copy()', TL_ERROR);
  622. $this->redirect('contao/main.php?act=error');
  623. }
  624. // Check
  625. $this->checkIsWritable();
  626. $this->checkLanguage($this->getDC());
  627. // Load fields and co
  628. $this->getDC()->loadEditableFields();
  629. $this->getDC()->setWidgetID($this->getDC()->getId());
  630. // Check if we have fields
  631. if (!$this->getDC()->hasEditableFields())
  632. {
  633. $this->redirect($this->getReferer());
  634. }
  635. // Load something
  636. $this->getDC()->preloadTinyMce();
  637. // Load record from data provider - Load the source model
  638. $objDataProvider = $this->getDC()->getDataProvider();
  639. $objSrcModel = $objDataProvider->fetch($objDataProvider->getEmptyConfig()->setId($intId));
  640. $objDBModel = clone $objSrcModel;
  641. $objDBModel->setMeta(DCGE::MODEL_IS_CHANGED, true);
  642. $this->getDC()->setCurrentModel($objDBModel);
  643. // Check if we have a auto submit
  644. $this->getDC()->updateModelFromPOST();
  645. // Check submit
  646. if ($this->getDC()->isSubmitted() == true)
  647. {
  648. if (isset($_POST["save"]))
  649. {
  650. // process input and update changed properties.
  651. if ($this->doSave($this->getDC()) !== false)
  652. {
  653. $this->reload();
  654. }
  655. }
  656. else if (isset($_POST["saveNclose"]))
  657. {
  658. // process input and update changed properties.
  659. if ($this->doSave($this->getDC()) !== false)
  660. {
  661. setcookie('BE_PAGE_OFFSET', 0, 0, '/');
  662. $_SESSION['TL_INFO'] = '';
  663. $_SESSION['TL_ERROR'] = '';
  664. $_SESSION['TL_CONFIRM'] = '';
  665. $this->redirect($this->getReferer());
  666. }
  667. }
  668. // Maybe Callbacks ? Yes, this is the first version of an simple
  669. // button callback system like dc_memory.
  670. else
  671. {
  672. $arrButtons = $this->getDC()->arrDCA['buttons'];
  673. if (is_array($arrButtons))
  674. {
  675. foreach ($arrButtons as $arrButton)
  676. {
  677. if (empty($arrButton) || !is_array($arrButton))
  678. {
  679. continue;
  680. }
  681. if (key_exists($arrButton['formkey'], $_POST))
  682. {
  683. $strClass = $arrButton['button_callback'][0];
  684. $strMethod = $arrButton['button_callback'][1];
  685. $this->import($strClass);
  686. $this->$strClass->$strMethod($this->getDC());
  687. break;
  688. }
  689. }
  690. }
  691. if (Input::getInstance()->post('SUBMIT_TYPE') !== 'auto')
  692. {
  693. $this->reload();
  694. }
  695. }
  696. }
  697. return;
  698. case 5:
  699. // Init Vars
  700. $intMode = $this->Input->get('mode');
  701. $intPid = $this->Input->get('pid');
  702. $intId = $this->Input->get('id');
  703. $intChilds = $this->Input->get('childs');
  704. if (strlen($intMode) == 0 || strlen($intPid) == 0 || strlen($intId) == 0)
  705. {
  706. $this->log('Missing parameter for copy in ' . $this->getDC()->getTable(), 'DC_General - Controller - copy()', TL_ERROR);
  707. $this->redirect('contao/main.php?act=error');
  708. }
  709. // Get the join field
  710. $arrJoinCondition = $this->getDC()->getJoinConditions('self');
  711. // Insert the copy
  712. $this->insertCopyModel($intId, $intPid, $intMode, $intChilds, $arrJoinCondition[0]['srcField'], $arrJoinCondition[0]['dstField'], $arrJoinCondition[0]['operation']);
  713. break;
  714. default:
  715. return vsprintf($this->notImplMsg, 'copy - Mode ' . $this->getDC()->arrDCA['list']['sorting']['mode']);
  716. break;
  717. }
  718. // Reset clipboard + redirect
  719. $this->resetClipboard(true);
  720. }
  721. /**
  722. * Create a new entry
  723. */
  724. public function create()
  725. {
  726. // Checks
  727. $this->checkIsWritable();
  728. $this->checkLanguage();
  729. // Load current values
  730. $objCurrentDataProvider = $this->getDC()->getDataProvider();
  731. // Load fields and co
  732. $this->getDC()->loadEditableFields();
  733. $this->getDC()->setWidgetID($this->getDC()->getId());
  734. // Check if we have fields
  735. if (!$this->getDC()->hasEditableFields())
  736. {
  737. $this->redirect($this->getReferer());
  738. }
  739. // Load something
  740. $this->getDC()->preloadTinyMce();
  741. // Load record from data provider
  742. $objDBModel = $objCurrentDataProvider->getEmptyModel();
  743. $this->getDC()->setCurrentModel($objDBModel);
  744. if ($this->getDC()->arrDCA['list']['sorting']['mode'] < 4)
  745. {
  746. // check if the pid id/word is set
  747. if ($this->Input->get('pid'))
  748. {
  749. $objParentDP = $this->objDC->getDataProvider('parent');
  750. $objParent = $objParentDP->fetch($objParentDP->getEmptyConfig()->setId($this->Input->get('pid')));
  751. $this->setParent($objDBModel, $objParent, 'self');
  752. }
  753. }
  754. else if ($this->getDC()->arrDCA['list']['sorting']['mode'] == 4)
  755. {
  756. // check if the pid id/word is set
  757. if ($this->Input->get('pid') == '')
  758. {
  759. $this->log('Missing pid for new entry in ' . $this->getDC()->getTable(), 'DC_General - Controller - create()', TL_ERROR);
  760. $this->redirect('contao/main.php?act=error');
  761. }
  762. $objDBModel->setProperty('pid', $this->Input->get('pid'));
  763. }
  764. else if ($this->getDC()->arrDCA['list']['sorting']['mode'] == 5 && $this->Input->get('mode') != '')
  765. {
  766. /**
  767. * Create in mode 5
  768. *
  769. * <p>
  770. * -= GET Parameter =-<br/>
  771. * act - create <br/>
  772. * after - ID of target element <br/>
  773. * mode - 1 Insert after | 2 Insert into <br/>
  774. * pid - Id of the parent used in list mode 4,5 <br/>
  775. * pdp - Parent Data Provider real name <br/>
  776. * cdp - Current Data Provider real name <br/>
  777. * id - Parent child id used for redirect <br/>
  778. * </p>
  779. */
  780. // Get vars
  781. $mixAfter = $this->Input->get('after');
  782. $intMode = $this->Input->get('mode');
  783. $mixPid = $this->Input->get('pid');
  784. $strPDP = $this->Input->get('pdp');
  785. $strCDP = $this->Input->get('cdp');
  786. $intId = $this->Input->get('id');
  787. // Check basic vars
  788. if (is_null($mixAfter) || empty($intMode) || empty($strCDP))
  789. {
  790. $this->log('Missing parameter for create in ' . $this->getDC()->getTable(), __CLASS__ . ' - ' . __FUNCTION__, TL_ERROR);
  791. $this->redirect('contao/main.php?act=error');
  792. }
  793. // Load current data provider
  794. $objCurrentDataProvider = $this->objDC->getDataProvider($strCDP);
  795. if ($objCurrentDataProvider == null)
  796. {
  797. throw new Exception('Could not load current data provider in ' . __CLASS__ . ' - ' . __FUNCTION__);
  798. }
  799. $objParentDataProvider = null;
  800. if (!empty($strPDP))
  801. {
  802. $objParentDataProvider = $this->objDC->getDataProvider($strPDP);
  803. if ($objParentDataProvider == null)
  804. {
  805. throw new Exception('Could not load parent data provider ' . $strPDP . ' in ' . __CLASS__ . ' - ' . __FUNCTION__);
  806. }
  807. }
  808. // first enforce the parent table conditions, if we have an parent.
  809. if (($strPDP != $strCDP) && $mixPid)
  810. {
  811. // parenting entry is root? we want to become so too.
  812. if ($this->isRootEntry($strPDP, $mixPid))
  813. {
  814. $this->setRoot($objDBModel, $strPDP);
  815. }
  816. else
  817. {
  818. // we have some parent model and can use that one.
  819. $objParentModel = $objParentDataProvider->fetch($objParentDataProvider->getEmptyConfig()->setId($mixPid));
  820. $this->setParent($objDBModel, $objParentModel, $strPDP);
  821. }
  822. // TODO: update sorting here.
  823. }
  824. switch ($this->Input->get('mode'))
  825. {
  826. case 1: // insert after
  827. // we want a new item in $strCDP having an optional parent in $strPDP (with pid item $mixPid) just after $mixAfter (in child tree conditions).
  828. // sadly, with our complex rules an getParent() is IMPOSSIBLE (or in other words way too costly as we would be forced to iterate through all items and check if this item would end up in their child collection).
  829. // therefore we get the child we want to be next of and set all fields to the same values as in the sibling to end up in the same parent.
  830. $objOtherChild = $objCurrentDataProvider->fetch($objCurrentDataProvider->getEmptyConfig()->setId($mixAfter));
  831. $this->getDC()->setSameParent($objDBModel, $objOtherChild, $strCDP);
  832. // TODO: update sorting here.
  833. break;
  834. case 2: // insert into
  835. // we want a new item in $strCDP having an optional parent in $strPDP (with pid item $mixPid) just as child of $mixAfter (in child tree conditions).
  836. // now check if we want to be inserted as root in our own condition - this means either no "after".
  837. if (($mixAfter == 0))
  838. {
  839. $this->setRoot($objDBModel, 'self');
  840. }
  841. else
  842. {
  843. // enforce the child condition from our parent.
  844. $objMyParent = $objCurrentDataProvider->fetch($objCurrentDataProvider->getEmptyConfig()->setId($mixAfter));
  845. $this->setParent($objDBModel, $objMyParent, 'self');
  846. }
  847. // TODO: update sorting here.
  848. break;
  849. default:
  850. $this->log('Unknown create mode for new entry in ' . $this->getDC()->getTable(), 'DC_General - Controller - create()', TL_ERROR);
  851. $this->redirect('contao/main.php?act=error');
  852. break;
  853. }
  854. // Reset clipboard
  855. $this->resetClipboard();
  856. }
  857. // Check if we have a auto submit
  858. $this->getDC()->updateModelFromPOST();
  859. // Check submit
  860. if ($this->getDC()->isSubmitted() == true && !$this->getDC()->isNoReload())
  861. {
  862. try
  863. {
  864. // Get new Position
  865. $strPDP = $this->Input->get('pdp');
  866. $strCDP = $this->Input->get('cdp');
  867. $mixAfter = $this->Input->get('after');
  868. $mixInto = $this->Input->get('into');
  869. $this->getNewPosition($this->objDC->getDataProvider($strPDP), $this->objDC->getDataProvider($strCDP), $this->objDC->getCurrentModel(), $mixAfter, $mixInto, 'create');
  870. if (isset($_POST["save"]))
  871. {
  872. // process input and update changed properties.
  873. if (($objModell = $this->doSave($this->getDC())) !== false)
  874. {
  875. // Callback
  876. $this->getDC()->getCallbackClass()->oncreateCallback($objDBModel->getID(), $objDBModel->getPropertiesAsArray());
  877. // Log
  878. $this->log('A new entry in table "' . $this->getDC()->getTable() . '" has been created (ID: ' . $objModell->getID() . ')', 'DC_General - Controller - create()', TL_GENERAL);
  879. // Redirect
  880. $this->redirect($this->addToUrl("id=" . $objDBModel->getID() . "&amp;act=edit"));
  881. }
  882. }
  883. else if (isset($_POST["saveNclose"]))
  884. {
  885. // process input and update changed properties.
  886. if (($objModell = $this->doSave($this->getDC())) !== false)
  887. {
  888. setcookie('BE_PAGE_OFFSET', 0, 0, '/');
  889. $_SESSION['TL_INFO'] = '';
  890. $_SESSION['TL_ERROR'] = '';
  891. $_SESSION['TL_CONFIRM'] = '';
  892. // Callback
  893. $this->getDC()->getCallbackClass()->oncreateCallback($objDBModel->getID(), $objDBModel->getPropertiesAsArray());
  894. // Log
  895. $this->log('A new entry in table "' . $this->getDC()->getTable() . '" has been created (ID: ' . $objModell->getID() . ')', 'DC_General - Controller - create()', TL_GENERAL);
  896. // Redirect
  897. $this->redirect($this->getReferer());
  898. }
  899. }
  900. else
  901. {
  902. $arrButtons = $this->getDC()->arrDCA['buttons'];
  903. if (is_array($arrButtons))
  904. {
  905. foreach ($arrButtons as $arrButton)
  906. {
  907. if (empty($arrButton) || !is_array($arrButton))
  908. {
  909. continue;
  910. }
  911. if (key_exists($arrButton['formkey'], $_POST))
  912. {
  913. $strClass = $arrButton['button_callback'][0];
  914. $strMethod = $arrButton['button_callback'][1];
  915. $this->import($strClass);
  916. $this->$strClass->$strMethod($this->getDC());
  917. break;
  918. }
  919. }
  920. }
  921. }
  922. }
  923. catch (Exception $exc)
  924. {
  925. $_SESSION['TL_ERROR'][] = sprintf('Exception: %s in file %s on line %s', $exc->getMessage(), $exc->getFile(), $exc->getLine());
  926. }
  927. }
  928. }
  929. /**
  930. * Recurse through all childs in mode 5 and return their Ids.
  931. */
  932. protected function fetchMode5ChildsOf($objParentModel, $blnRecurse = true)
  933. {
  934. $arrJoinCondition = $this->getDC()->getChildCondition($objParentModel, 'self');
  935. // Build filter
  936. $objChildConfig = $this->getDC()->getDataProvider()->getEmptyConfig();
  937. $objChildConfig->setFilter($arrJoinCondition);
  938. // Get child collection
  939. $objChildCollection = $this->getDC()->getDataProvider()->fetchAll($objChildConfig);
  940. $arrIDs = array();
  941. foreach ($objChildCollection as $objChildModel)
  942. {
  943. $arrIDs[] = $objChildModel->getID();
  944. if ($blnRecurse)
  945. {
  946. $arrIDs = array_merge($arrIDs, $this->fetchMode5ChildsOf($objChildModel, $blnRecurse));
  947. }
  948. }
  949. return $arrIDs;
  950. }
  951. public function delete()
  952. {
  953. // Load current values
  954. $objCurrentDataProvider = $this->getDC()->getDataProvider();
  955. // Init some vars
  956. $intRecordID = $this->getDC()->getId();
  957. // Check if we have a id
  958. if (strlen($intRecordID) == 0)
  959. {
  960. $this->reload();
  961. }
  962. // Check if is it allowed to delete a record
  963. if ($this->getDC()->arrDCA['config']['notDeletable'])
  964. {
  965. $this->log('Table "' . $this->getDC()->getTable() . '" is not deletable', 'DC_General - Controller - delete()', TL_ERROR);
  966. $this->redirect('contao/main.php?act=error');
  967. }
  968. // Callback
  969. $this->getDC()->setCurrentModel($objCurrentDataProvider->fetch($objCurrentDataProvider->getEmptyConfig()->setId($intRecordID)));
  970. $this->getDC()->getCallbackClass()->ondeleteCallback();
  971. $arrDelIDs = array();
  972. // Delete record
  973. switch ($this->getDC()->arrDCA['list']['sorting']['mode'])
  974. {
  975. case 0:
  976. case 1:
  977. case 2:
  978. case 3:
  979. case 4:
  980. $arrDelIDs = array();
  981. $arrDelIDs[] = $intRecordID;
  982. break;
  983. case 5:
  984. $arrDelIDs = $this->fetchMode5ChildsOf($this->getDC()->getCurrentModel(), $blnRecurse = true);
  985. $arrDelIDs[] = $intRecordID;
  986. break;
  987. }
  988. // Delete all entries
  989. foreach ($arrDelIDs as $intId)
  990. {
  991. $this->getDC()->getDataProvider()->delete($intId);
  992. // Add a log entry unless we are deleting from tl_log itself
  993. if ($this->getDC()->getTable() != 'tl_log')
  994. {
  995. $this->log('DELETE FROM ' . $this->getDC()->getTable() . ' WHERE id=' . $intId, 'DC_General - Controller - delete()', TL_GENERAL);
  996. }
  997. }
  998. $this->redirect($this->getReferer());
  999. }
  1000. public function edit()
  1001. {
  1002. // Load some vars
  1003. $objCurrentDataProvider = $this->getDC()->getDataProvider();
  1004. // Check
  1005. $this->checkIsWritable();
  1006. $this->checkLanguage($this->getDC());
  1007. // Load an older Version
  1008. if (strlen($this->Input->post("version")) != 0 && $this->getDC()->isVersionSubmit())
  1009. {
  1010. $this->loadVersion($this->getDC()->getId(), $this->Input->post("version"));
  1011. }
  1012. // Load fields and co
  1013. $this->getDC()->loadEditableFields();
  1014. $this->getDC()->setWidgetID($this->getDC()->getId());
  1015. // Check if we have fields
  1016. if (!$this->getDC()->hasEditableFields())
  1017. {
  1018. $this->redirect($this->getReferer());
  1019. }
  1020. // Load something
  1021. $this->getDC()->preloadTinyMce();
  1022. // Load record from data provider
  1023. $objDBModel = $objCurrentDataProvider->fetch($objCurrentDataProvider->getEmptyConfig()->setId($this->getDC()->getId()));
  1024. if ($objDBModel == null)
  1025. {
  1026. $objDBModel = $objCurrentDataProvider->getEmptyModel();
  1027. }
  1028. $this->getDC()->setCurrentModel($objDBModel);
  1029. // Check if we have a auto submit
  1030. $this->getDC()->updateModelFromPOST();
  1031. // Check submit
  1032. if ($this->getDC()->isSubmitted() == true)
  1033. {
  1034. if (isset($_POST["save"]))
  1035. {
  1036. // process input and update changed properties.
  1037. if ($this->doSave($this->getDC()) !== false)
  1038. {
  1039. $this->reload();
  1040. }
  1041. }
  1042. else if (isset($_POST["saveNclose"]))
  1043. {
  1044. // process input and update changed properties.
  1045. if ($this->doSave($this->getDC()) !== false)
  1046. {
  1047. setcookie('BE_PAGE_OFFSET', 0, 0, '/');
  1048. $_SESSION['TL_INFO'] = '';
  1049. $_SESSION['TL_ERROR'] = '';
  1050. $_SESSION['TL_CONFIRM'] = '';
  1051. $this->redirect($this->getReferer());
  1052. }
  1053. }
  1054. // Maybe Callbacks ? Yes, this is the first version of an simple
  1055. // button callback system like dc_memory.
  1056. else
  1057. {
  1058. $arrButtons = $this->getDC()->arrDCA['buttons'];
  1059. if (is_array($arrButtons))
  1060. {
  1061. foreach ($arrButtons as $arrButton)
  1062. {
  1063. if (empty($arrButton) || !is_array($arrButton))
  1064. {
  1065. continue;
  1066. }
  1067. if (key_exists($arrButton['formkey'], $_POST))
  1068. {
  1069. $strClass = $arrButton['button_callback'][0];
  1070. $strMethod = $arrButton['button_callback'][1];
  1071. $this->import($strClass);
  1072. $this->$strClass->$strMethod($this->getDC());
  1073. break;
  1074. }
  1075. }
  1076. }
  1077. if (Input::getInstance()->post('SUBMIT_TYPE') !== 'auto')
  1078. {
  1079. $this->reload();
  1080. }
  1081. }
  1082. }
  1083. }
  1084. /**
  1085. * Show informations about one entry
  1086. */
  1087. public function show()
  1088. {
  1089. // Load check multi language
  1090. $objCurrentDataProvider = $this->getDC()->getDataProvider();
  1091. // Check
  1092. $this->checkLanguage($this->getDC());
  1093. // Load record from data provider
  1094. $objDBModel = $objCurrentDataProvider->fetch($objCurrentDataProvider->getEmptyConfig()->setId($this->getDC()->getId()));
  1095. if ($objDBModel == null)
  1096. {
  1097. $this->log('Could not find ID ' . $this->getDC()->getId() . ' in Table ' . $this->getDC()->getTable() . '.', 'DC_General show()', TL_ERROR);
  1098. $this->redirect('contao/main.php?act=error');
  1099. }
  1100. $this->getDC()->setCurrentModel($objDBModel);
  1101. }
  1102. /**
  1103. * Show all entries from a table
  1104. *
  1105. * @return void | String if error
  1106. */
  1107. public function showAll()
  1108. {
  1109. // Checks
  1110. $this->checkClipboard();
  1111. $this->checkPanelSubmit();
  1112. // Setup
  1113. $this->getDC()->setButtonId('tl_buttons');
  1114. $this->establishSorting();
  1115. $this->getFilter();
  1116. $this->generatePanelFilter('set');
  1117. // Switch mode
  1118. switch ($this->getDC()->arrDCA['list']['sorting']['mode'])
  1119. {
  1120. case 0:
  1121. case 1:
  1122. case 2:
  1123. case 3:
  1124. $this->viewList();
  1125. break;
  1126. case 4:
  1127. $this->viewParent();
  1128. break;
  1129. case 5:
  1130. $this->treeViewM5();
  1131. break;
  1132. default:
  1133. return vsprintf($this->notImplMsg, 'showAll - Mode ' . $this->getDC()->arrDCA['list']['sorting']['mode']);
  1134. break;
  1135. }
  1136. // keep panel after real view compilation, as in there the limits etc will get compiled.
  1137. $this->panel($this->getDC());
  1138. }
  1139. /* /////////////////////////////////////////////////////////////////////
  1140. * ---------------------------------------------------------------------
  1141. * AJAX
  1142. * ---------------------------------------------------------------------
  1143. * ////////////////////////////////////////////////////////////////// */
  1144. public function ajaxTreeView($intID, $intLevel)
  1145. {
  1146. // Load current informations
  1147. $objCurrentDataProvider = $this->getDC()->getDataProvider();
  1148. $strToggleID = $this->getDC()->getTable() . '_tree';
  1149. $arrToggle = $this->Session->get($strToggleID);
  1150. if (!is_array($arrToggle))
  1151. {
  1152. $arrToggle = array();
  1153. }
  1154. $arrToggle[$intID] = 1;
  1155. $this->Session->set($strToggleID, $arrToggle);
  1156. // Init some vars
  1157. $objTableTreeData = $objCurrentDataProvider->getEmptyCollection();
  1158. $objRootConfig = $objCurrentDataProvider->getEmptyConfig();
  1159. $objRootConfig->setId($intID);
  1160. $objModel = $objCurrentDataProvider->fetch($objRootConfig);
  1161. $this->treeWalkModel($objModel, $intLevel, $arrToggle, array('self'));
  1162. foreach ($objModel->getMeta(DCGE::TREE_VIEW_CHILD_COLLECTION) as $objCollection)
  1163. {
  1164. foreach ($objCollection as $objSubModel)
  1165. {
  1166. $objTableTreeData->add($objSubModel);
  1167. }
  1168. }
  1169. $this->getDC()->setCurrentCollecion($objTableTreeData);
  1170. }
  1171. /**
  1172. * Loads the current model from the data provider and overrides the selector
  1173. *
  1174. * @param type $strSelector the name of the checkbox toggling the palette.
  1175. */
  1176. public function generateAjaxPalette($strSelector)
  1177. {
  1178. // Check
  1179. $this->checkIsWritable();
  1180. $this->checkLanguage($this->getDC());
  1181. // Load fields and co
  1182. $this->getDC()->loadEditableFields();
  1183. $this->getDC()->setWidgetID($this->getDC()->getId());
  1184. // Check if we have fields
  1185. if (!$this->getDC()->hasEditableFields())
  1186. {
  1187. $this->redirect($this->getReferer());
  1188. }
  1189. // Load something
  1190. $this->getDC()->preloadTinyMce();
  1191. $objDataProvider = $this->getDC()->getDataProvider();
  1192. // Load record from data provider
  1193. $objDBModel = $objDataProvider->fetch($objDataProvider->getEmptyConfig()->setId($this->getDC()->getId()));
  1194. if ($objDBModel == null)
  1195. {
  1196. $objDBModel = $objDataProvider->getEmptyModel();
  1197. }
  1198. $this->getDC()->setCurrentModel($objDBModel);
  1199. // override the setting from POST now.
  1200. $objDBModel->setProperty($strSelector, intval($this->Input->post('state')));
  1201. }
  1202. /* /////////////////////////////////////////////////////////////////////
  1203. * ---------------------------------------------------------------------
  1204. * Edit modes
  1205. * ---------------------------------------------------------------------
  1206. * ////////////////////////////////////////////////////////////////// */
  1207. /**
  1208. * Load an older version
  1209. */
  1210. protected function loadVersion($intID, $mixVersion)
  1211. {
  1212. $objCurrentDataProvider = $this->getDC()->getDataProvider();
  1213. // Load record from version
  1214. $objVersionModel = $objCurrentDataProvider->getVersion($intID, $mixVersion);
  1215. // Redirect if there is no record with the given ID
  1216. if ($objVersionModel == null)
  1217. {
  1218. $this->log('Could not load record ID ' . $intID . ' of table "' . $this->getDC()->getTable() . '"', 'DC_General - Controller - edit()', TL_ERROR);
  1219. $this->redirect('contao/main.php?act=error');
  1220. }
  1221. $objCurrentDataProvider->save($objVersionModel);
  1222. $objCurrentDataProvider->setVersionActive($intID, $mixVersion);
  1223. // Callback onrestoreCallback
  1224. $arrData = $objVersionModel->getPropertiesAsArray();
  1225. $arrData["id"] = $objVersionModel->getID();
  1226. $this->getDC()->getCallbackClass()->onrestoreCallback($intID, $this->getDC()->getTable(), $arrData, $mixVersion);
  1227. $this->log(sprintf('Version %s of record ID %s (table %s) has been restored', $this->Input->post('version'), $this->getDC()->getId(), $this->getDC()->getTable()), 'DC_General - Controller - edit()', TL_GENERAL);
  1228. // Reload page with new recored
  1229. $this->reload();
  1230. }
  1231. /**
  1232. * Perform low level saving of the current model in a DC.
  1233. * NOTE: the model will get populated with the new values within this function.
  1234. * Therefore the current submitted data will be stored within the model but only on
  1235. * success also be saved into the DB.
  1236. *
  1237. * @return bool|InterfaceGeneralModel Model if the save operation was successful or unnecessary, false otherwise.
  1238. */
  1239. protected function doSave()
  1240. {
  1241. $objDBModel = $this->getDC()->getCurrentModel();
  1242. // Check if table is closed
  1243. if ($this->getDC()->arrDCA['config']['closed'] && !($objDBModel->getID()))
  1244. {
  1245. // TODO show alarm message
  1246. $this->redirect($this->getReferer());
  1247. }
  1248. // if we may not store the value, we keep the changes
  1249. // in the current model and return (DO NOT SAVE!).
  1250. if ($this->getDC()->isNoReload() == true)
  1251. {
  1252. return false;
  1253. }
  1254. // Callback
  1255. $this->getDC()->getCallbackClass()->onsubmitCallback();
  1256. // Refresh timestamp
  1257. if ($this->getDC()->getDataProvider()->fieldExists("tstamp") == true)
  1258. {
  1259. $objDBModel->setProperty("tstamp", time());
  1260. }
  1261. // Callback
  1262. $this->getDC()->getCallbackClass()->onsaveCallback($objDBModel);
  1263. // Check if we have a field with eval->alwaysSave
  1264. foreach ($this->objDC->getFieldList() as $arrFieldSettings)
  1265. {
  1266. if($arrFieldSettings['eval']['alwaysSave'] == true)
  1267. {
  1268. $objDBModel->setMeta(DCGE::MODEL_IS_CHANGED, true);
  1269. break;
  1270. }
  1271. }
  1272. // $this->getNewPosition($objDBModel, 'create', null, false);
  1273. // everything went ok, now save the new record
  1274. if (!$objDBModel->getMeta(DCGE::MODEL_IS_CHANGED) && ($objDBModel->getID()))
  1275. {
  1276. return $objDBModel;
  1277. }
  1278. $this->getDC()->getDataProvider()->save($objDBModel);
  1279. // Check if versioning is enabled
  1280. if (isset($this->getDC()->arrDCA['config']['enableVersioning']) && $this->getDC()->arrDCA['config']['enableVersioning'] == true)
  1281. {
  1282. // Compare version and current record
  1283. $mixCurrentVersion = $this->getDC()->getDataProvider()->getActiveVersion($objDBModel->getID());
  1284. if ($mixCurrentVersion != null)
  1285. {
  1286. $mixCurrentVersion = $this->getDC()->getDataProvider()->getVersion($objDBModel->getID(), $mixCurrentVersion);
  1287. if ($this->getDC()->getDataProvider()->sameModels($objDBModel, $mixCurrentVersion) == false)
  1288. {
  1289. // TODO: FE|BE switch
  1290. $this->import('BackendUser', 'User');
  1291. $this->getDC()->getDataProvider()->saveVersion($objDBModel, $this->User->username);
  1292. }
  1293. }
  1294. else
  1295. {
  1296. // TODO: FE|BE switch
  1297. $this->import('BackendUser', 'User');
  1298. $this->getDC()->getDataProvider()->saveVersion($objDBModel, $this->User->username);
  1299. }
  1300. }
  1301. // Return the current model
  1302. return $objDBModel;
  1303. }
  1304. /**
  1305. * Calculate the new position of an element
  1306. *
  1307. * Warning this function needs the cdp (current data provider).
  1308. * Warning this function needs the pdp (parent data provider).
  1309. *
  1310. * Based on backbone87 PR - "creating items in parent modes generates sorting value of 0"
  1311. *
  1312. * @param InterfaceGeneralData $objCDP - Current data provider
  1313. * @param InterfaceGeneralData $objPDP - Parent data provider
  1314. * @param InterfaceGeneralModel $objDBModel - Model of element which should moved
  1315. * @param mixed $mixAfter - Target element
  1316. * @param string $strMode - Mode like cut | create and so on
  1317. * @param integer $intInsertMode - Insert Mode => 1 After | 2 Into
  1318. * @param mixed $mixParentID - Parent ID of table or element
  1319. *
  1320. * @return void
  1321. */
  1322. protected function getNewPosition($objCDP, $objPDP, $objDBModel, $mixAfter, $mixInto, $strMode, $mixParentID = null, $intInsertMode = null, $blnWithoutReorder = false)
  1323. {
  1324. // Check if we have a sorting field, if not skip here.
  1325. if (!$objCDP->fieldExists('sorting'))
  1326. {
  1327. return;
  1328. }
  1329. // Load default DataProvider.
  1330. if (is_null($objCDP))
  1331. {
  1332. $objCDP = $this->getDC()->getDataProvider();
  1333. }
  1334. if ($mixAfter === DCGE::INSERT_AFTER_START)
  1335. {
  1336. $mixAfter = 0;
  1337. }
  1338. // Search for the highest sorting. Default - Add to end off all.
  1339. // ToDo: We have to check the child <=> parent condition . To get all sortings for one level.
  1340. // If we get a after 0, add to top.
  1341. if ($mixAfter === 0) {
  1342. // Build filter for conditions
  1343. $arrFilter = array();
  1344. if (in_array($this->getDC()->arrDCA['list']['sorting']['mode'], array(4, 5, 6)))
  1345. {
  1346. $arrConditions = $this->objDC->getRootConditions($objCDP->getEmptyModel()->getProviderName());
  1347. if ($arrConditions)
  1348. {
  1349. foreach ($arrConditions as $arrCondition)
  1350. {
  1351. if (key_exists('remote', $arrCondition))
  1352. {
  1353. $arrFilter[] = array(
  1354. 'value' => Input::getInstance()->get($arrCondition['remote']),
  1355. 'property' => $arrCondition['property'],
  1356. 'operation' => $arrCondition['operation']
  1357. );
  1358. }
  1359. else if (key_exists('remote_value', $arrCondition))
  1360. {
  1361. $arrFilter[] = array(
  1362. 'value' => Input::getInstance()->get($arrCondition['remote_value']),
  1363. 'property' => $arrCondition['property'],
  1364. 'operation' => $arrCondition['operation']
  1365. );
  1366. }
  1367. else
  1368. {
  1369. $arrFilter[] = array(
  1370. 'value' => $arrCondition['value'],
  1371. 'property' => $arrCondition['property'],
  1372. 'operation' => $arrCondition['operation']
  1373. );
  1374. }
  1375. }
  1376. }
  1377. }
  1378. // Build config
  1379. $objConfig = $objCDP->getEmptyConfig();
  1380. $objConfig->setFields(array('sorting'));
  1381. $objConfig->setSorting(array('sorting' => DCGE::MODEL_SORTING_ASC));
  1382. $objConfig->setAmount(1);
  1383. $objConfig->setFilter($arrFilter);
  1384. $objCollection = $objCDP->fetchAll($objConfig);
  1385. if ($objCollection->length())
  1386. {
  1387. $intLowestSorting = $objCollection->get(0)->getProperty('sorting');
  1388. $intNextSorting = round($intLowestSorting / 2);
  1389. }
  1390. else
  1391. {
  1392. $intNextSorting = 256;
  1393. }
  1394. // Check if we have a valide sorting.
  1395. if (($intLowestSorting < 2 || $intNextSorting <= 2) && !$blnWithoutReorder)
  1396. {
  1397. // ToDo: Add child <=> parent config.
  1398. $objConfig = $objCDP->getEmptyConfig();
  1399. $objConfig->setFilter($arrFilter);
  1400. $this->reorderSorting($objConfig);
  1401. $this->getNewPosition($objCDP, $objPDP, $objDBModel, $mixAfter, $mixInto, $strMode, $mixParentID, $intInsertMode, true);
  1402. return;
  1403. }
  1404. // Fallback to valid sorting.
  1405. else if ($intNextSorting <= 2)
  1406. {
  1407. $intNextSorting = 256;
  1408. }
  1409. $objDBModel->setProperty('sorting', $intNextSorting);
  1410. }
  1411. // If we get a after, search for the right value.
  1412. else if (!empty($mixAfter))
  1413. {
  1414. // Init some vars.
  1415. $intAfterSorting = 0;
  1416. $intNextSorting = 0;
  1417. // Get "after" sorting value value.
  1418. $objAfterConfig = $objCDP->getEmptyConfig();
  1419. $objAfterConfig->setAmount(1);
  1420. $objAfterConfig->setFilter(array(array(
  1421. 'value' => $mixAfter,
  1422. 'property' => 'id',
  1423. 'operation' => '='
  1424. )));
  1425. $objAfterCollection = $objCDP->fetchAll($objAfterConfig);
  1426. if ($objAfterCollection->length())
  1427. {
  1428. $intAfterSorting = $objAfterCollection->get(0)->getProperty('sorting');
  1429. }
  1430. // Get "next" sorting value value.
  1431. $objNextConfig = $objCDP->getEmptyConfig();
  1432. $objNextConfig->setFields(array('sorting'));
  1433. $objNextConfig->setAmount(1);
  1434. $objNextConfig->setSorting(array('sorting' => DCGE::MODEL_SORTING_ASC));
  1435. $arrFilterSettings = array(array(
  1436. 'value' => $intAfterSorting,
  1437. 'property' => 'sorting',
  1438. 'operation' => '>'
  1439. ));
  1440. $arrFilterChildCondition = array();
  1441. // If we have mode 4, 5, 6 build the child <=> parent condition.
  1442. if (in_array($this->getDC()->arrDCA['list']['sorting']['mode'], array(4, 5, 6)))
  1443. {
  1444. $arrChildCondition = $this->objDC->getParentChildCondition($objAfterCollection->get(0), $objCDP->getEmptyModel()->getProviderName());
  1445. $arrChildCondition = $arrChildCondition['setOn'];
  1446. if ($arrChildCondition)
  1447. {
  1448. foreach ($arrChildCondition as $arrOperation)
  1449. {
  1450. if (array_key_exists('to_field', $arrOperation))
  1451. {
  1452. $arrFilterChildCondition[] = array(
  1453. 'value' => $objAfterCollection->get(0)->getProperty($arrOperation['to_field']),
  1454. 'property' => $arrOperation['to_field'],
  1455. 'operation' => '='
  1456. );
  1457. }
  1458. else
  1459. {
  1460. $arrFilterChildCondition[] = array(
  1461. 'value' => $arrOperation['property'],
  1462. 'property' => $arrOperation['to_field'],
  1463. 'operation' => '='
  1464. );
  1465. }
  1466. }
  1467. }
  1468. }
  1469. $objNextConfig->setFilter(array_merge($arrFilterSettings, $arrFilterChildCondition));
  1470. $objNextCollection = $objCDP->fetchAll($objNextConfig);
  1471. if ($objNextCollection->length())
  1472. {
  1473. $intNextSorting = $objNextCollection->get(0)->getProperty('sorting');
  1474. }
  1475. else
  1476. {
  1477. $intNextSorting = $intAfterSorting + (2 * 256);
  1478. }
  1479. // Check if we have a valide sorting.
  1480. if (($intAfterSorting < 2 || $intNextSorting < 2 || round(($intNextSorting - $intAfterSorting) / 2) <= 2) && !$blnWithoutReorder)
  1481. {
  1482. // ToDo: Add child <=> parent config.
  1483. $objConfig = $objCDP->getEmptyConfig();
  1484. $objConfig->setFilter($arrFilterChildCondition);
  1485. $this->reorderSorting($objConfig);
  1486. $this->getNewPosition($objCDP, $objPDP, $objDBModel, $mixAfter, $mixInto, $strMode, $mixParentID, $intInsertMode, true);
  1487. return;
  1488. }
  1489. // Fallback to valid sorting.
  1490. else if ($intNextSorting <= 2)
  1491. {
  1492. $intNextSorting = 256;
  1493. }
  1494. // Get sorting between these two values.
  1495. $intNewSorting = $intAfterSorting + round(($intNextSorting - $intAfterSorting) / 2);
  1496. // Save in model.
  1497. $objDBModel->setProperty('sorting', $intNewSorting);
  1498. }
  1499. // Else use the highest value. Fallback.
  1500. else
  1501. {
  1502. $objConfig = $objCDP->getEmptyConfig();
  1503. $objConfig->setFields(array('sorting'));
  1504. $objConfig->setSorting(array('sorting' => DCGE::MODEL_SORTING_DESC));
  1505. $objConfig->setAmount(1);
  1506. $objCollection = $objCDP->fetchAll($objConfig);
  1507. $intHighestSorting = 0;
  1508. if ($objCollection->length())
  1509. {
  1510. $intHighestSorting = $objCollection->get(0)->getProperty('sorting') + 256;
  1511. }
  1512. $objDBModel->setProperty('sorting', $intHighestSorting);
  1513. }
  1514. }
  1515. /**
  1516. * Reorder all sortings for one table.
  1517. *
  1518. * @param InterfaceGeneralDataConfig $objConfig
  1519. *
  1520. * @return void
  1521. */
  1522. protected function reorderSorting($objConfig)
  1523. {
  1524. $objCurrentDataProvider = $this->getDC()->getDataProvider();
  1525. if ($objConfig == null)
  1526. {
  1527. $objConfig = $objCurrentDataProvider->getEmptyConfig();
  1528. }
  1529. // Search for the lowest sorting
  1530. $objConfig->setFields(array('sorting'));
  1531. $objConfig->setSorting(array('sorting' => DCGE::MODEL_SORTING_ASC, 'id' => DCGE::MODEL_SORTING_ASC));
  1532. $arrCollection = $objCurrentDataProvider->fetchAll($objConfig);
  1533. $i = 1;
  1534. $intCount = 256;
  1535. foreach ($arrCollection as $value)
  1536. {
  1537. $value->setProperty('sorting', $intCount * $i++);
  1538. $objCurrentDataProvider->save($value);
  1539. }
  1540. }
  1541. /* /////////////////////////////////////////////////////////////////////
  1542. * ---------------------------------------------------------------------
  1543. * Copy modes
  1544. * ---------------------------------------------------------------------
  1545. * ////////////////////////////////////////////////////////////////// */
  1546. /**
  1547. * @todo Make it fine
  1548. *
  1549. * @param type $intSrcID
  1550. * @param type $intDstID
  1551. * @param type $intMode
  1552. * @param type $blnChilds
  1553. * @param type $strDstField
  1554. * @param type $strSrcField
  1555. * @param type $strOperation
  1556. */
  1557. protected function insertCopyModel($intIdSource, $intIdTarget, $intMode, $blnChilds, $strFieldId, $strFieldPid, $strOperation)
  1558. {
  1559. // Get dataprovider
  1560. $objDataProvider = $this->getDC()->getDataProvider();
  1561. // Load the source model
  1562. $objSrcModel = $objDataProvider->fetch($objDataProvider->getEmptyConfig()->setId($intIdSource));
  1563. // Create a empty model for the copy
  1564. $objCopyModel = clone $objSrcModel;
  1565. // // Load all params
  1566. // $arrProperties = $objSrcModel->getPropertiesAsArray();
  1567. //
  1568. // // Clear some fields, see dca
  1569. // foreach ($arrProperties as $key => $value)
  1570. // {
  1571. // // If the field is not known, remove it
  1572. // if (!key_exists($key, $this->getDC()->arrDCA['fields']))
  1573. // {
  1574. // continue;
  1575. // }
  1576. //
  1577. // // Check doNotCopy
  1578. // if ($this->getDC()->arrDCA['fields'][$key]['eval']['doNotCopy'] == true)
  1579. // {
  1580. // unset($arrProperties[$key]);
  1581. // continue;
  1582. // }
  1583. //
  1584. // // Check fallback
  1585. // if ($this->getDC()->arrDCA['fields'][$key]['eval']['fallback'] == true)
  1586. // {
  1587. // $objDataProvider->resetFallback($key);
  1588. // }
  1589. //
  1590. // // Check unique
  1591. // if ($this->getDC()->arrDCA['fields'][$key]['eval']['unique'] == true && $objDataProvider->isUniqueValue($key, $value))
  1592. // {
  1593. // throw new Exception(vsprintf($GLOBALS['TL_LANG']['ERR']['unique'], $key));
  1594. // }
  1595. // }
  1596. //
  1597. // // Add the properties to the empty model
  1598. // $objCopyModel->setPropertiesAsArray($arrProperties);
  1599. $intListMode = $this->getDC()->arrDCA['list']['sorting']['mode'];
  1600. //Insert After => Get the parent from he target id
  1601. if (in_array($intListMode, array(0, 1, 2, 3)))
  1602. {
  1603. // ToDo: reset sorting for new entry
  1604. }
  1605. //Insert After => Get the parent from he target id
  1606. else if (in_array($intListMode, array(5)) && $intMode == 1)
  1607. {
  1608. $this->setParent($objCopyModel, $this->getParent('self', null, $intIdTarget), 'self');
  1609. }
  1610. // Insert Into => use the pid
  1611. else if (in_array($intListMode, array(5)) && $intMode == 2)
  1612. {
  1613. if ($this->isRootEntry('self', $intIdTarget))
  1614. {
  1615. $this->setRoot($objCopyModel, 'self');
  1616. }
  1617. else
  1618. {
  1619. $objParentConfig = $this->getDC()->getDataProvider()->getEmptyConfig();
  1620. $objParentConfig->setId($intIdTarget);
  1621. $objParentModel = $this->getDC()->getDataProvider()->fetch($objParentConfig);
  1622. $this->setParent($objCopyModel, $objParentModel, 'self');
  1623. }
  1624. }
  1625. else
  1626. {
  1627. $this->log('Unknown create mode for copy in ' . $this->getDC()->getTable(), 'DC_General - Controller - copy()', TL_ERROR);
  1628. $this->redirect('contao/main.php?act=error');
  1629. }
  1630. $objDataProvider->save($objCopyModel);
  1631. $this->arrInsertIDs[$objCopyModel->getID()] = true;
  1632. if ($blnChilds == true)
  1633. {
  1634. $strFilter = $strFieldPid . $strOperation . $objSrcModel->getProperty($strFieldId);
  1635. $objChildConfig = $objDataProvider->getEmptyConfig()->setFilter(array($strFilter));
  1636. $objChildCollection = $objDataProvider->fetchAll($objChildConfig);
  1637. foreach ($objChildCollection as $key => $value)
  1638. {
  1639. if (key_exists($value->getID(), $this->arrInsertIDs))
  1640. {
  1641. continue;
  1642. }
  1643. $this->insertCopyModel($value->getID(), $objCopyModel->getID(), 2, $blnChilds, $strFieldId, $strFieldPid, $strOperation);
  1644. }
  1645. }
  1646. }
  1647. /* /////////////////////////////////////////////////////////////////////
  1648. * ---------------------------------------------------------------------
  1649. * showAll Modis
  1650. * ---------------------------------------------------------------------
  1651. * ////////////////////////////////////////////////////////////////// */
  1652. /**
  1653. * Conrtorller funktion for Mode 0,1,2,3
  1654. *
  1655. * @todo set global current in DC_General
  1656. * @todo $strTable is unknown
  1657. */
  1658. protected function viewList()
  1659. {
  1660. // Setup
  1661. $objCurrentDataProvider = $this->getDC()->getDataProvider();
  1662. $objParentDataProvider = $this->getDC()->getDataProvider('parent');
  1663. $showFields = $this->getDC()->arrDCA['list']['label']['fields'];
  1664. $arrLimit = $this->calculateLimit();
  1665. // Load record from current data provider
  1666. $objConfig = $objCurrentDataProvider->getEmptyConfig()
  1667. ->setStart($arrLimit[0])
  1668. ->setAmount($arrLimit[1])
  1669. ->setFilter($this->getFilter())
  1670. ->setSorting(array($this->getDC()->getFirstSorting() => $this->getDC()->getFirstSortingOrder()));
  1671. $objCollection = $objCurrentDataProvider->fetchAll($objConfig);
  1672. // TODO: set global current in DC_General
  1673. /* $this->current[] = $objModelRow->getProperty('id'); */
  1674. // foreach ($objCollection as $objModel)
  1675. // {
  1676. //
  1677. // }
  1678. //
  1679. // Rename each pid to its label and resort the result (sort by parent table)
  1680. if ($this->getDC()->arrDCA['list']['sorting']['mode'] == 3)
  1681. {
  1682. $this->getDC()->setFirstSorting('pid');
  1683. foreach ($objCollection as $objModel)
  1684. {
  1685. $objFieldConfig = $objParentDataProvider->getEmptyConfig()
  1686. ->setId($objModel->getID());
  1687. $objFieldModel = $objParentDataProvider->fetch($objFieldConfig);
  1688. $objModel->setProperty('pid', $objFieldModel->getProperty($showFields[0]));
  1689. }
  1690. $this->arrColSort = array(
  1691. 'field' => 'pid',
  1692. 'reverse' => false
  1693. );
  1694. $objCollection->sort(array($this, 'sortCollection'));
  1695. }
  1696. if (is_array($showFields))
  1697. {
  1698. // Label
  1699. foreach ($showFields as $v)
  1700. {
  1701. // Decrypt each value
  1702. if ($this->getDC()->arrDCA['fields'][$v]['eval']['encrypt'])
  1703. {
  1704. foreach ($objCollection as $objModel)
  1705. {
  1706. $mixValue = $objModel->getProperty($v);
  1707. $mixValue = deserialize($mixValue);
  1708. $mixValue = $this->objEncrypt->decrypt($mixValue);
  1709. $objModel->setProperty($v, $mixValue);
  1710. }
  1711. }
  1712. // ToDo: $strTable is unknown
  1713. // if (strpos($v, ':') !== false)
  1714. // {
  1715. // list($strKey, $strTable) = explode(':', $v);
  1716. // list($strTable, $strField) = explode('.', $strTable);
  1717. //
  1718. //
  1719. // $objModel = $this->getDC()->getDataProvider($strTable)->fetch(
  1720. // $this->getDC()->getDataProvider()->getEmptyConfig()
  1721. // ->setId($row[$strKey])
  1722. // ->setFields(array($strField))
  1723. // );
  1724. //
  1725. // $objModelRow->setMeta(DCGE::MODEL_LABEL_ARGS, (($objModel->hasProperties()) ? $objModel->getProperty($strField) : ''));
  1726. // }
  1727. }
  1728. }
  1729. $this->getDC()->setCurrentCollecion($objCollection);
  1730. }
  1731. protected function treeViewM5()
  1732. {
  1733. // Load some infromations from DCA
  1734. $arrNeededFields = $this->calcNeededFields($this->getDC()->getDataProvider()->getEmptyModel(), $this->getDC()->getTable());
  1735. $arrTitlePattern = $this->calcLabelPattern($this->getDC()->getTable());
  1736. $arrRootEntries = $this->getDC()->getRootConditions($this->getDC()->getTable());
  1737. $arrLimit = $this->calculateLimit();
  1738. // TODO: @CS we need this to be srctable_dsttable_tree for interoperability, for mode5 this will be self_self_tree but with strTable.
  1739. $strToggleID = $this->getDC()->getTable() . '_tree';
  1740. $arrToggle = $this->Session->get($strToggleID);
  1741. if (!is_array($arrToggle))
  1742. {
  1743. $arrToggle = array();
  1744. }
  1745. // Check if the open/close all is active
  1746. if ($this->blnShowAllEntries == true)
  1747. {
  1748. if (key_exists('all', $arrToggle))
  1749. {
  1750. $arrToggle = array();
  1751. }
  1752. else
  1753. {
  1754. $arrToggle = array();
  1755. $arrToggle['all'] = 1;
  1756. }
  1757. // Save in session and redirect
  1758. $this->Session->set($strToggleID, $arrToggle);
  1759. $this->redirectHome();
  1760. }
  1761. // Init some vars
  1762. $objTableTreeData = $this->getDC()->getDataProvider()->getEmptyCollection();
  1763. $objRootConfig = $this->getDC()->getDataProvider()->getEmptyConfig();
  1764. // TODO: @CS rebuild to new layout of filters here.
  1765. // Set fields limit
  1766. $objRootConfig->setFields(array_keys(array_flip($arrNeededFields)));
  1767. // Set Filter for root elements
  1768. $objRootConfig->setFilter($arrRootEntries);
  1769. if (preg_match('/limit/', $this->getDC()->arrDCA['list']['sorting']['panelLayout']))
  1770. {
  1771. // Set limit
  1772. $objRootConfig->setStart($arrLimit[0])->setAmount($arrLimit[1]);
  1773. }
  1774. $objRootConfig->setSorting(array('sorting' => 'ASC'));
  1775. // Fetch all root elements
  1776. $objRootCollection = $this->getDC()->getDataProvider()->fetchAll($objRootConfig);
  1777. foreach ($objRootCollection as $objRootModel)
  1778. {
  1779. $objTableTreeData->add($objRootModel);
  1780. $this->treeWalkModel($objRootModel, 0, $arrToggle, array('self'));
  1781. }
  1782. $this->getDC()->setCurrentCollecion($objTableTreeData);
  1783. }
  1784. protected function calcLabelFields($strTable)
  1785. {
  1786. if ($strTable == $this->getDC()->getTable())
  1787. {
  1788. // easy, take from DCA.
  1789. return $this->getDC()->arrDCA['list']['label']['fields'];
  1790. }
  1791. $arrChildDef = $this->getDC()->arrDCA['dca_config']['child_list'];
  1792. if (is_array($arrChildDef) && array_key_exists($strTable, $arrChildDef) && isset($arrChildDef[$strTable]['fields']))
  1793. {
  1794. // check if defined in child conditions.
  1795. return $arrChildDef[$strTable]['fields'];
  1796. }
  1797. else if (($strTable == 'self') && is_array($arrChildDef) && array_key_exists('self', $arrChildDef) && $arrChildDef['self']['fields'])
  1798. {
  1799. return $arrChildDef['self']['fields'];
  1800. }
  1801. }
  1802. protected function calcLabelPattern($strTable)
  1803. {
  1804. if ($strTable == $this->getDC()->getTable())
  1805. {
  1806. // easy, take from DCA.
  1807. return $this->getDC()->arrDCA['list']['label']['format'];
  1808. }
  1809. $arrChildDef = $this->getDC()->arrDCA['dca_config']['child_list'];
  1810. if (is_array($arrChildDef) && array_key_exists($strTable, $arrChildDef) && isset($arrChildDef[$strTable]['format']))
  1811. {
  1812. // check if defined in child conditions.
  1813. return $arrChildDef[$strTable]['format'];
  1814. }
  1815. else if (($strTable == 'self') && array_key_exists('self', $arrChildDef) && $arrChildDef['self']['format'])
  1816. {
  1817. return $arrChildDef['self']['format'];
  1818. }
  1819. }
  1820. /**
  1821. * Get a list with all needed fields for the models.
  1822. *
  1823. * @param InterfaceGeneralModel $objModel
  1824. * @param string $strDstTable
  1825. *
  1826. * @return array A list with all needed values.
  1827. */
  1828. protected function calcNeededFields(InterfaceGeneralModel $objModel, $strDstTable)
  1829. {
  1830. $arrFields = $this->calcLabelFields($strDstTable);
  1831. $arrChildCond = $this->getDC()->getChildCondition($objModel, $strDstTable);
  1832. foreach ($arrChildCond as $arrCond)
  1833. {
  1834. if ($arrCond['property'])
  1835. {
  1836. $arrFields[] = $arrCond['property'];
  1837. }
  1838. }
  1839. // Add some default values, if we have this values in DB.
  1840. if($this->objDC->getDataProvider($strDstTable)->fieldExists('enabled'))
  1841. {
  1842. $arrFields [] = 'enabled';
  1843. }
  1844. return $arrFields;
  1845. }
  1846. protected function buildLabel(InterfaceGeneralModel $objModel)
  1847. {
  1848. // Build full lable
  1849. $arrFields = array();
  1850. foreach ($this->calcLabelFields($objModel->getProviderName()) as $strField)
  1851. {
  1852. $arrFields[] = $objModel->getProperty($strField);
  1853. }
  1854. $objModel->setMeta(DCGE::TREE_VIEW_TITLE, vsprintf($this->calcLabelPattern($objModel->getProviderName()), $arrFields));
  1855. // Callback - let it override the just generated label
  1856. $strLabel = $this->getDC()->getCallbackClass()->labelCallback($objModel, $objModel->getMeta(DCGE::TREE_VIEW_TITLE), $arrFields);
  1857. if ($strLabel != '')
  1858. {
  1859. $objModel->setMeta(DCGE::TREE_VIEW_TITLE, $strLabel);
  1860. }
  1861. }
  1862. /**
  1863. * This "renders" a model for tree view.
  1864. *
  1865. * @param InterfaceGeneralModel $objModel the model to render.
  1866. *
  1867. * @param int $intLevel the current level in the tree hierarchy.
  1868. *
  1869. * @param array $arrToggle the array that determines the current toggle states for the table of the given model.
  1870. *
  1871. * @param array $arrSubTables the tables that shall be rendered "below" this item.
  1872. *
  1873. */
  1874. protected function treeWalkModel(InterfaceGeneralModel $objModel, $intLevel, $arrToggle, $arrSubTables = array())
  1875. {
  1876. $blnHasChild = false;
  1877. $objModel->setMeta(DCGE::TREE_VIEW_LEVEL, $intLevel);
  1878. $this->buildLabel($objModel);
  1879. if ($arrToggle['all'] == 1 && !(key_exists($objModel->getID(), $arrToggle) && $arrToggle[$objModel->getID()] == 0))
  1880. {
  1881. $objModel->setMeta(DCGE::TREE_VIEW_IS_OPEN, true);
  1882. }
  1883. // Get toogle state
  1884. else if (key_exists($objModel->getID(), $arrToggle) && $arrToggle[$objModel->getID()] == 1)
  1885. {
  1886. $objModel->setMeta(DCGE::TREE_VIEW_IS_OPEN, true);
  1887. }
  1888. else
  1889. {
  1890. $objModel->setMeta(DCGE::TREE_VIEW_IS_OPEN, false);
  1891. }
  1892. $arrChildCollections = array();
  1893. foreach ($arrSubTables as $strSubTable)
  1894. {
  1895. // evaluate the child filter for this item.
  1896. $arrChildFilter = $this->getDC()->getChildCondition($objModel, $strSubTable);
  1897. // if we do not know how to render this table within here, continue with the next one.
  1898. if (!$arrChildFilter)
  1899. {
  1900. continue;
  1901. }
  1902. // Create a new Config
  1903. $objChildConfig = $this->getDC()->getDataProvider($strSubTable)->getEmptyConfig();
  1904. $objChildConfig->setFilter($arrChildFilter);
  1905. $objChildConfig->setFields($this->calcNeededFields($objModel, $strSubTable));
  1906. $objChildConfig->setSorting(array('sorting' => 'ASC'));
  1907. // Fetch all children
  1908. $objChildCollection = $this->getDC()->getDataProvider($strSubTable)->fetchAll($objChildConfig);
  1909. // Speed up
  1910. if ($objChildCollection->length() > 0 && !$objModel->getMeta(DCGE::TREE_VIEW_IS_OPEN))
  1911. {
  1912. $blnHasChild = true;
  1913. break;
  1914. }
  1915. else if ($objChildCollection->length() > 0)
  1916. {
  1917. $blnHasChild = true;
  1918. // TODO: @CS we need this to be srctable_dsttable_tree for interoperability, for mode5 this will be self_self_tree but with strTable.
  1919. $strToggleID = $this->getDC()->getTable() . '_tree';
  1920. $arrSubToggle = $this->Session->get($strToggleID);
  1921. if (!is_array($arrSubToggle))
  1922. {
  1923. $arrSubToggle = array();
  1924. }
  1925. foreach ($objChildCollection as $objChildModel)
  1926. {
  1927. // let the child know about it's parent.
  1928. $objModel->setMeta(DCGE::MODEL_PID, $objModel->getID());
  1929. $objModel->setMeta(DCGE::MODEL_PTABLE, $objModel->getProviderName());
  1930. // TODO: determine the real subtables here.
  1931. $this->treeWalkModel($objChildModel, $intLevel + 1, $arrSubToggle, $arrSubTables);
  1932. }
  1933. $arrChildCollections[] = $objChildCollection;
  1934. // speed up, if not open, one item is enough to break as we have some childs.
  1935. if (!$objModel->getMeta(DCGE::TREE_VIEW_IS_OPEN))
  1936. {
  1937. break;
  1938. }
  1939. }
  1940. }
  1941. // If open store children
  1942. if ($objModel->getMeta(DCGE::TREE_VIEW_IS_OPEN) && count($arrChildCollections) != 0)
  1943. {
  1944. $objModel->setMeta(DCGE::TREE_VIEW_CHILD_COLLECTION, $arrChildCollections);
  1945. }
  1946. $objModel->setMeta(DCGE::TREE_VIEW_HAS_CHILDS, $blnHasChild);
  1947. }
  1948. /**
  1949. * Show header of the parent table and list all records of the current table
  1950. * @return string
  1951. */
  1952. protected function viewParent()
  1953. {
  1954. if (!CURRENT_ID)
  1955. {
  1956. throw new Exception("mode 4 need a proper parent id defined, somehow none is defined?", 1);
  1957. }
  1958. if (!($objParentDP = $this->getDC()->getDataProvider('parent')))
  1959. {
  1960. throw new Exception("mode 4 need a proper parent dataprovide defined, somehow none is defined?", 1);
  1961. }
  1962. $objParentItem = $this->objDC->getCurrentParentCollection()->get(0);
  1963. // Get limits
  1964. $arrLimit = $this->calculateLimit();
  1965. // Load record from data provider
  1966. $objConfig = $this->getDC()->getDataProvider()->getEmptyConfig()
  1967. ->setStart($arrLimit[0])
  1968. ->setAmount($arrLimit[1])
  1969. ->setFilter($this->getFilter())
  1970. ->setSorting(array($this->getDC()->getFirstSorting() => $this->getDC()->getFirstSortingOrder()));
  1971. if ($this->foreignKey)
  1972. {
  1973. $objConfig->setFields($this->arrFields);
  1974. }
  1975. $this->getDC()->setCurrentCollecion($this->getDC()->getDataProvider()->fetchAll($objConfig));
  1976. }
  1977. /* /////////////////////////////////////////////////////////////////////
  1978. * ---------------------------------------------------------------------
  1979. * Panels
  1980. * ---------------------------------------------------------------------
  1981. * ////////////////////////////////////////////////////////////////// */
  1982. /**
  1983. * Check all submits from the panels. Save all vlaues into the Session.
  1984. * Reload the Website.
  1985. *
  1986. * @return void
  1987. */
  1988. protected function checkPanelSubmit()
  1989. {
  1990. // var_dump($_POST);
  1991. // var_dump($_GET);
  1992. // exit();
  1993. //
  1994. // Check if we have a submit
  1995. if (!in_array($this->Input->post('FORM_SUBMIT'), array('tl_filters')))
  1996. {
  1997. return;
  1998. }
  1999. // Session
  2000. $arrSession = Session::getInstance()->getData();
  2001. // Set limit from user input
  2002. if (strlen($this->Input->post('tl_limit')) != 0)
  2003. {
  2004. $strFilter = ($this->getDC()->arrDCA['list']['sorting']['mode'] == 4) ? $this->getDC()->getTable() . '_' . CURRENT_ID : $this->getDC()->getTable();
  2005. if ($this->Input->post('tl_limit') != 'tl_limit')
  2006. {
  2007. $arrSession['filter'][$strFilter]['limit'] = $this->Input->post('tl_limit');
  2008. }
  2009. else
  2010. {
  2011. unset($arrSession['filter'][$strFilter]['limit']);
  2012. }
  2013. }
  2014. // Set sorting from user input
  2015. if (strlen($this->Input->post('tl_sort')) != 0)
  2016. {
  2017. $arrSession['sorting'][$this->getDC()->getTable()] = in_array($this->getDC()->arrDCA['fields'][$this->Input->post('tl_sort')]['flag'], array(2, 4, 6, 8, 10, 12)) ? $this->Input->post('tl_sort') . ' DESC' : $this->Input->post('tl_sort');
  2018. }
  2019. // Set filter from user input
  2020. if ($this->Input->post('FORM_SUBMIT') == 'tl_filters')
  2021. {
  2022. // Get sorting fields
  2023. $arrFilterFields = array();
  2024. foreach ($this->getDC()->arrDCA['fields'] as $k => $v)
  2025. {
  2026. if ($v['filter'])
  2027. {
  2028. $arrFilterFields[] = $k;
  2029. }
  2030. }
  2031. foreach ($arrFilterFields as $field)
  2032. {
  2033. if ($this->Input->post($field, true) != 'tl_' . $field)
  2034. {
  2035. $arrSession['filter'][$strFilter][$field] = $this->Input->post($field, true);
  2036. }
  2037. else
  2038. {
  2039. unset($arrSession['filter'][$strFilter][$field]);
  2040. }
  2041. }
  2042. $this->Session->setData($arrSession);
  2043. }
  2044. // Store search value in the current session
  2045. if ($this->Input->post('FORM_SUBMIT') == 'tl_filters123')
  2046. {
  2047. $arrSession['search'][$this->getDC()->getTable()]['value'] = '';
  2048. $arrSession['search'][$this->getDC()->getTable()]['field'] = $this->Input->post('tl_field', true);
  2049. // Make sure the regular expression is valid
  2050. if ($this->Input->postRaw('tl_value') != '')
  2051. {
  2052. try
  2053. {
  2054. $objConfig = $this->getDC()->getDataProvider()->getEmptyConfig()
  2055. ->setSorting($this->getListViewSorting())
  2056. ->setSearch(
  2057. array(
  2058. array(
  2059. 'mode' => DCGE::DP_MODE_REGEX,
  2060. 'field' => $this->Input->post('tl_field', true),
  2061. 'value' => $this->Input->postRaw('tl_value')
  2062. )));
  2063. $this->getDC()->getDataProvider()->fetchAll($objConfig);
  2064. $arrSession['search'][$this->getDC()->getTable()]['value'] = $this->Input->postRaw('tl_value');
  2065. }
  2066. catch (Exception $e)
  2067. {
  2068. // Do nothing
  2069. }
  2070. }
  2071. Session::getInstance()->setData($arrSession);
  2072. }
  2073. Session::getInstance()->setData($arrSession);
  2074. // Reload
  2075. $this->reload();
  2076. }
  2077. /**
  2078. * Get all Informations for the panels.
  2079. *
  2080. * @WTF: Why we have 3 funtions for checking the panles submits?
  2081. * @todo CRY
  2082. * @todo Remove all checks for post and so on only build data.
  2083. * @todo Save all information about panels in Session. Not in DC General
  2084. * @todo Remove all functions, vars for Panels from DC General
  2085. */
  2086. protected function panel()
  2087. {
  2088. // Check if we have a panel
  2089. if (empty($this->getDC()->arrDCA['list']['sorting']['panelLayout']))
  2090. {
  2091. return;
  2092. }
  2093. $arrPanelView = array();
  2094. // Build the panel informations
  2095. $arrSortPanels = $this->generatePanelSort();
  2096. $arrFilterPanels = $this->generatePanelFilter();
  2097. $arrSearchPanels = $this->generatePanelSearch();
  2098. $arrLimitPanels = $this->generatePanelLimit();
  2099. if (!is_array($arrSortPanels) && !is_array($arrFilterPanels) && !is_array($arrLimitPanels) && !is_array($arrSearchPanels))
  2100. {
  2101. return;
  2102. }
  2103. $panelLayout = $this->getDC()->arrDCA['list']['sorting']['panelLayout'];
  2104. $arrPanels = trimsplit(';', $panelLayout);
  2105. foreach ($arrPanels as $keyPanel => $strPanel)
  2106. {
  2107. foreach (trimsplit(',', $strPanel) as $strField)
  2108. {
  2109. switch ($strField)
  2110. {
  2111. case 'limit':
  2112. if (!empty($arrLimitPanels))
  2113. $arrPanelView[$keyPanel]['limit'] = $arrLimitPanels;
  2114. break;
  2115. case 'search':
  2116. if (!empty($arrSearchPanels))
  2117. $arrPanelView[$keyPanel]['search'] = $arrSearchPanels;
  2118. break;
  2119. case 'filter':
  2120. if (!empty($arrFilterPanels))
  2121. $arrPanelView[$keyPanel]['filter'] = $arrFilterPanels;
  2122. break;
  2123. case 'sort':
  2124. if (!empty($arrSortPanels))
  2125. $arrPanelView[$keyPanel]['sort'] = $arrSortPanels;
  2126. break;
  2127. // ToDo: Callback for new panels ?
  2128. default:
  2129. break;
  2130. }
  2131. }
  2132. if (is_array($arrPanelView[$keyPanel]))
  2133. {
  2134. $arrPanelView[$keyPanel] = array_reverse($arrPanelView[$keyPanel]);
  2135. }
  2136. }
  2137. if (count($arrPanelView) > 0)
  2138. {
  2139. $this->getDC()->setPanelView(array_values($arrPanelView));
  2140. }
  2141. }
  2142. /**
  2143. * Generate all information for the filter panel.
  2144. *
  2145. * @param type $type
  2146. * @return type
  2147. */
  2148. protected function generatePanelFilter($type = 'add')
  2149. {
  2150. // Init
  2151. $arrSortingFields = array();
  2152. $arrSession = Session::getInstance()->getData();
  2153. // Setup
  2154. $this->getDC()->setButtonId('tl_buttons_a');
  2155. $strFilter = ($this->getDC()->arrDCA['list']['sorting']['mode'] == 4) ? $this->getDC()->getTable() . '_' . CURRENT_ID : $this->getDC()->getTable();
  2156. // Get sorting fields
  2157. foreach ($this->getDC()->arrDCA['fields'] as $k => $v)
  2158. {
  2159. if ($v['filter'])
  2160. {
  2161. $arrSortingFields[] = $k;
  2162. }
  2163. }
  2164. // Return if there are no sorting fields
  2165. if (empty($arrSortingFields))
  2166. {
  2167. return array();
  2168. }
  2169. // Set filter
  2170. if ($type == 'set')
  2171. {
  2172. $this->filterMenuSetFilter($arrSortingFields, $arrSession, $strFilter);
  2173. return;
  2174. }
  2175. // Add options
  2176. if ($type == 'add')
  2177. {
  2178. $arrPanelView = $this->filterMenuAddOptions($arrSortingFields, $arrSession, $strFilter);
  2179. return $arrPanelView;
  2180. }
  2181. }
  2182. protected function generatePanelSearch()
  2183. {
  2184. $searchFields = array();
  2185. $arrPanelView = array();
  2186. $arrSession = Session::getInstance()->getData();
  2187. // Get search fields
  2188. foreach ($this->getDC()->arrDCA['fields'] as $k => $v)
  2189. {
  2190. if ($v['search'])
  2191. {
  2192. $searchFields[] = $k;
  2193. }
  2194. }
  2195. // Return if there are no search fields
  2196. if (count($searchFields) == 0)
  2197. {
  2198. return array();
  2199. }
  2200. // // Set search value from session
  2201. // if ($arrSession['search'][$this->getDC()->getTable()]['value'] != '')
  2202. // {
  2203. // if (substr($GLOBALS['TL_CONFIG']['dbCollation'], -3) == '_ci')
  2204. // {
  2205. // $this->getDC()->setFilter(array("LOWER(CAST(" . $arrSession['search'][$this->getDC()->getTable()]['field'] . " AS CHAR)) REGEXP LOWER('" . $arrSession['search'][$this->getDC()->getTable()]['value'] . "')"));
  2206. // }
  2207. // else
  2208. // {
  2209. // $this->getDC()->setFilter(array("CAST(" . $arrSession['search'][$this->getDC()->getTable()]['field'] . " AS CHAR) REGEXP '" . $arrSession['search'][$this->getDC()->getTable()]['value'] . "'"));
  2210. // }
  2211. // }
  2212. $arrOptions = array();
  2213. foreach ($searchFields as $field)
  2214. {
  2215. $mixedOptionsLabel = strlen($this->getDC()->arrDCA['fields'][$field]['label'][0]) ? $this->getDC()->arrDCA['fields'][$field]['label'][0] : $GLOBALS['TL_LANG']['MSC'][$field];
  2216. $arrOptions[utf8_romanize($mixedOptionsLabel) . '_' . $field] = array(
  2217. 'value' => specialchars($field),
  2218. 'select' => (($field == $arrSession['search'][$this->getDC()->getTable()]['field']) ? ' selected="selected"' : ''),
  2219. 'content' => $mixedOptionsLabel
  2220. );
  2221. }
  2222. // Sort by option values
  2223. uksort($arrOptions, 'strcasecmp');
  2224. $arrPanelView['option'] = $arrOptions;
  2225. $active = strlen($arrSession['search'][$this->getDC()->getTable()]['value']) ? true : false;
  2226. $arrPanelView['select'] = array(
  2227. 'class' => 'tl_select' . ($active ? ' active' : '')
  2228. );
  2229. $arrPanelView['input'] = array(
  2230. 'class' => 'tl_text' . (($active) ? ' active' : ''),
  2231. 'value' => specialchars($arrSession['search'][$this->getDC()->getTable()]['value'])
  2232. );
  2233. return $arrPanelView;
  2234. }
  2235. /**
  2236. * Page Limit Picker.
  2237. * Check the limits, set session config, create information for the view.
  2238. *
  2239. * @param boolean
  2240. *
  2241. * @return string
  2242. */
  2243. protected function generatePanelLimit($blnOptional = false)
  2244. {
  2245. // Init vars
  2246. $arrPanelView = array();
  2247. $blnIsMaxResultsPerPage = false;
  2248. // Setup Vars
  2249. $strFilter = ($this->getDC()->arrDCA['list']['sorting']['mode'] == 4) ? $this->getDC()->getTable() . '_' . CURRENT_ID : $this->getDC()->getTable();
  2250. $arrSession = Session::getInstance()->getData();
  2251. // Get the amount for the current filter settings
  2252. if ($this->getDC()->arrDCA['list']['sorting']['mode'] == 5)
  2253. {
  2254. $objRootConfig = $this->getDC()->getDataProvider()->getEmptyConfig();
  2255. $objRootConfig->setIdOnly(true);
  2256. $objRootConfig->setFilter($this->getDC()->getRootConditions('self'));
  2257. $intCount = $this->getDC()->getDataProvider()->getCount($objRootConfig);
  2258. }
  2259. else
  2260. {
  2261. $objConfig = $this->getDC()->getDataProvider()->getEmptyConfig()->setFilter($this->getFilter());
  2262. $intCount = $this->getDC()->getDataProvider()->getCount($objConfig);
  2263. }
  2264. // Overall limit
  2265. if ($intCount > $GLOBALS['TL_CONFIG']['resultsPerPage'])
  2266. {
  2267. $blnIsMaxResultsPerPage = true;
  2268. // $GLOBALS['TL_CONFIG']['resultsPerPage'] = $GLOBALS['TL_CONFIG']['maxResultsPerPage'];
  2269. // $arrSession['filter'][$strFilter]['limit'] = '0,' . $GLOBALS['TL_CONFIG']['maxResultsPerPage'];
  2270. }
  2271. // Build options
  2272. if ($intCount > 0)
  2273. {
  2274. $arrPanelView['option'][0] = array();
  2275. $options_total = ceil($intCount / $GLOBALS['TL_CONFIG']['resultsPerPage']);
  2276. // Reset limit if other parameters have decreased the number of results
  2277. if ($this->getDC()->getLimit() == '' || preg_replace('/,.*$/i', '', $this->getDC()->getLimit()) > $intCount)
  2278. {
  2279. $this->getDC()->setLimit('0,' . $GLOBALS['TL_CONFIG']['resultsPerPage']);
  2280. }
  2281. // Build options
  2282. for ($i = 0; $i < $options_total; $i++)
  2283. {
  2284. $this_limit = ($i * $GLOBALS['TL_CONFIG']['resultsPerPage']) . ',' . $GLOBALS['TL_CONFIG']['resultsPerPage'];
  2285. $upper_limit = ($i * $GLOBALS['TL_CONFIG']['resultsPerPage'] + $GLOBALS['TL_CONFIG']['resultsPerPage']);
  2286. if ($upper_limit > $intCount)
  2287. {
  2288. $upper_limit = $intCount;
  2289. }
  2290. $arrPanelView['option'][] = array(
  2291. 'value' => $this_limit,
  2292. 'select' => $this->optionSelected($this->getDC()->getLimit(), $this_limit),
  2293. 'content' => ($i * $GLOBALS['TL_CONFIG']['resultsPerPage'] + 1) . ' - ' . $upper_limit
  2294. );
  2295. }
  2296. if ($blnIsMaxResultsPerPage)
  2297. {
  2298. $arrLimit = trimsplit(',', $this->getDC()->getLimit());
  2299. $arrPanelView['option'][] = array(
  2300. 'value' => 'all',
  2301. 'select' => ($arrLimit[0] == 0 && $arrLimit[1] == $intCount) ? ' selected="selected"' : '',
  2302. 'content' => $GLOBALS['TL_LANG']['MSC']['filterAll']
  2303. );
  2304. }
  2305. }
  2306. // Return if there is only one page
  2307. if ($blnOptional && ($intCount < 1 || $options_total < 2))
  2308. {
  2309. return array();
  2310. }
  2311. $arrPanelView['select'] = array(
  2312. 'class' => (($arrSession['filter'][$strFilter]['limit'] != 'all' && $intCount > $GLOBALS['TL_CONFIG']['resultsPerPage']) ? ' active' : '')
  2313. );
  2314. $arrPanelView['option'][0] = array(
  2315. 'value' => 'tl_limit',
  2316. 'select' => '',
  2317. 'content' => $GLOBALS['TL_LANG']['MSC']['filterRecords']
  2318. );
  2319. Session::getInstance()->setData($arrSession);
  2320. return $arrPanelView;
  2321. }
  2322. /**
  2323. * Return a select menu that allows to sort results by a particular field
  2324. *
  2325. * @return string
  2326. */
  2327. protected function generatePanelSort()
  2328. {
  2329. // Init
  2330. $arrPanelView = array();
  2331. $arrSortingFields = array();
  2332. $arrSession = Session::getInstance()->getData();
  2333. $strOrderBy = $this->getDC()->arrDCA['list']['sorting']['fields'];
  2334. $strFirstOrderBy = preg_replace('/\s+.*$/i', '', $strOrderBy[0]);
  2335. // Setup
  2336. $this->getDC()->setButtonId('tl_buttons_a');
  2337. // Return an empty array, if don't have mode 2 or 4
  2338. if (!in_array($this->getDC()->arrDCA['list']['sorting']['mode'], array(2, 4)))
  2339. {
  2340. return array();
  2341. }
  2342. // Get sorting fields
  2343. foreach ($this->getDC()->arrDCA['fields'] as $k => $v)
  2344. {
  2345. if ($v['sorting'])
  2346. {
  2347. $arrSortingFields[] = $k;
  2348. }
  2349. }
  2350. // Return if there are no sorting fields
  2351. if (empty($arrSortingFields))
  2352. {
  2353. return array();
  2354. }
  2355. // Add PID to order fields
  2356. if ($this->getDC()->arrDCA['list']['sorting']['mode'] == 3 && $this->getDC()->getDataProvider()->fieldExists('pid'))
  2357. {
  2358. array_unshift($strOrderBy, 'pid');
  2359. }
  2360. // Overwrite the "orderBy" value with the session value
  2361. if (strlen($arrSession['sorting'][$this->getDC()->getTable()]))
  2362. {
  2363. $overwrite = preg_quote(preg_replace('/\s+.*$/i', '', $arrSession['sorting'][$this->getDC()->getTable()]), '/');
  2364. $strOrderBy = array_diff($strOrderBy, preg_grep('/^' . $overwrite . '/i', $strOrderBy));
  2365. array_unshift($strOrderBy, $arrSession['sorting'][$this->getDC()->getTable()]);
  2366. $this->getDC()->setFirstSorting($overwrite);
  2367. $this->getDC()->setSorting($strOrderBy);
  2368. }
  2369. $arrOptions = array();
  2370. foreach ($arrSortingFields as $field)
  2371. {
  2372. $mixedOptionsLabel = strlen($this->getDC()->arrDCA['fields'][$field]['label'][0]) ? $this->getDC()->arrDCA['fields'][$field]['label'][0] : $GLOBALS['TL_LANG']['MSC'][$field];
  2373. if (is_array($mixedOptionsLabel))
  2374. {
  2375. $mixedOptionsLabel = $mixedOptionsLabel[0];
  2376. }
  2377. $arrOptions[$mixedOptionsLabel] = array(
  2378. 'value' => specialchars($field),
  2379. 'select' => ((!strlen($arrSession['sorting'][$this->getDC()->getTable()]) && $field == $strFirstOrderBy || $field == str_replace(' DESC', '', $arrSession['sorting'][$this->getDC()->getTable()])) ? ' selected="selected"' : ''),
  2380. 'content' => $mixedOptionsLabel
  2381. );
  2382. }
  2383. // Sort by option values
  2384. uksort($arrOptions, 'strcasecmp');
  2385. $arrPanelView['option'] = $arrOptions;
  2386. return $arrPanelView;
  2387. }
  2388. /**
  2389. * Set filter from user input and table configuration for filter menu
  2390. *
  2391. * @param array $arrSortingFields
  2392. * @param array $arrSession
  2393. * @param string $strFilter
  2394. * @return array
  2395. */
  2396. protected function filterMenuSetFilter($arrSortingFields, $arrSession, $strFilter)
  2397. {
  2398. // Set filter from table configuration
  2399. foreach ($arrSortingFields as $field)
  2400. {
  2401. if (isset($arrSession['filter'][$strFilter][$field]))
  2402. {
  2403. // Sort by day
  2404. if (in_array($this->arrDCA['fields'][$field]['flag'], array(5, 6)))
  2405. {
  2406. if ($arrSession['filter'][$strFilter][$field] == '')
  2407. {
  2408. $this->getDC()->setFilter(array(array('operation' => '=', 'property' => $field, 'value' => '')));
  2409. }
  2410. else
  2411. {
  2412. $objDate = new Date($arrSession['filter'][$strFilter][$field]);
  2413. $this->getDC()->setFilter(array(
  2414. array('operation' => '>', 'property' => $field, 'value' => $objDate->dayBegin),
  2415. array('operation' => '<', 'property' => $field, 'value' => $objDate->dayEnd)
  2416. ));
  2417. }
  2418. }
  2419. // Sort by month
  2420. elseif (in_array($this->arrDCA['fields'][$field]['flag'], array(7, 8)))
  2421. {
  2422. if ($arrSession['filter'][$strFilter][$field] == '')
  2423. {
  2424. $this->getDC()->setFilter(array(array('operation' => '=', 'property' => $field, 'value' => '')));
  2425. }
  2426. else
  2427. {
  2428. $objDate = new Date($arrSession['filter'][$strFilter][$field]);
  2429. $this->getDC()->setFilter(array(
  2430. array('operation' => '>', 'property' => $field, 'value' => $objDate->monthBegin),
  2431. array('operation' => '<', 'property' => $field, 'value' => $objDate->monthEnd)
  2432. ));
  2433. }
  2434. }
  2435. // Sort by year
  2436. elseif (in_array($this->arrDCA['fields'][$field]['flag'], array(9, 10)))
  2437. {
  2438. if ($arrSession['filter'][$strFilter][$field] == '')
  2439. {
  2440. $this->getDC()->setFilter(array(array('operation' => '=', 'property' => $field, 'value' => '')));
  2441. }
  2442. else
  2443. {
  2444. $objDate = new Date($arrSession['filter'][$strFilter][$field]);
  2445. $this->getDC()->setFilter(array(
  2446. array('operation' => '>', 'property' => $field, 'value' => $objDate->yearBegin),
  2447. array('operation' => '<', 'property' => $field, 'value' => $objDate->yearEnd)
  2448. ));
  2449. }
  2450. }
  2451. // Manual filter
  2452. elseif ($this->arrDCA['fields'][$field]['eval']['multiple'])
  2453. {
  2454. // TODO find in set
  2455. // CSV lists (see #2890)
  2456. /* if (isset($this->dca['fields'][$field]['eval']['csv']))
  2457. {
  2458. $this->procedure[] = $this->Database->findInSet('?', $field, true);
  2459. $this->values[] = $session['filter'][$filter][$field];
  2460. }
  2461. else
  2462. {
  2463. $this->procedure[] = $field . ' LIKE ?';
  2464. $this->values[] = '%"' . $session['filter'][$filter][$field] . '"%';
  2465. } */
  2466. }
  2467. // Other sort algorithm
  2468. else
  2469. {
  2470. $this->getDC()->setFilter(
  2471. array(
  2472. array('operation' => '=', 'property' => $field, 'value' => $arrSession['filter'][$strFilter][$field])
  2473. )
  2474. );
  2475. }
  2476. }
  2477. }
  2478. return $arrSession;
  2479. }
  2480. /**
  2481. * Add sorting options to filter menu
  2482. *
  2483. * @param array $arrSortingFields
  2484. * @param array $arrSession
  2485. * @param string $strFilter
  2486. * @return array
  2487. */
  2488. protected function filterMenuAddOptions($arrSortingFields, $arrSession, $strFilter)
  2489. {
  2490. $arrPanelView = array();
  2491. // Add sorting options
  2492. foreach ($arrSortingFields as $cnt => $field)
  2493. {
  2494. $arrProcedure = array();
  2495. if ($this->getDC()->arrDCA['list']['sorting']['mode'] == 4)
  2496. {
  2497. $arrProcedure[] = array('operation' => '=', 'property' => 'pid', 'value' => CURRENT_ID);
  2498. }
  2499. if (!is_null($this->getDC()->getRootIds()) && is_array($this->getDC()->getRootIds()))
  2500. {
  2501. $arrProcedure[] = array('operation' => 'IN', 'property' => 'id', 'values' => array_map('intval', $this->getDC()->getRootIds()));
  2502. }
  2503. foreach ((array)$this->getFilter() as $arrSubFilter)
  2504. {
  2505. if ($arrSubFilter['property'] != $field)
  2506. {
  2507. $arrProcedure[] = $arrSubFilter;
  2508. }
  2509. }
  2510. $objCollection = $this->getDC()->getDataProvider()->getFilterOptions(
  2511. $this->getDC()
  2512. ->getDataProvider()
  2513. ->getEmptyConfig()
  2514. ->setFields(array($field))
  2515. ->setFilter($arrProcedure)
  2516. );
  2517. // Begin select menu
  2518. $arrPanelView[$field] = array(
  2519. 'select' => array(
  2520. 'name' => $field,
  2521. 'id' => $field,
  2522. 'class' => 'tl_select' . (isset($arrSession['filter'][$strFilter][$field]) ? ' active' : '')
  2523. ),
  2524. 'option' => array(
  2525. array(
  2526. 'value' => 'tl_' . $field,
  2527. 'content' => (is_array($this->getDC()->arrDCA['fields'][$field]['label']) ? $this->getDC()->arrDCA['fields'][$field]['label'][0] : $this->getDC()->arrDCA['fields'][$field]['label'])
  2528. ),
  2529. array(
  2530. 'value' => 'tl_' . $field,
  2531. 'content' => '---'
  2532. )
  2533. )
  2534. );
  2535. if ($objCollection->length() > 0)
  2536. {
  2537. $options = array();
  2538. foreach ($objCollection as $intIndex => $objModel)
  2539. {
  2540. $options[$intIndex] = $objModel->getProperty($field);
  2541. }
  2542. // Sort by day
  2543. if (in_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['flag'], array(5, 6)))
  2544. {
  2545. $this->arrColSort = array(
  2546. 'field' => $field,
  2547. 'reverse' => ($this->getDC()->arrDCA['fields'][$field]['flag'] == 6) ? true : false
  2548. );
  2549. $objCollection->sort(array($this, 'sortCollection'));
  2550. foreach ($objCollection as $intIndex => $objModel)
  2551. {
  2552. if ($objModel->getProperty($field) == '')
  2553. {
  2554. $options[$objModel->getProperty($field)] = '-';
  2555. }
  2556. else
  2557. {
  2558. $options[$objModel->getProperty($field)] = $this->parseDate($GLOBALS['TL_CONFIG']['dateFormat'], $objModel->getProperty($field));
  2559. }
  2560. unset($options[$intIndex]);
  2561. }
  2562. }
  2563. // Sort by month
  2564. elseif (in_array($this->getDC()->arrDCA['fields'][$field]['flag'], array(7, 8)))
  2565. {
  2566. $this->arrColSort = array(
  2567. 'field' => $field,
  2568. 'reverse' => ($this->getDC()->arrDCA['fields'][$field]['flag'] == 8) ? true : false
  2569. );
  2570. $objCollection->sort(array($this, 'sortCollection'));
  2571. foreach ($objCollection as $intIndex => $objModel)
  2572. {
  2573. if ($objModel->getProperty($field) == '')
  2574. {
  2575. $options[$objModel->getProperty($field)] = '-';
  2576. }
  2577. else
  2578. {
  2579. $options[$objModel->getProperty($field)] = date('Y-m', $objModel->getProperty($field));
  2580. $intMonth = (date('m', $objModel->getProperty($field)) - 1);
  2581. if (isset($GLOBALS['TL_LANG']['MONTHS'][$intMonth]))
  2582. {
  2583. $options[$objModel->getProperty($field)] = $GLOBALS['TL_LANG']['MONTHS'][$intMonth] . ' ' . date('Y', $objModel->getProperty($field));
  2584. }
  2585. }
  2586. unset($options[$intIndex]);
  2587. }
  2588. }
  2589. // Sort by year
  2590. elseif (in_array($this->getDC()->arrDCA['fields'][$field]['flag'], array(9, 10)))
  2591. {
  2592. $this->arrColSort = array(
  2593. 'field' => $field,
  2594. 'reverse' => ($this->getDC()->arrDCA['fields'][$field]['flag'] == 10) ? true : false
  2595. );
  2596. $objCollection->sort(array($this, 'sortCollection'));
  2597. foreach ($objCollection as $intIndex => $objModel)
  2598. {
  2599. if ($objModel->getProperty($field) == '')
  2600. {
  2601. $options[$objModel->getProperty($field)] = '-';
  2602. }
  2603. else
  2604. {
  2605. $options[$objModel->getProperty($field)] = date('Y', $objModel->getProperty($field));
  2606. }
  2607. unset($options[$intIndex]);
  2608. }
  2609. }
  2610. // Manual filter
  2611. if ($this->getDC()->arrDCA['fields'][$field]['eval']['multiple'])
  2612. {
  2613. $moptions = array();
  2614. foreach ($objCollection as $objModel)
  2615. {
  2616. if (isset($this->getDC()->arrDCA['fields'][$field]['eval']['csv']))
  2617. {
  2618. $doptions = trimsplit($this->getDC()->arrDCA['fields'][$field]['eval']['csv'], $objModel->getProperty($field));
  2619. }
  2620. else
  2621. {
  2622. $doptions = deserialize($objModel->getProperty($field));
  2623. }
  2624. if (is_array($doptions))
  2625. {
  2626. $moptions = array_merge($moptions, $doptions);
  2627. }
  2628. }
  2629. $options = $moptions;
  2630. }
  2631. $options = array_unique($options);
  2632. $arrOptionsCallback = array();
  2633. // Load options callback
  2634. if (is_array($this->getDC()->arrDCA['fields'][$field]['options_callback']) && !$this->getDC()->arrDCA['fields'][$field]['reference'])
  2635. {
  2636. $arrOptionsCallback = $this->getDC()->getCallbackClass()->optionsCallback($field);
  2637. // Sort options according to the keys of the callback array
  2638. if (!is_null($arrOptionsCallback))
  2639. {
  2640. $options = array_intersect(array_keys($arrOptionsCallback), $options);
  2641. }
  2642. }
  2643. $arrOptions = array();
  2644. $arrSortOptions = array();
  2645. $blnDate = in_array($this->getDC()->arrDCA['fields'][$field]['flag'], array(5, 6, 7, 8, 9, 10));
  2646. // Options
  2647. foreach ($options as $kk => $vv)
  2648. {
  2649. $value = $blnDate ? $kk : $vv;
  2650. // Replace the ID with the foreign key
  2651. if (isset($this->getDC()->arrDCA['fields'][$field]['foreignKey']))
  2652. {
  2653. $key = explode('.', $this->getDC()->arrDCA['fields'][$field]['foreignKey'], 2);
  2654. $objModel = $this->getDC()->getDataProvider($key[0])->fetch(
  2655. $this->getDC()->getDataProvider($key[0])->getEmptyConfig()
  2656. ->setId($vv)
  2657. ->setFields(array($key[1] . ' AS value'))
  2658. );
  2659. if ($objModel->hasProperties())
  2660. {
  2661. $vv = $objModel->getProperty('value');
  2662. }
  2663. }
  2664. // Replace boolean checkbox value with "yes" and "no"
  2665. elseif ($this->getDC()->arrDCA['fields'][$field]['eval']['isBoolean'] || ($this->getDC()->arrDCA['fields'][$field]['inputType'] == 'checkbox' && !$this->getDC()->arrDCA['fields'][$field]['eval']['multiple']))
  2666. {
  2667. $vv = ($vv != '') ? $GLOBALS['TL_LANG']['MSC']['yes'] : $GLOBALS['TL_LANG']['MSC']['no'];
  2668. }
  2669. // Options callback
  2670. elseif (is_array($arrOptionsCallback) && !empty($arrOptionsCallback))
  2671. {
  2672. $vv = $arrOptionsCallback[$vv];
  2673. }
  2674. // Get the name of the parent record
  2675. elseif ($field == 'pid')
  2676. {
  2677. // Load language file and data container array of the parent table
  2678. $this->loadLanguageFile($this->getDC()->getParentTable());
  2679. $this->loadDataContainer($this->getDC()->getParentTable());
  2680. $objParentDC = new DC_General($this->getDC()->getParentTable());
  2681. $arrParentDca = $objParentDC->getDCA();
  2682. $showFields = $arrParentDca['list']['label']['fields'];
  2683. if (!$showFields[0])
  2684. {
  2685. $showFields[0] = 'id';
  2686. }
  2687. $objModel = $this->getDC()->getDataProvider('parent')->fetch(
  2688. $this->getDC()->getDataProvider('parent')->getEmptyConfig()
  2689. ->setId($vv)
  2690. ->setFields(array($showFields[0]))
  2691. );
  2692. if ($objModel->hasProperties())
  2693. {
  2694. $vv = $objModel->getProperty($showFields[0]);
  2695. }
  2696. }
  2697. $strOptionsLabel = '';
  2698. // Use reference array
  2699. if (isset($this->getDC()->arrDCA['fields'][$field]['reference']))
  2700. {
  2701. $strOptionsLabel = is_array($this->getDC()->arrDCA['fields'][$field]['reference'][$vv]) ? $this->getDC()->arrDCA['fields'][$field]['reference'][$vv][0] : $this->getDC()->arrDCA['fields'][$field]['reference'][$vv];
  2702. }
  2703. // Associative array
  2704. elseif ($this->getDC()->arrDCA['fields'][$field]['eval']['isAssociative'] || array_is_assoc($this->getDC()->arrDCA['fields'][$field]['options']))
  2705. {
  2706. $strOptionsLabel = $this->getDC()->arrDCA['fields'][$field]['options'][$vv];
  2707. }
  2708. // No empty options allowed
  2709. if (!strlen($strOptionsLabel))
  2710. {
  2711. // FIXME: this is a rather evil hack but I ended up here with an array containing files.
  2712. // This usually reensembles an invalid setup but we should not raise warnings then but cope
  2713. // correctly with it. For the moment, we simply ignore such data we can not handle.
  2714. if (!is_string($vv))
  2715. {
  2716. continue;
  2717. }
  2718. $strOptionsLabel = strlen($vv) ? $vv : '-';
  2719. }
  2720. $arrOptions[utf8_romanize($strOptionsLabel)] = array(
  2721. 'value' => specialchars($value),
  2722. 'select' => ((isset($arrSession['filter'][$strFilter][$field]) && $value == $arrSession['filter'][$strFilter][$field]) ? ' selected="selected"' : ''),
  2723. 'content' => $strOptionsLabel
  2724. );
  2725. $arrSortOptions[] = utf8_romanize($strOptionsLabel);
  2726. }
  2727. // Sort by option values
  2728. if (!$blnDate)
  2729. {
  2730. natcasesort($arrSortOptions);
  2731. if (in_array($this->getDC()->arrDCA['fields'][$field]['flag'], array(2, 4, 12)))
  2732. {
  2733. $arrSortOptions = array_reverse($arrSortOptions, true);
  2734. }
  2735. }
  2736. foreach ($arrSortOptions as $value)
  2737. {
  2738. $arrPanelView[$field]['option'][] = $arrOptions[$value];
  2739. }
  2740. }
  2741. // Force a line-break after six elements
  2742. if ((($cnt + 1) % 6) == 0)
  2743. {
  2744. $arrPanelView[] = 'new';
  2745. }
  2746. }
  2747. return $arrPanelView;
  2748. }
  2749. /* /////////////////////////////////////////////////////////////////////
  2750. * ---------------------------------------------------------------------
  2751. * Helper DataProvider
  2752. * ---------------------------------------------------------------------
  2753. * ////////////////////////////////////////////////////////////////// */
  2754. /**
  2755. * Check if a entry has some childs
  2756. *
  2757. * @param array $arrFilterPattern
  2758. * @param InterfaceGeneralModel $objParentModel
  2759. *
  2760. * @return boolean True => has children | False => no children
  2761. */
  2762. protected function hasChildren($objParentModel, $strTable)
  2763. {
  2764. $arrFilter = array();
  2765. // Build filter Settings
  2766. foreach ($this->getDC()->getJoinConditions($objParentModel, $strTable) as $valueFilter)
  2767. {
  2768. if (isset($valueFilter['srcField']) && $valueFilter['srcField'] != '')
  2769. {
  2770. $arrFilter[] = $valueFilter['dstField'] . $valueFilter['operation'] . $objParentModel->getProperty($valueFilter['srcField']);
  2771. }
  2772. else
  2773. {
  2774. $arrFilter[] = $valueFilter['dstField'] . $valueFilter['operation'];
  2775. }
  2776. }
  2777. // Create a new Config
  2778. $objConfig = $this->getDC()->getDataProvider()->getEmptyConfig();
  2779. $objConfig->setFilter($arrFilter);
  2780. // Fetch all children
  2781. if ($this->getDC()->getDataProvider()->getCount($objConfig) != 0)
  2782. {
  2783. return true;
  2784. }
  2785. else
  2786. {
  2787. return false;
  2788. }
  2789. }
  2790. protected function setParent(InterfaceGeneralModel $objChildEntry, InterfaceGeneralModel $objParentEntry, $strTable)
  2791. {
  2792. $arrChildCondition = $this->getDC()->getParentChildCondition($objParentEntry, $objChildEntry->getProviderName());
  2793. if (!($arrChildCondition && $arrChildCondition['setOn']))
  2794. {
  2795. throw new Exception("Can not calculate parent.", 1);
  2796. }
  2797. foreach ($arrChildCondition['setOn'] as $arrCondition)
  2798. {
  2799. if ($arrCondition['from_field'])
  2800. {
  2801. $objChildEntry->setProperty($arrCondition['to_field'], $objParentEntry->getProperty($arrCondition['from_field']));
  2802. }
  2803. else if (!is_null('value', $arrCondition))
  2804. {
  2805. $objChildEntry->setProperty($arrCondition['to_field'], $arrCondition['value']);
  2806. }
  2807. else
  2808. {
  2809. throw new Exception("Error Processing child condition, neither from_field nor value specified: " . var_export($arrCondition, true), 1);
  2810. }
  2811. }
  2812. }
  2813. protected function getParent($strTable, $objCurrentModel = null, $intCurrentID = null)
  2814. {
  2815. // Check if something is set
  2816. if ($objCurrentModel == null && $intCurrentID == null)
  2817. {
  2818. return null;
  2819. }
  2820. // If we have only the id load current model
  2821. if ($objCurrentModel == null)
  2822. {
  2823. $objCurrentConfig = $this->getDC()->getDataProvider()->getEmptyConfig();
  2824. $objCurrentConfig->setId($intCurrentID);
  2825. $objCurrentModel = $this->getDC()->getDataProvider()->fetch($objCurrentConfig);
  2826. }
  2827. // Build child to parent
  2828. $strFilter = $arrJoinCondition[0]['srcField'] . $arrJoinCondition[0]['operation'] . $objCurrentModel->getProperty($arrJoinCondition[0]['dstField']);
  2829. // Load model
  2830. $objParentConfig = $this->getDC()->getDataProvider()->getEmptyConfig();
  2831. $objParentConfig->setFilter(array($strFilter));
  2832. return $this->getDC()->getDataProvider()->fetch($objParentConfig);
  2833. }
  2834. protected function isRootEntry($strTable, $mixID)
  2835. {
  2836. // Get the join field
  2837. $arrRootCondition = $this->getDC()->getRootConditions($strTable);
  2838. switch ($arrRootCondition[0]['operation'])
  2839. {
  2840. case '=':
  2841. return ($mixID == $arrRootCondition[0]['value']);
  2842. case '<':
  2843. return ($arrRootCondition[0]['value'] < $mixID);
  2844. case '>':
  2845. return ($arrRootCondition[0]['value'] > $mixID);
  2846. case '!=':
  2847. return ($arrRootCondition[0]['value'] != $mixID);
  2848. }
  2849. return false;
  2850. }
  2851. protected function setRoot(InterfaceGeneralModel $objCurrentEntry, $strTable)
  2852. {
  2853. $arrRootSetter = $this->getDC()->getRootSetter($strTable);
  2854. if (!($arrRootSetter && $arrRootSetter))
  2855. {
  2856. throw new Exception("Can not calculate parent.", 1);
  2857. }
  2858. foreach ($arrRootSetter as $arrCondition)
  2859. {
  2860. if (($arrCondition['property'] && isset($arrCondition['value'])))
  2861. {
  2862. $objCurrentEntry->setProperty($arrCondition['property'], $arrCondition['value']);
  2863. }
  2864. else
  2865. {
  2866. throw new Exception("Error Processing root condition, you need to specify property and value: " . var_export($arrCondition, true), 1);
  2867. }
  2868. }
  2869. }
  2870. /* /////////////////////////////////////////////////////////////////////
  2871. * ---------------------------------------------------------------------
  2872. * Helper
  2873. * ---------------------------------------------------------------------
  2874. * ////////////////////////////////////////////////////////////////// */
  2875. public function sortCollection(InterfaceGeneralModel $a, InterfaceGeneralModel $b)
  2876. {
  2877. if ($a->getProperty($this->arrColSort['field']) == $b->getProperty($this->arrColSort['field']))
  2878. {
  2879. return 0;
  2880. }
  2881. if (!$this->arrColSort['reverse'])
  2882. {
  2883. return ($a->getProperty($this->arrColSort['field']) < $b->getProperty($this->arrColSort['field'])) ? -1 : 1;
  2884. }
  2885. else
  2886. {
  2887. return ($a->getProperty($this->arrColSort['field']) < $b->getProperty($this->arrColSort['field'])) ? 1 : -1;
  2888. }
  2889. }
  2890. /**
  2891. * Ajax actions that do require a data container object
  2892. * @param DataContainer
  2893. */
  2894. public function executePostActions()
  2895. {
  2896. header('Content-Type: text/html; charset=' . $GLOBALS['TL_CONFIG']['characterSet']);
  2897. switch ($this->Input->post('action'))
  2898. {
  2899. // Toggle subpalettes
  2900. case 'toggleSubpalette':
  2901. $this->import('BackendUser', 'User');
  2902. // Check whether the field is a selector field and allowed for regular users (thanks to Fabian Mihailowitsch) (see #4427)
  2903. if (!is_array($this->getDC()->arrDCA['palettes']['__selector__'])
  2904. || !in_array($this->Input->post('field'), $this->getDC()->arrDCA['palettes']['__selector__'])
  2905. || ($this->getDC()->arrDCA['fields'][$this->Input->post('field')]['exclude']
  2906. && !$this->User->hasAccess($this->getDC()->getTable() . '::' . $this->Input->post('field'), 'alexf')))
  2907. {
  2908. $this->log('Field "' . $this->Input->post('field') . '" is not an allowed selector field (possible SQL injection attempt)', 'DC_General executePostActions()', TL_ERROR);
  2909. header('HTTP/1.1 400 Bad Request');
  2910. die('Bad Request');
  2911. }
  2912. if ($this->Input->get('act') == 'editAll')
  2913. {
  2914. throw new Exception("Ajax editAll unimplemented, I do not know what to do.", 1);
  2915. if ($this->Input->post('load'))
  2916. {
  2917. echo $this->getDC()->editAll();
  2918. }
  2919. }
  2920. else
  2921. {
  2922. if ($this->Input->post('load'))
  2923. {
  2924. echo $this->getDC()->generateAjaxPalette($this->Input->post('field'));
  2925. }
  2926. }
  2927. exit;
  2928. break;
  2929. default:
  2930. // do nothing, the normal workflow from Backend will kick in now.
  2931. }
  2932. }
  2933. }