PageRenderTime 47ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 1ms

/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

Large files files are truncated, but you can click here to view the full 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->fetch

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