PageRenderTime 57ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/administrator/components/com_modules/models/module.php

https://github.com/joebushi/joomla
PHP | 741 lines | 442 code | 101 blank | 198 comment | 68 complexity | 424cb8931044be8616b8f5dbc73db83b MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0
  1. <?php
  2. /**
  3. * @version $Id$
  4. * @package Joomla.Administrator
  5. * @subpackage Modules
  6. * @copyright Copyright (C) 2005 - 2010 Open Source Matters, Inc. All rights reserved.
  7. * @license GNU General Public License version 2 or later; see LICENSE.txt
  8. */
  9. // No direct access.
  10. defined('_JEXEC') or die;
  11. jimport('joomla.application.component.modelform');
  12. /**
  13. * Module model.
  14. *
  15. * @package Joomla.Administrator
  16. * @subpackage com_modules
  17. * @since 1.6
  18. */
  19. class ModulesModelModule extends JModelForm
  20. {
  21. /**
  22. * Item cache.
  23. */
  24. private $_cache = array();
  25. /**
  26. * Method to auto-populate the model state.
  27. */
  28. protected function _populateState()
  29. {
  30. $app = JFactory::getApplication('administrator');
  31. // Load the User state.
  32. if (!($pk = (int) $app->getUserState('com_modules.edit.module.id')))
  33. {
  34. if ($extensionId = (int) $app->getUserState('com_modules.add.module.extension_id'))
  35. {
  36. $this->setState('extension.id', $extensionId);
  37. }
  38. else
  39. {
  40. $pk = (int) JRequest::getInt('id');
  41. }
  42. }
  43. $this->setState('module.id', $pk);
  44. // Load the parameters.
  45. $params = JComponentHelper::getParams('com_modules');
  46. $this->setState('params', $params);
  47. }
  48. /**
  49. * Prepare and sanitise the table prior to saving.
  50. */
  51. protected function _prepareTable(&$table)
  52. {
  53. jimport('joomla.filter.output');
  54. $date = JFactory::getDate();
  55. $user = JFactory::getUser();
  56. $table->title = htmlspecialchars_decode($table->title, ENT_QUOTES);
  57. if (empty($table->id)) {
  58. // Set the values
  59. //$table->created = $date->toMySQL();
  60. }
  61. else {
  62. // Set the values
  63. //$table->modified = $date->toMySQL();
  64. //$table->modified_by = $user->get('id');
  65. }
  66. }
  67. /**
  68. * Returns a reference to the a Table object, always creating it.
  69. *
  70. * @param type $type The table type to instantiate
  71. * @param string $prefix A prefix for the table class name. Optional.
  72. * @param array $options Configuration array for model. Optional.
  73. * @return JTable A database object
  74. */
  75. public function getTable($type = 'Module', $prefix = 'JTable', $config = array())
  76. {
  77. return JTable::getInstance($type, $prefix, $config);
  78. }
  79. /**
  80. * Method to override check-out a row for editing.
  81. *
  82. * @param int The ID of the primary key.
  83. * @return boolean
  84. */
  85. public function checkout($pk = null)
  86. {
  87. // Initialise variables.
  88. $pk = (!empty($pk)) ? $pk : (int) $this->getState('module.id');
  89. return parent::checkout($pk);
  90. }
  91. /**
  92. * Method to checkin a row.
  93. *
  94. * @param integer The ID of the primary key.
  95. *
  96. * @return boolean
  97. */
  98. public function checkin($pk = null)
  99. {
  100. // Initialise variables.
  101. $pk = (!empty($pk)) ? $pk : (int) $this->getState('module.id');
  102. return parent::checkin($pk);
  103. }
  104. /**
  105. * Method to get a single record.
  106. *
  107. * @param integer The id of the primary key.
  108. *
  109. * @return mixed Object on success, false on failure.
  110. */
  111. public function &getItem($pk = null)
  112. {
  113. // Initialise variables.
  114. $pk = (!empty($pk)) ? (int) $pk : (int) $this->getState('module.id');
  115. if (!isset($this->_cache[$pk])) {
  116. $false = false;
  117. // Get a row instance.
  118. $table = &$this->getTable();
  119. // Attempt to load the row.
  120. $return = $table->load($pk);
  121. // Check for a table object error.
  122. if ($return === false && $error = $table->getError()) {
  123. $this->setError($error);
  124. return $false;
  125. }
  126. // Check if we are creating a new extension.
  127. if (empty($pk)) {
  128. if ($extensionId = (int) $this->getState('extension.id')) {
  129. jimport('joomla.database.query');
  130. $query = new JQuery;
  131. $query->select('element, client_id');
  132. $query->from('#__extensions');
  133. $query->where('extension_id = '.$extensionId);
  134. $query->where('type = '.$this->_db->quote('module'));
  135. $this->_db->setQuery($query);
  136. $extension = $this->_db->loadObject();
  137. if (empty($extension)) {
  138. if ($error = $this->_db->getErrorMsg()) {
  139. $this->setError($error);
  140. } else {
  141. $this->setError('Modules_Error_Cannot_find_extension');
  142. }
  143. return false;
  144. }
  145. // Extension found, prime some module values.
  146. $table->module = $extension->element;
  147. $table->client_id = $extension->client_id;
  148. } else {
  149. $this->setError('Modules_Error_Cannot_get_item');
  150. return false;
  151. }
  152. }
  153. // Convert to the JObject before adding other data.
  154. $this->_cache[$pk] = JArrayHelper::toObject($table->getProperties(1), 'JObject');
  155. // Convert the params field to an array.
  156. $registry = new JRegistry;
  157. $registry->loadJSON($table->params);
  158. $this->_cache[$pk]->params = $registry->toArray();
  159. // Determine the page assignment mode.
  160. $this->_db->setQuery(
  161. 'SELECT menuid' .
  162. ' FROM #__modules_menu' .
  163. ' WHERE moduleid = '.$pk
  164. );
  165. $assigned = $this->_db->loadResultArray();
  166. if (empty($pk)) {
  167. // If this is a new module, assign to all pages.
  168. $assignment = 0;
  169. } else if (empty($assigned)) {
  170. // For an existing module it is assigned to none.
  171. $assignment = '-';
  172. }
  173. else {
  174. if ($assigned[0] > 0) {
  175. $assignment = +1;
  176. } else if ($assigned[0] < 0) {
  177. $assignment = -1;
  178. } else {
  179. $assignment = 0;
  180. }
  181. }
  182. $this->_cache[$pk]->assigned = $assigned;
  183. $this->_cache[$pk]->assignment = $assignment;
  184. // Get the module XML.
  185. $client = JApplicationHelper::getClientInfo($table->client_id);
  186. $path = JPath::clean($client->path.'/modules/'.$table->module.'/'.$table->module.'.xml');
  187. if (file_exists($path)) {
  188. $this->_cache[$pk]->xml = simplexml_load_file($path);
  189. } else {
  190. $this->_cache[$pk]->xml = null;
  191. }
  192. }
  193. return $this->_cache[$pk];
  194. }
  195. /**
  196. * Method to get the client object
  197. *
  198. * @since 1.6
  199. */
  200. function &getClient()
  201. {
  202. return $this->_client;
  203. }
  204. /**
  205. * Method to get the record form.
  206. *
  207. * @return mixed JForm object on success, false on failure.
  208. */
  209. public function getForm()
  210. {
  211. // Initialise variables.
  212. $app = JFactory::getApplication();
  213. // Get the form.
  214. $form = parent::getForm('module', 'com_modules.module', array('array' => 'jform', 'event' => 'onPrepareForm'));
  215. // Check for an error.
  216. if (JError::isError($form)) {
  217. $this->setError($form->getMessage());
  218. return false;
  219. }
  220. // Check the session for previously entered form data.
  221. $data = $app->getUserState('com_modules.edit.module.data', array());
  222. // Bind the form data if present.
  223. if (!empty($data)) {
  224. $form->bind($data);
  225. }
  226. return $form;
  227. }
  228. /**
  229. * Method to get a form object for the module params.
  230. *
  231. * @param string An optional module folder.
  232. * @param int An client id.
  233. *
  234. * @return mixed A JForm object on success, false on failure.
  235. */
  236. public function getParamsForm($module = null, $clientId = null)
  237. {
  238. jimport('joomla.filesystem.file');
  239. jimport('joomla.filesystem.folder');
  240. // Initialise variables.
  241. $lang = JFactory::getLanguage();
  242. $form = null;
  243. $formName = 'com_modules.module.params';
  244. $formOptions = array('array' => 'jformparams', 'event' => 'onPrepareForm');
  245. if (empty($module) && is_null($clientId))
  246. {
  247. $item = $this->getItem();
  248. $clientId = $item->client_id;
  249. $module = $item->module;
  250. }
  251. $client = JApplicationHelper::getClientInfo($clientId);
  252. $formFile = JPath::clean($client->path.'/modules/'.$module.'/'.$module.'.xml');
  253. // Load the core and/or local language file(s).
  254. $lang->load($module, $client->path.'/modules/'.$module);
  255. $lang->load($module, $client->path);
  256. if (file_exists($formFile))
  257. {
  258. // If an XML file was found in the component, load it first.
  259. // We need to qualify the full path to avoid collisions with component file names.
  260. $form = parent::getForm($formFile, $formName, $formOptions, true);
  261. // Check for an error.
  262. if (JError::isError($form)) {
  263. $this->setError($form->getMessage());
  264. return false;
  265. }
  266. }
  267. return $form;
  268. }
  269. /**
  270. * Method to save the form data.
  271. *
  272. * @param array The form data.
  273. * @return boolean True on success.
  274. */
  275. public function save($data)
  276. {
  277. // Initialise variables;
  278. $dispatcher = JDispatcher::getInstance();
  279. $table = $this->getTable();
  280. $pk = (!empty($data['id'])) ? $data['id'] : (int) $this->getState('module.id');
  281. $isNew = true;
  282. // Include the content modules for the onSave events.
  283. JPluginHelper::importPlugin('content');
  284. // Load the row if saving an existing record.
  285. if ($pk > 0)
  286. {
  287. $table->load($pk);
  288. $isNew = false;
  289. }
  290. // Bind the data.
  291. if (!$table->bind($data))
  292. {
  293. $this->setError(JText::sprintf('JTable_Error_Bind_failed', $table->getError()));
  294. return false;
  295. }
  296. // Prepare the row for saving
  297. $this->_prepareTable($table);
  298. // Check the data.
  299. if (!$table->check())
  300. {
  301. $this->setError($table->getError());
  302. return false;
  303. }
  304. // Trigger the onBeforeSaveContent event.
  305. $result = $dispatcher->trigger('onBeforeContentSave', array(&$table, $isNew));
  306. if (in_array(false, $result, true)) {
  307. $this->setError($table->getError());
  308. return false;
  309. }
  310. // Store the data.
  311. if (!$table->store()) {
  312. $this->setError($table->getError());
  313. return false;
  314. }
  315. //
  316. // Process the menu link mappings.
  317. //
  318. $assignment = isset($data['assignment']) ? $data['assignment'] : 0;
  319. // Delete old module to menu item associations
  320. // $this->_db->setQuery(
  321. // 'DELETE FROM #__modules_menu'.
  322. // ' WHERE moduleid = '.(int) $table->id
  323. // );
  324. $query = new JQuery;
  325. $query->delete();
  326. $query->from('#__modules_menu');
  327. $query->where('moduleid='.(int)$table->id);
  328. $this->_db->setQuery((string)$query);
  329. $this->_db->query();
  330. if (!$this->_db->query())
  331. {
  332. $this->setError($this->_db->getErrorMsg());
  333. return false;
  334. }
  335. // If the assignment is numeric, then something is selected (otherwise it's none).
  336. if (is_numeric($assignment))
  337. {
  338. // Variable is numeric, but could be a string.
  339. $assignment = (int) $assignment;
  340. // Check needed to stop a module being assigned to `All`
  341. // and other menu items resulting in a module being displayed twice.
  342. if ($assignment === 0)
  343. {
  344. // assign new module to `all` menu item associations
  345. // $this->_db->setQuery(
  346. // 'INSERT INTO #__modules_menu'.
  347. // ' SET moduleid = '.(int) $table->id.', menuid = 0'
  348. // );
  349. $query = new JQuery;
  350. $query->insert('#__modules_menu');
  351. $query->set('moduleid='.(int)$table->id);
  352. $query->set('menuid=0');
  353. $this->_db->setQuery((string)$query);
  354. if (!$this->_db->query())
  355. {
  356. $this->setError($this->_db->getErrorMsg());
  357. return false;
  358. }
  359. }
  360. else if (!empty($data['assigned']))
  361. {
  362. // Get the sign of the number.
  363. $sign = $assignment < 0 ? -1 : +1;
  364. // Preprocess the assigned array.
  365. $tuples = array();
  366. foreach ($data['assigned'] as &$pk)
  367. {
  368. $tuples[] = '('.(int) $table->id.','.(int) $pk * $sign.')';
  369. }
  370. $this->_db->setQuery(
  371. 'INSERT INTO #__modules_menu (moduleid, menuid) VALUES '.
  372. implode(',', $tuples)
  373. );
  374. if (!$this->_db->query())
  375. {
  376. $this->setError($this->_db->getErrorMsg());
  377. return false;
  378. }
  379. }
  380. }
  381. // Clean the cache.
  382. $cache = JFactory::getCache('com_modules');
  383. $cache->clean();
  384. // Trigger the onAfterContentSave event.
  385. $dispatcher->trigger('onAfterContentSave', array(&$table, $isNew));
  386. $this->setState('module.id', $table->id);
  387. return true;
  388. }
  389. /**
  390. * Method to delete rows.
  391. *
  392. * @param array An array of item ids.
  393. *
  394. * @return boolean Returns true on success, false on failure.
  395. */
  396. public function delete(&$pks)
  397. {
  398. // Initialise variables.
  399. $pks = (array) $pks;
  400. $user = JFactory::getUser();
  401. $table = $this->getTable();
  402. // Iterate the items to delete each one.
  403. foreach ($pks as $i => $pk)
  404. {
  405. if ($table->load($pk))
  406. {
  407. // Access checks.
  408. if (!$user->authorise('core.delete', 'com_modules'))
  409. {
  410. throw new Exception(JText::_('JError_Core_Delete_not_permitted'));
  411. }
  412. if (!$table->delete($pk))
  413. {
  414. throw new Exception($table->getError());
  415. } else {
  416. // Delete the menu assignments
  417. $query = new JQuery;
  418. $query->delete();
  419. $query->from('#__modules_menu');
  420. $query->where('moduleid='.(int)$pk);
  421. $this->_db->setQuery((string)$query);
  422. $this->_db->query();
  423. }
  424. }
  425. else
  426. {
  427. throw new Exception($table->getError());
  428. }
  429. }
  430. return true;
  431. }
  432. /**
  433. * Method to publish records.
  434. *
  435. * @param array The ids of the items to publish.
  436. * @param int The value of the published state
  437. *
  438. * @return boolean True on success.
  439. */
  440. function publish(&$pks, $value = 1)
  441. {
  442. // Initialise variables.
  443. $user = JFactory::getUser();
  444. $table = $this->getTable();
  445. $pks = (array) $pks;
  446. // Access checks.
  447. foreach ($pks as $i => $pk)
  448. {
  449. if ($table->load($pk))
  450. {
  451. $allow = $user->authorise('core.edit.state', 'com_modules');
  452. if (!$allow)
  453. {
  454. // Prune items that you can't change.
  455. unset($pks[$i]);
  456. JError::raiseWarning(403, JText::_('JError_Core_Edit_State_not_permitted'));
  457. }
  458. }
  459. }
  460. // Attempt to change the state of the records.
  461. if (!$table->publish($pks, $value, $user->get('id'))) {
  462. $this->setError($table->getError());
  463. return false;
  464. }
  465. return true;
  466. }
  467. /**
  468. * Method to duplicate modules.
  469. *
  470. * @param array An array of primary key IDs.
  471. *
  472. * @return boolean True if successful.
  473. * @throws Exception
  474. */
  475. public function duplicate(&$pks)
  476. {
  477. // Initialise variables.
  478. $user = JFactory::getUser();
  479. $db = $this->getDbo();
  480. // Access checks.
  481. if (!$user->authorise('core.create', 'com_modules'))
  482. {
  483. throw new Exception(JText::_('JError_Core_Create_not_permitted'));
  484. }
  485. $table = $this->getTable();
  486. foreach ($pks as $pk)
  487. {
  488. if ($table->load($pk, true))
  489. {
  490. // Reset the id to create a new record.
  491. $table->id = 0;
  492. // Alter the title.
  493. $m = null;
  494. if (preg_match('#\((\d+)\)$#', $table->title, $m))
  495. {
  496. $table->title = preg_replace('#\(\d+\)$#', '('.($m[1] + 1).')', $table->title);
  497. }
  498. else
  499. {
  500. $table->title .= ' (2)';
  501. }
  502. if (!$table->check() || !$table->store()) {
  503. throw new Exception($table->getError());
  504. }
  505. // $query = 'SELECT menuid'
  506. // . ' FROM #__modules_menu'
  507. // . ' WHERE moduleid = '.(int) $pk
  508. // ;
  509. $query = new JQuery;
  510. $query->select('menuid');
  511. $query->from('#__modules_menu');
  512. $query->where('moduleid='.(int)$pk);
  513. $this->_db->setQuery((string)$query);
  514. $rows = $this->_db->loadResultArray();
  515. foreach ($rows as $menuid) {
  516. $tuples[] = '('.(int) $table->id.','.(int) $menuid.')';
  517. }
  518. }
  519. else
  520. {
  521. throw new Exception($table->getError());
  522. }
  523. }
  524. if (!empty($tuples))
  525. {
  526. // Module-Menu Mapping: Do it in one query
  527. $query = 'INSERT INTO #__modules_menu (moduleid,menuid) VALUES '.implode(',', $tuples);
  528. $this->_db->setQuery($query);
  529. if (!$this->_db->query()) {
  530. return JError::raiseWarning(500, $row->getError());
  531. }
  532. }
  533. return true;
  534. }
  535. /**
  536. * Method to adjust the ordering of a row.
  537. *
  538. * @param int The ID of the primary key to move.
  539. * @param integer Increment, usually +1 or -1
  540. * @return boolean False on failure or error, true otherwise.
  541. */
  542. public function reorder($pks, $delta = 0)
  543. {
  544. // Initialise variables.
  545. $user = JFactory::getUser();
  546. $table = $this->getTable();
  547. $pks = (array) $pks;
  548. $result = true;
  549. // Access checks.
  550. $allow = $user->authorise('core.edit', 'com_modules');
  551. if (!$allow)
  552. {
  553. $this->setError(JText::_('JError_Core_Edit_not_permitted'));
  554. return false;
  555. }
  556. foreach ($pks as $i => $pk)
  557. {
  558. $table->reset();
  559. if ($table->load($pk) && $this->checkout($pk))
  560. {
  561. $table->ordering += $delta;
  562. if (!$table->store())
  563. {
  564. $this->setError($table->getError());
  565. unset($pks[$i]);
  566. $result = false;
  567. }
  568. }
  569. else
  570. {
  571. $this->setError($table->getError());
  572. unset($pks[$i]);
  573. $result = false;
  574. }
  575. }
  576. return $result;
  577. }
  578. /**
  579. * Saves the manually set order of records.
  580. *
  581. * @param array An array of primary key ids.
  582. * @param int +/-1
  583. */
  584. function saveorder($pks, $order)
  585. {
  586. // Initialise variables.
  587. $table = $this->getTable();
  588. $conditions = array();
  589. if (empty($pks)) {
  590. return JError::raiseWarning(500, JText::_('JError_No_items_selected'));
  591. }
  592. // update ordering values
  593. foreach ($pks as $i => $pk)
  594. {
  595. $table->load((int) $pk);
  596. // Access checks.
  597. $allow = $user->authorise('core.edit.state', 'com_modules');
  598. if (!$allow)
  599. {
  600. // Prune items that you can't change.
  601. unset($pks[$i]);
  602. JError::raiseWarning(403, JText::_('JError_Core_Edit_State_not_permitted'));
  603. }
  604. else if ($table->ordering != $order[$i])
  605. {
  606. $table->ordering = $order[$i];
  607. if (!$table->store())
  608. {
  609. $this->setError($table->getError());
  610. return false;
  611. }
  612. // remember to reorder within position and client_id
  613. $condition[] = 'client_id = '.(int) $table->client_id;
  614. $condition[] = 'position = '.(int) $table->position;
  615. $found = false;
  616. foreach ($conditions as $cond)
  617. {
  618. if ($cond[1] == $condition)
  619. {
  620. $found = true;
  621. break;
  622. }
  623. }
  624. if (!$found) {
  625. $conditions[] = array ($table->id, $condition);
  626. }
  627. }
  628. }
  629. // Execute reorder for each category.
  630. foreach ($conditions as $cond)
  631. {
  632. $table->load($cond[0]);
  633. $table->reorder($cond[1]);
  634. }
  635. // Clear the component's cache
  636. $cache = JFactory::getCache('com_modules');
  637. $cache->clean();
  638. return true;
  639. }
  640. }