/libraries/cms/table/contenthistory.php

https://github.com/elinw/joomla-cms · PHP · 183 lines · 94 code · 19 blank · 70 comment · 9 complexity · 4446c037c00291ceff8f0c95f0000a7c MD5 · raw file

  1. <?php
  2. /**
  3. * @package Joomla.Libraries
  4. * @subpackage Table
  5. *
  6. * @copyright Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
  7. * @license GNU General Public License version 2 or later; see LICENSE.txt
  8. */
  9. defined('_JEXEC') or die;
  10. /**
  11. * Content History table.
  12. *
  13. * @package Joomla.Libraries
  14. * @subpackage Table
  15. * @since 3.2
  16. */
  17. class JTableContenthistory extends JTable
  18. {
  19. /**
  20. * Array of object fields to unset from the data object before calculating SHA1 hash. This allows us to detect a meaningful change
  21. * in the database row using the hash.
  22. *
  23. * @var array
  24. * @since 3.2
  25. */
  26. public $ignoreChanges = array();
  27. /**
  28. * Constructor
  29. *
  30. * @param JDatabaseDriver $db A database connector object
  31. *
  32. * @since 3.1
  33. */
  34. public function __construct($db)
  35. {
  36. parent::__construct('#__ucm_history', 'version_id', $db);
  37. $this->ignoreChanges = array('modified', 'modified_time', 'checked_out_time', 'version', 'hits');
  38. }
  39. /**
  40. * Overrides JTable::store to set modified hash, user id, and save date.
  41. *
  42. * @param boolean $updateNulls True to update fields even if they are null.
  43. *
  44. * @return boolean True on success.
  45. *
  46. * @since 3.2
  47. */
  48. public function store($updateNulls = false)
  49. {
  50. $this->set('character_count', strlen($this->get('version_data')));
  51. if (!isset($this->sha1_hash))
  52. {
  53. $this->set('sha1_hash', $this->getSha1($this->get('version_data')));
  54. }
  55. $this->set('editor_user_id', JFactory::getUser()->id);
  56. $this->set('save_date', JFactory::getDate()->toSql());
  57. return parent::store($updateNulls);
  58. }
  59. /**
  60. * Utility method to get the hash after removing selected values. This lets us detect changes other than
  61. * modified date (which will change on every save).
  62. *
  63. * @param mixed $jsonData Either an object or a string with json-encoded data
  64. *
  65. * @return string SHA1 hash on sucess. Empty string on failure.
  66. *
  67. * @since 3.2
  68. */
  69. public function getSha1($jsonData)
  70. {
  71. $object = (is_object($jsonData)) ? $jsonData : json_decode($jsonData);
  72. foreach ($this->ignoreChanges as $remove)
  73. {
  74. if (isset($object->$remove))
  75. {
  76. unset($object->$remove);
  77. }
  78. }
  79. // Convert integers and booleans to strings to get a consistent hash value
  80. foreach ($object as $name => $value)
  81. {
  82. if (is_object($value))
  83. {
  84. // Go one level down for JSON column values
  85. foreach ($value as $subName => $subValue)
  86. {
  87. $object->$subName = (is_int($subValue) || is_bool($subValue)) ? (string) $subValue : $subValue;
  88. }
  89. }
  90. else
  91. {
  92. $object->$name = (is_int($value) || is_bool($value)) ? (string) $value : $value;
  93. }
  94. }
  95. // Work around empty publish_up, publish_down values
  96. if (isset($object->publish_down))
  97. {
  98. $object->publish_down = (int) $object->publish_down;
  99. }
  100. if (isset($object->publish_up))
  101. {
  102. $object->publish_up = (int) $object->publish_up;
  103. }
  104. return sha1(json_encode($object));
  105. }
  106. /**
  107. * Utility method to get a matching row based on the hash value and id columns.
  108. * This lets us check to make sure we don't save duplicate versions.
  109. *
  110. * @return string SHA1 hash on sucess. Empty string on failure.
  111. *
  112. * @since 3.2
  113. */
  114. public function getHashMatch()
  115. {
  116. $db = $this->_db;
  117. $query = $db->getQuery(true);
  118. $query->select('*')
  119. ->from($db->quoteName('#__ucm_history'))
  120. ->where($db->quoteName('ucm_item_id') . ' = ' . $this->get('ucm_item_id'))
  121. ->where($db->quoteName('ucm_type_id') . ' = ' . $this->get('ucm_type_id'))
  122. ->where($db->quoteName('sha1_hash') . ' = ' . $db->quote($this->get('sha1_hash')));
  123. $db->setQuery($query, 0, 1);
  124. return $db->loadObject();
  125. }
  126. /**
  127. * Utility method to remove the oldest versions of an item, saving only the most recent versions.
  128. *
  129. * @param integer $maxVersions The maximum number of versions to save. All others will be deleted.
  130. *
  131. * @return boolean true on sucess, false on failure.
  132. *
  133. * @since 3.2
  134. */
  135. public function deleteOldVersions($maxVersions)
  136. {
  137. $result = true;
  138. // Get the list of version_id values we want to save
  139. $db = $this->_db;
  140. $query = $db->getQuery(true);
  141. $query->select($db->quoteName('version_id'))
  142. ->from($db->quoteName('#__ucm_history'))
  143. ->where($db->quoteName('ucm_item_id') . ' = ' . (int) $this->ucm_item_id)
  144. ->where($db->quoteName('ucm_type_id') . ' = ' . (int) $this->ucm_type_id)
  145. ->where($db->quoteName('keep_forever') . ' != 1')
  146. ->order($db->quoteName('save_date') . ' DESC ');
  147. $db->setQuery($query, 0, (int) $maxVersions);
  148. $idsToSave = $db->loadColumn(0);
  149. // Don't process delete query unless we have at least the maximum allowed versions
  150. if (count($idsToSave) == (int) $maxVersions)
  151. {
  152. // Delete any rows not in our list and and not flagged to keep forever.
  153. $query = $db->getQuery(true);
  154. $query->delete($db->quoteName('#__ucm_history'))
  155. ->where($db->quoteName('ucm_item_id') . ' = ' . (int) $this->ucm_item_id)
  156. ->where($db->quoteName('ucm_type_id') . ' = ' . (int) $this->ucm_type_id)
  157. ->where($db->quoteName('version_id') . ' NOT IN (' . implode(',', $idsToSave) . ')')
  158. ->where($db->quoteName('keep_forever') . ' != 1');
  159. $db->setQuery($query);
  160. $result = (boolean) $db->execute();
  161. }
  162. return $result;
  163. }
  164. }