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

/libraries/legacy/model/admin.php

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