PageRenderTime 32ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 1ms

/libraries/joomla/application/component/modeladmin.php

http://github.com/joomla/joomla-platform
PHP | 1124 lines | 644 code | 150 blank | 330 comment | 82 complexity | 5aca934e913b400a9662b53e91c3ce30 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. <?php
  2. /**
  3. * @package Joomla.Platform
  4. * @subpackage Application
  5. *
  6. * @copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
  7. * @license GNU General Public License version 2 or later; see LICENSE
  8. */
  9. defined('JPATH_PLATFORM') or die;
  10. jimport('joomla.application.component.modelform');
  11. /**
  12. * Prototype admin model.
  13. *
  14. * @package Joomla.Platform
  15. * @subpackage Application
  16. * @since 11.1
  17. */
  18. abstract class JModelAdmin extends JModelForm
  19. {
  20. /**
  21. * The prefix to use with controller messages.
  22. *
  23. * @var string
  24. * @since 11.1
  25. */
  26. protected $text_prefix = null;
  27. /**
  28. * The event to trigger after deleting the data.
  29. *
  30. * @var string
  31. * @since 11.1
  32. */
  33. protected $event_after_delete = null;
  34. /**
  35. * The event to trigger after saving the data.
  36. *
  37. * @var string
  38. * @since 11.1
  39. */
  40. protected $event_after_save = null;
  41. /**
  42. * The event to trigger before deleting the data.
  43. *
  44. * @var string
  45. * @since 11.1
  46. */
  47. protected $event_before_delete = null;
  48. /**
  49. * The event to trigger before saving the data.
  50. *
  51. * @var string
  52. * @since 11.1
  53. */
  54. protected $event_before_save = null;
  55. /**
  56. * The event to trigger after changing the published state of the data.
  57. *
  58. * @var string
  59. * @since 11.1
  60. */
  61. protected $event_change_state = null;
  62. /**
  63. * Constructor.
  64. *
  65. * @param array $config An optional associative array of configuration settings.
  66. *
  67. * @see JController
  68. * @since 11.1
  69. */
  70. public function __construct($config = array())
  71. {
  72. parent::__construct($config);
  73. if (isset($config['event_after_delete']))
  74. {
  75. $this->event_after_delete = $config['event_after_delete'];
  76. }
  77. elseif (empty($this->event_after_delete))
  78. {
  79. $this->event_after_delete = 'onContentAfterDelete';
  80. }
  81. if (isset($config['event_after_save']))
  82. {
  83. $this->event_after_save = $config['event_after_save'];
  84. }
  85. elseif (empty($this->event_after_save))
  86. {
  87. $this->event_after_save = 'onContentAfterSave';
  88. }
  89. if (isset($config['event_before_delete']))
  90. {
  91. $this->event_before_delete = $config['event_before_delete'];
  92. }
  93. elseif (empty($this->event_before_delete))
  94. {
  95. $this->event_before_delete = 'onContentBeforeDelete';
  96. }
  97. if (isset($config['event_before_save']))
  98. {
  99. $this->event_before_save = $config['event_before_save'];
  100. }
  101. elseif (empty($this->event_before_save))
  102. {
  103. $this->event_before_save = 'onContentBeforeSave';
  104. }
  105. if (isset($config['event_change_state']))
  106. {
  107. $this->event_change_state = $config['event_change_state'];
  108. }
  109. elseif (empty($this->event_change_state))
  110. {
  111. $this->event_change_state = 'onContentChangeState';
  112. }
  113. // Guess the JText message prefix. Defaults to the option.
  114. if (isset($config['text_prefix']))
  115. {
  116. $this->text_prefix = strtoupper($config['text_prefix']);
  117. }
  118. elseif (empty($this->text_prefix))
  119. {
  120. $this->text_prefix = strtoupper($this->option);
  121. }
  122. }
  123. /**
  124. * Method to perform batch operations on an item or a set of items.
  125. *
  126. * @param array $commands An array of commands to perform.
  127. * @param array $pks An array of item ids.
  128. * @param array $contexts An array of item contexts.
  129. *
  130. * @return boolean Returns true on success, false on failure.
  131. *
  132. * @since 11.1
  133. */
  134. public function batch($commands, $pks, $contexts)
  135. {
  136. // Sanitize user ids.
  137. $pks = array_unique($pks);
  138. JArrayHelper::toInteger($pks);
  139. // Remove any values of zero.
  140. if (array_search(0, $pks, true))
  141. {
  142. unset($pks[array_search(0, $pks, true)]);
  143. }
  144. if (empty($pks))
  145. {
  146. $this->setError(JText::_('JGLOBAL_NO_ITEM_SELECTED'));
  147. return false;
  148. }
  149. $done = false;
  150. if (!empty($commands['category_id']))
  151. {
  152. $cmd = JArrayHelper::getValue($commands, 'move_copy', 'c');
  153. if ($cmd == 'c')
  154. {
  155. $result = $this->batchCopy($commands['category_id'], $pks, $contexts);
  156. if (is_array($result))
  157. {
  158. $pks = $result;
  159. }
  160. else
  161. {
  162. return false;
  163. }
  164. }
  165. elseif ($cmd == 'm' && !$this->batchMove($commands['category_id'], $pks, $contexts))
  166. {
  167. return false;
  168. }
  169. $done = true;
  170. }
  171. if (!empty($commands['assetgroup_id']))
  172. {
  173. if (!$this->batchAccess($commands['assetgroup_id'], $pks, $contexts))
  174. {
  175. return false;
  176. }
  177. $done = true;
  178. }
  179. if (!empty($commands['language_id']))
  180. {
  181. if (!$this->batchLanguage($commands['language_id'], $pks, $contexts))
  182. {
  183. return false;
  184. }
  185. $done = true;
  186. }
  187. if (!$done)
  188. {
  189. $this->setError(JText::_('JLIB_APPLICATION_ERROR_INSUFFICIENT_BATCH_INFORMATION'));
  190. return false;
  191. }
  192. // Clear the cache
  193. $this->cleanCache();
  194. return true;
  195. }
  196. /**
  197. * Batch access level changes for a group of rows.
  198. *
  199. * @param integer $value The new value matching an Asset Group ID.
  200. * @param array $pks An array of row IDs.
  201. * @param array $contexts An array of item contexts.
  202. *
  203. * @return boolean True if successful, false otherwise and internal error is set.
  204. *
  205. * @since 11.1
  206. */
  207. protected function batchAccess($value, $pks, $contexts)
  208. {
  209. // Set the variables
  210. $user = JFactory::getUser();
  211. $table = $this->getTable();
  212. foreach ($pks as $pk)
  213. {
  214. if ($user->authorise('core.edit', $contexts[$pk]))
  215. {
  216. $table->reset();
  217. $table->load($pk);
  218. $table->access = (int) $value;
  219. if (!$table->store())
  220. {
  221. $this->setError($table->getError());
  222. return false;
  223. }
  224. }
  225. else
  226. {
  227. $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_EDIT'));
  228. return false;
  229. }
  230. }
  231. // Clean the cache
  232. $this->cleanCache();
  233. return true;
  234. }
  235. /**
  236. * Batch copy items to a new category or current.
  237. *
  238. * @param integer $value The new category.
  239. * @param array $pks An array of row IDs.
  240. * @param array $contexts An array of item contexts.
  241. *
  242. * @return mixed An array of new IDs on success, boolean false on failure.
  243. *
  244. * @since 11.1
  245. */
  246. protected function batchCopy($value, $pks, $contexts)
  247. {
  248. $categoryId = (int) $value;
  249. $table = $this->getTable();
  250. $i = 0;
  251. // Check that the category exists
  252. if ($categoryId)
  253. {
  254. $categoryTable = JTable::getInstance('Category');
  255. if (!$categoryTable->load($categoryId))
  256. {
  257. if ($error = $categoryTable->getError())
  258. {
  259. // Fatal error
  260. $this->setError($error);
  261. return false;
  262. }
  263. else
  264. {
  265. $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_MOVE_CATEGORY_NOT_FOUND'));
  266. return false;
  267. }
  268. }
  269. }
  270. if (empty($categoryId))
  271. {
  272. $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_MOVE_CATEGORY_NOT_FOUND'));
  273. return false;
  274. }
  275. // Check that the user has create permission for the component
  276. $extension = JFactory::getApplication()->input->get('option', '');
  277. $user = JFactory::getUser();
  278. if (!$user->authorise('core.create', $extension . '.category.' . $categoryId))
  279. {
  280. $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_CREATE'));
  281. return false;
  282. }
  283. // Parent exists so we let's proceed
  284. while (!empty($pks))
  285. {
  286. // Pop the first ID off the stack
  287. $pk = array_shift($pks);
  288. $table->reset();
  289. // Check that the row actually exists
  290. if (!$table->load($pk))
  291. {
  292. if ($error = $table->getError())
  293. {
  294. // Fatal error
  295. $this->setError($error);
  296. return false;
  297. }
  298. else
  299. {
  300. // Not fatal error
  301. $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_BATCH_MOVE_ROW_NOT_FOUND', $pk));
  302. continue;
  303. }
  304. }
  305. // Alter the title & alias
  306. $data = $this->generateNewTitle($categoryId, $table->alias, $table->title);
  307. $table->title = $data['0'];
  308. $table->alias = $data['1'];
  309. // Reset the ID because we are making a copy
  310. $table->id = 0;
  311. // New category ID
  312. $table->catid = $categoryId;
  313. // TODO: Deal with ordering?
  314. // $table->ordering = 1;
  315. // Check the row.
  316. if (!$table->check())
  317. {
  318. $this->setError($table->getError());
  319. return false;
  320. }
  321. // Store the row.
  322. if (!$table->store())
  323. {
  324. $this->setError($table->getError());
  325. return false;
  326. }
  327. // Get the new item ID
  328. $newId = $table->get('id');
  329. // Add the new ID to the array
  330. $newIds[$i] = $newId;
  331. $i++;
  332. }
  333. // Clean the cache
  334. $this->cleanCache();
  335. return $newIds;
  336. }
  337. /**
  338. * Batch language changes for a group of rows.
  339. *
  340. * @param string $value The new value matching a language.
  341. * @param array $pks An array of row IDs.
  342. * @param array $contexts An array of item contexts.
  343. *
  344. * @return boolean True if successful, false otherwise and internal error is set.
  345. *
  346. * @since 11.3
  347. */
  348. protected function batchLanguage($value, $pks, $contexts)
  349. {
  350. // Set the variables
  351. $user = JFactory::getUser();
  352. $table = $this->getTable();
  353. foreach ($pks as $pk)
  354. {
  355. if ($user->authorise('core.edit', $contexts[$pk]))
  356. {
  357. $table->reset();
  358. $table->load($pk);
  359. $table->language = $value;
  360. if (!$table->store())
  361. {
  362. $this->setError($table->getError());
  363. return false;
  364. }
  365. }
  366. else
  367. {
  368. $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_EDIT'));
  369. return false;
  370. }
  371. }
  372. // Clean the cache
  373. $this->cleanCache();
  374. return true;
  375. }
  376. /**
  377. * Batch move items to a new category
  378. *
  379. * @param integer $value The new category ID.
  380. * @param array $pks An array of row IDs.
  381. * @param array $contexts An array of item contexts.
  382. *
  383. * @return boolean True if successful, false otherwise and internal error is set.
  384. *
  385. * @since 11.1
  386. */
  387. protected function batchMove($value, $pks, $contexts)
  388. {
  389. $categoryId = (int) $value;
  390. $table = $this->getTable();
  391. // Check that the category exists
  392. if ($categoryId)
  393. {
  394. $categoryTable = JTable::getInstance('Category');
  395. if (!$categoryTable->load($categoryId))
  396. {
  397. if ($error = $categoryTable->getError())
  398. {
  399. // Fatal error
  400. $this->setError($error);
  401. return false;
  402. }
  403. else
  404. {
  405. $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_MOVE_CATEGORY_NOT_FOUND'));
  406. return false;
  407. }
  408. }
  409. }
  410. if (empty($categoryId))
  411. {
  412. $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_MOVE_CATEGORY_NOT_FOUND'));
  413. return false;
  414. }
  415. // Check that user has create and edit permission for the component
  416. $extension = JFactory::getApplication()->input->get('option', '');
  417. $user = JFactory::getUser();
  418. if (!$user->authorise('core.create', $extension . '.category.' . $categoryId))
  419. {
  420. $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_CREATE'));
  421. return false;
  422. }
  423. // Parent exists so we let's proceed
  424. foreach ($pks as $pk)
  425. {
  426. if (!$user->authorise('core.edit', $contexts[$pk]))
  427. {
  428. $this->setError(JText::_('JLIB_APPLICATION_ERROR_BATCH_CANNOT_EDIT'));
  429. return false;
  430. }
  431. // Check that the row actually exists
  432. if (!$table->load($pk))
  433. {
  434. if ($error = $table->getError())
  435. {
  436. // Fatal error
  437. $this->setError($error);
  438. return false;
  439. }
  440. else
  441. {
  442. // Not fatal error
  443. $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_BATCH_MOVE_ROW_NOT_FOUND', $pk));
  444. continue;
  445. }
  446. }
  447. // Set the new category ID
  448. $table->catid = $categoryId;
  449. // Check the row.
  450. if (!$table->check())
  451. {
  452. $this->setError($table->getError());
  453. return false;
  454. }
  455. // Store the row.
  456. if (!$table->store())
  457. {
  458. $this->setError($table->getError());
  459. return false;
  460. }
  461. }
  462. // Clean the cache
  463. $this->cleanCache();
  464. return true;
  465. }
  466. /**
  467. * Method to test whether a record can be deleted.
  468. *
  469. * @param object $record A record object.
  470. *
  471. * @return boolean True if allowed to delete the record. Defaults to the permission for the component.
  472. *
  473. * @since 11.1
  474. */
  475. protected function canDelete($record)
  476. {
  477. $user = JFactory::getUser();
  478. return $user->authorise('core.delete', $this->option);
  479. }
  480. /**
  481. * Method to test whether a record can be deleted.
  482. *
  483. * @param object $record A record object.
  484. *
  485. * @return boolean True if allowed to change the state of the record. Defaults to the permission for the component.
  486. *
  487. * @since 11.1
  488. */
  489. protected function canEditState($record)
  490. {
  491. $user = JFactory::getUser();
  492. return $user->authorise('core.edit.state', $this->option);
  493. }
  494. /**
  495. * Method override to check-in a record or an array of record
  496. *
  497. * @param mixed $pks The ID of the primary key or an array of IDs
  498. *
  499. * @return mixed Boolean false if there is an error, otherwise the count of records checked in.
  500. *
  501. * @since 11.1
  502. */
  503. public function checkin($pks = array())
  504. {
  505. // Initialise variables.
  506. $pks = (array) $pks;
  507. $table = $this->getTable();
  508. $count = 0;
  509. if (empty($pks))
  510. {
  511. $pks = array((int) $this->getState($this->getName() . '.id'));
  512. }
  513. // Check in all items.
  514. foreach ($pks as $pk)
  515. {
  516. if ($table->load($pk))
  517. {
  518. if ($table->checked_out > 0)
  519. {
  520. if (!parent::checkin($pk))
  521. {
  522. return false;
  523. }
  524. $count++;
  525. }
  526. }
  527. else
  528. {
  529. $this->setError($table->getError());
  530. return false;
  531. }
  532. }
  533. return $count;
  534. }
  535. /**
  536. * Method override to check-out a record.
  537. *
  538. * @param integer $pk The ID of the primary key.
  539. *
  540. * @return boolean True if successful, false if an error occurs.
  541. *
  542. * @since 11.1
  543. */
  544. public function checkout($pk = null)
  545. {
  546. // Initialise variables.
  547. $pk = (!empty($pk)) ? $pk : (int) $this->getState($this->getName() . '.id');
  548. return parent::checkout($pk);
  549. }
  550. /**
  551. * Method to delete one or more records.
  552. *
  553. * @param array &$pks An array of record primary keys.
  554. *
  555. * @return boolean True if successful, false if an error occurs.
  556. *
  557. * @since 11.1
  558. */
  559. public function delete(&$pks)
  560. {
  561. // Initialise variables.
  562. $dispatcher = JDispatcher::getInstance();
  563. $pks = (array) $pks;
  564. $table = $this->getTable();
  565. // Include the content plugins for the on delete events.
  566. JPluginHelper::importPlugin('content');
  567. // Iterate the items to delete each one.
  568. foreach ($pks as $i => $pk)
  569. {
  570. if ($table->load($pk))
  571. {
  572. if ($this->canDelete($table))
  573. {
  574. $context = $this->option . '.' . $this->name;
  575. // Trigger the onContentBeforeDelete event.
  576. $result = $dispatcher->trigger($this->event_before_delete, array($context, $table));
  577. if (in_array(false, $result, true))
  578. {
  579. $this->setError($table->getError());
  580. return false;
  581. }
  582. if (!$table->delete($pk))
  583. {
  584. $this->setError($table->getError());
  585. return false;
  586. }
  587. // Trigger the onContentAfterDelete event.
  588. $dispatcher->trigger($this->event_after_delete, array($context, $table));
  589. }
  590. else
  591. {
  592. // Prune items that you can't change.
  593. unset($pks[$i]);
  594. $error = $this->getError();
  595. if ($error)
  596. {
  597. JError::raiseWarning(500, $error);
  598. return false;
  599. }
  600. else
  601. {
  602. JError::raiseWarning(403, JText::_('JLIB_APPLICATION_ERROR_DELETE_NOT_PERMITTED'));
  603. return false;
  604. }
  605. }
  606. }
  607. else
  608. {
  609. $this->setError($table->getError());
  610. return false;
  611. }
  612. }
  613. // Clear the component's cache
  614. $this->cleanCache();
  615. return true;
  616. }
  617. /**
  618. * Method to change the title & alias.
  619. *
  620. * @param integer $category_id The id of the category.
  621. * @param string $alias The alias.
  622. * @param string $title The title.
  623. *
  624. * @return array Contains the modified title and alias.
  625. *
  626. * @since 11.1
  627. */
  628. protected function generateNewTitle($category_id, $alias, $title)
  629. {
  630. // Alter the title & alias
  631. $table = $this->getTable();
  632. while ($table->load(array('alias' => $alias, 'catid' => $category_id)))
  633. {
  634. $title = JString::increment($title);
  635. $alias = JString::increment($alias, 'dash');
  636. }
  637. return array($title, $alias);
  638. }
  639. /**
  640. * Method to get a single record.
  641. *
  642. * @param integer $pk The id of the primary key.
  643. *
  644. * @return mixed Object on success, false on failure.
  645. *
  646. * @since 11.1
  647. */
  648. public function getItem($pk = null)
  649. {
  650. // Initialise variables.
  651. $pk = (!empty($pk)) ? $pk : (int) $this->getState($this->getName() . '.id');
  652. $table = $this->getTable();
  653. if ($pk > 0)
  654. {
  655. // Attempt to load the row.
  656. $return = $table->load($pk);
  657. // Check for a table object error.
  658. if ($return === false && $table->getError())
  659. {
  660. $this->setError($table->getError());
  661. return false;
  662. }
  663. }
  664. // Convert to the JObject before adding other data.
  665. $properties = $table->getProperties(1);
  666. $item = JArrayHelper::toObject($properties, 'JObject');
  667. if (property_exists($item, 'params'))
  668. {
  669. $registry = new JRegistry;
  670. $registry->loadString($item->params);
  671. $item->params = $registry->toArray();
  672. }
  673. return $item;
  674. }
  675. /**
  676. * A protected method to get a set of ordering conditions.
  677. *
  678. * @param object $table A JTable object.
  679. *
  680. * @return array An array of conditions to add to ordering queries.
  681. *
  682. * @since 11.1
  683. */
  684. protected function getReorderConditions($table)
  685. {
  686. return array();
  687. }
  688. /**
  689. * Stock method to auto-populate the model state.
  690. *
  691. * @return void
  692. *
  693. * @since 11.1
  694. */
  695. protected function populateState()
  696. {
  697. // Initialise variables.
  698. $table = $this->getTable();
  699. $key = $table->getKeyName();
  700. // Get the pk of the record from the request.
  701. $pk = JRequest::getInt($key);
  702. $this->setState($this->getName() . '.id', $pk);
  703. // Load the parameters.
  704. $value = JComponentHelper::getParams($this->option);
  705. $this->setState('params', $value);
  706. }
  707. /**
  708. * Prepare and sanitise the table data prior to saving.
  709. *
  710. * @param JTable &$table A reference to a JTable object.
  711. *
  712. * @return void
  713. *
  714. * @since 11.1
  715. */
  716. protected function prepareTable(&$table)
  717. {
  718. // Derived class will provide its own implementation if required.
  719. }
  720. /**
  721. * Method to change the published state of one or more records.
  722. *
  723. * @param array &$pks A list of the primary keys to change.
  724. * @param integer $value The value of the published state.
  725. *
  726. * @return boolean True on success.
  727. *
  728. * @since 11.1
  729. */
  730. public function publish(&$pks, $value = 1)
  731. {
  732. // Initialise variables.
  733. $dispatcher = JDispatcher::getInstance();
  734. $user = JFactory::getUser();
  735. $table = $this->getTable();
  736. $pks = (array) $pks;
  737. // Include the content plugins for the change of state event.
  738. JPluginHelper::importPlugin('content');
  739. // Access checks.
  740. foreach ($pks as $i => $pk)
  741. {
  742. $table->reset();
  743. if ($table->load($pk))
  744. {
  745. if (!$this->canEditState($table))
  746. {
  747. // Prune items that you can't change.
  748. unset($pks[$i]);
  749. JError::raiseWarning(403, JText::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED'));
  750. return false;
  751. }
  752. }
  753. }
  754. // Attempt to change the state of the records.
  755. if (!$table->publish($pks, $value, $user->get('id')))
  756. {
  757. $this->setError($table->getError());
  758. return false;
  759. }
  760. $context = $this->option . '.' . $this->name;
  761. // Trigger the onContentChangeState event.
  762. $result = $dispatcher->trigger($this->event_change_state, array($context, $pks, $value));
  763. if (in_array(false, $result, true))
  764. {
  765. $this->setError($table->getError());
  766. return false;
  767. }
  768. // Clear the component's cache
  769. $this->cleanCache();
  770. return true;
  771. }
  772. /**
  773. * Method to adjust the ordering of a row.
  774. *
  775. * Returns NULL if the user did not have edit
  776. * privileges for any of the selected primary keys.
  777. *
  778. * @param integer $pks The ID of the primary key to move.
  779. * @param integer $delta Increment, usually +1 or -1
  780. *
  781. * @return mixed False on failure or error, true on success, null if the $pk is empty (no items selected).
  782. *
  783. * @since 11.1
  784. */
  785. public function reorder($pks, $delta = 0)
  786. {
  787. // Initialise variables.
  788. $table = $this->getTable();
  789. $pks = (array) $pks;
  790. $result = true;
  791. $allowed = true;
  792. foreach ($pks as $i => $pk)
  793. {
  794. $table->reset();
  795. if ($table->load($pk) && $this->checkout($pk))
  796. {
  797. // Access checks.
  798. if (!$this->canEditState($table))
  799. {
  800. // Prune items that you can't change.
  801. unset($pks[$i]);
  802. $this->checkin($pk);
  803. JError::raiseWarning(403, JText::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED'));
  804. $allowed = false;
  805. continue;
  806. }
  807. $where = array();
  808. $where = $this->getReorderConditions($table);
  809. if (!$table->move($delta, $where))
  810. {
  811. $this->setError($table->getError());
  812. unset($pks[$i]);
  813. $result = false;
  814. }
  815. $this->checkin($pk);
  816. }
  817. else
  818. {
  819. $this->setError($table->getError());
  820. unset($pks[$i]);
  821. $result = false;
  822. }
  823. }
  824. if ($allowed === false && empty($pks))
  825. {
  826. $result = null;
  827. }
  828. // Clear the component's cache
  829. if ($result == true)
  830. {
  831. $this->cleanCache();
  832. }
  833. return $result;
  834. }
  835. /**
  836. * Method to save the form data.
  837. *
  838. * @param array $data The form data.
  839. *
  840. * @return boolean True on success, False on error.
  841. *
  842. * @since 11.1
  843. */
  844. public function save($data)
  845. {
  846. // Initialise variables;
  847. $dispatcher = JDispatcher::getInstance();
  848. $table = $this->getTable();
  849. $key = $table->getKeyName();
  850. $pk = (!empty($data[$key])) ? $data[$key] : (int) $this->getState($this->getName() . '.id');
  851. $isNew = true;
  852. // Include the content plugins for the on save events.
  853. JPluginHelper::importPlugin('content');
  854. // Allow an exception to be thrown.
  855. try
  856. {
  857. // Load the row if saving an existing record.
  858. if ($pk > 0)
  859. {
  860. $table->load($pk);
  861. $isNew = false;
  862. }
  863. // Bind the data.
  864. if (!$table->bind($data))
  865. {
  866. $this->setError($table->getError());
  867. return false;
  868. }
  869. // Prepare the row for saving
  870. $this->prepareTable($table);
  871. // Check the data.
  872. if (!$table->check())
  873. {
  874. $this->setError($table->getError());
  875. return false;
  876. }
  877. // Trigger the onContentBeforeSave event.
  878. $result = $dispatcher->trigger($this->event_before_save, array($this->option . '.' . $this->name, &$table, $isNew));
  879. if (in_array(false, $result, true))
  880. {
  881. $this->setError($table->getError());
  882. return false;
  883. }
  884. // Store the data.
  885. if (!$table->store())
  886. {
  887. $this->setError($table->getError());
  888. return false;
  889. }
  890. // Clean the cache.
  891. $this->cleanCache();
  892. // Trigger the onContentAfterSave event.
  893. $dispatcher->trigger($this->event_after_save, array($this->option . '.' . $this->name, &$table, $isNew));
  894. }
  895. catch (Exception $e)
  896. {
  897. $this->setError($e->getMessage());
  898. return false;
  899. }
  900. $pkName = $table->getKeyName();
  901. if (isset($table->$pkName))
  902. {
  903. $this->setState($this->getName() . '.id', $table->$pkName);
  904. }
  905. $this->setState($this->getName() . '.new', $isNew);
  906. return true;
  907. }
  908. /**
  909. * Saves the manually set order of records.
  910. *
  911. * @param array $pks An array of primary key ids.
  912. * @param integer $order +1 or -1
  913. *
  914. * @return mixed
  915. *
  916. * @since 11.1
  917. */
  918. public function saveorder($pks = null, $order = null)
  919. {
  920. // Initialise variables.
  921. $table = $this->getTable();
  922. $conditions = array();
  923. if (empty($pks))
  924. {
  925. return JError::raiseWarning(500, JText::_($this->text_prefix . '_ERROR_NO_ITEMS_SELECTED'));
  926. }
  927. // Update ordering values
  928. foreach ($pks as $i => $pk)
  929. {
  930. $table->load((int) $pk);
  931. // Access checks.
  932. if (!$this->canEditState($table))
  933. {
  934. // Prune items that you can't change.
  935. unset($pks[$i]);
  936. JError::raiseWarning(403, JText::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED'));
  937. }
  938. elseif ($table->ordering != $order[$i])
  939. {
  940. $table->ordering = $order[$i];
  941. if (!$table->store())
  942. {
  943. $this->setError($table->getError());
  944. return false;
  945. }
  946. // Remember to reorder within position and client_id
  947. $condition = $this->getReorderConditions($table);
  948. $found = false;
  949. foreach ($conditions as $cond)
  950. {
  951. if ($cond[1] == $condition)
  952. {
  953. $found = true;
  954. break;
  955. }
  956. }
  957. if (!$found)
  958. {
  959. $key = $table->getKeyName();
  960. $conditions[] = array($table->$key, $condition);
  961. }
  962. }
  963. }
  964. // Execute reorder for each category.
  965. foreach ($conditions as $cond)
  966. {
  967. $table->load($cond[0]);
  968. $table->reorder($cond[1]);
  969. }
  970. // Clear the component's cache
  971. $this->cleanCache();
  972. return true;
  973. }
  974. }