PageRenderTime 35ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/tine20/Expressomail/Controller/Message/Move.php

https://gitlab.com/rsilveira1987/Expresso
PHP | 299 lines | 166 code | 35 blank | 98 comment | 33 complexity | 862ba9186d753c04b314887d294a5af1 MD5 | raw file
  1. <?php
  2. /**
  3. * Tine 2.0
  4. *
  5. * @package Expressomail
  6. * @subpackage Controller
  7. * @license http://www.gnu.org/licenses/agpl.html AGPL Version 3
  8. * @author Philipp Schüle <p.schuele@metaways.de>
  9. * @copyright Copyright (c) 2011 Metaways Infosystems GmbH (http://www.metaways.de)
  10. */
  11. /**
  12. * message flags controller for Expressomail
  13. *
  14. * @package Expressomail
  15. * @subpackage Controller
  16. */
  17. class Expressomail_Controller_Message_Move extends Expressomail_Controller_Message
  18. {
  19. /**
  20. * holds the instance of the singleton
  21. *
  22. * @var Expressomail_Controller_Message_Move
  23. */
  24. private static $_instance = NULL;
  25. /**
  26. * the constructor
  27. *
  28. * don't use the constructor. use the singleton
  29. */
  30. private function __construct()
  31. {
  32. $this->_backend = new Expressomail_Backend_Message();
  33. }
  34. /**
  35. * don't clone. Use the singleton.
  36. *
  37. */
  38. private function __clone()
  39. {
  40. }
  41. /**
  42. * the singleton pattern
  43. *
  44. * @return Expressomail_Controller_Message_Move
  45. */
  46. public static function getInstance()
  47. {
  48. if (self::$_instance === NULL) {
  49. self::$_instance = new Expressomail_Controller_Message_Move();
  50. }
  51. return self::$_instance;
  52. }
  53. /**
  54. * move messages to folder
  55. *
  56. * @param mixed $_messages
  57. * @param mixed $_targetFolder can be one of: folder_id, Expressomail_Model_Folder or Expressomail_Model_Folder::FOLDER_TRASH (constant)
  58. * @return Tinebase_Record_RecordSet of Expressomail_Model_Folder
  59. */
  60. public function moveMessages($_messages, $_targetFolder)
  61. {
  62. if ($_targetFolder !== Expressomail_Model_Folder::FOLDER_TRASH) {
  63. $targetFolder = ($_targetFolder instanceof Expressomail_Model_Folder) ? $_targetFolder : Expressomail_Controller_Folder::getInstance()->get($_targetFolder);
  64. } else {
  65. $targetFolder = $_targetFolder;
  66. }
  67. if ($_messages instanceof Tinebase_Model_Filter_FilterGroup) {
  68. $iterator = new Tinebase_Record_Iterator(array(
  69. 'iteratable' => $this,
  70. 'controller' => $this,
  71. 'filter' => $_messages,
  72. 'function' => 'processMoveIteration',
  73. ));
  74. $iterateResult = $iterator->iterate($targetFolder);
  75. if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
  76. . ' Moved ' . $iterateResult['totalcount'] . ' message(s).');
  77. // @todo return all results?
  78. $result = (! empty($iterateResult['results'])) ? array_pop($iterateResult['results']) : new Tinebase_Record_RecordSet('Expressomail_Model_Folder');
  79. } else {
  80. $messages = $this->_convertToRecordSet($_messages, TRUE);
  81. $result = $this->processMoveIteration($messages, $targetFolder);
  82. }
  83. return $result;
  84. }
  85. /**
  86. * move messages
  87. *
  88. * @param Tinebase_Record_RecordSet $_messages
  89. * @param mixed $_targetFolder can be one of: Expressomail_Model_Folder or Expressomail_Model_Folder::FOLDER_TRASH (constant)
  90. * @return Tinebase_Record_RecordSet of Expressomail_Model_Folder
  91. */
  92. public function processMoveIteration($_messages, $_targetFolder)
  93. {
  94. $folderName = ($_targetFolder instanceof Expressomail_Model_Folder ? $_targetFolder->globalname : $_targetFolder);
  95. if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
  96. . ' About to move ' . count($_messages) . ' messages to ' . $folderName);
  97. $_messages->addIndices(array('folder_id'));
  98. $movedMessages = FALSE;
  99. foreach (array_unique($_messages->folder_id) as $folderId) {
  100. $movedMessages = ($this->_moveMessagesByFolder($_messages, $folderId, $_targetFolder) || $movedMessages);
  101. }
  102. if (! $movedMessages) {
  103. // no messages have been moved -> return empty record set
  104. $result = new Tinebase_Record_RecordSet('Expressomail_Model_Folder');
  105. } else {
  106. // delete messages in local cache
  107. try {
  108. $number = $this->_backend->delete($_messages->getArrayOfIds());
  109. if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Deleted ' . $number .' messages from cache');
  110. } catch (Zend_Db_Statement_Exception $zdse) {
  111. if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ .
  112. ' Error deleting cached messages from folder ' . $folderName . ': ' . $zdse);
  113. }
  114. $result = $this->_updateCountsAfterMove($_messages);
  115. }
  116. return $result;
  117. }
  118. /**
  119. * move messages from one folder to another
  120. *
  121. * @param Tinebase_Record_RecordSet $_messages
  122. * @param string $_folderId
  123. * @param Expressomail_Model_Folder|string $_targetFolder
  124. * @return boolean did we move messages?
  125. */
  126. protected function _moveMessagesByFolder(Tinebase_Record_RecordSet $_messages, $_folderId, $_targetFolder)
  127. {
  128. $messagesInFolder = $_messages->filter('folder_id', $_folderId);
  129. if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__
  130. . ' Moving messages: ' . print_r($messagesInFolder->getArrayOfIds(), TRUE));
  131. $result = TRUE;
  132. if ($_targetFolder === Expressomail_Model_Folder::FOLDER_TRASH) {
  133. $result = $this->_moveMessagesToTrash($messagesInFolder, $_folderId);
  134. } else if ($_folderId === $_targetFolder->getId()) {
  135. // no need to move
  136. $result = FALSE;
  137. } else if ($messagesInFolder->getFirstRecord()->account_id == $_targetFolder->account_id) {
  138. $this->_moveMessagesInFolderOnSameAccount($messagesInFolder, $_targetFolder);
  139. } else {
  140. $this->_moveMessagesToAnotherAccount($messagesInFolder, $_targetFolder);
  141. }
  142. if (! $result) {
  143. $_messages->removeRecords($messagesInFolder);
  144. }
  145. return $result;
  146. }
  147. /**
  148. * move messages to trash
  149. *
  150. * @param Tinebase_Record_RecordSet $_messagesInFolder
  151. * @param string $_folderId
  152. * @return boolean did we move messages?
  153. */
  154. protected function _moveMessagesToTrash(Tinebase_Record_RecordSet $_messagesInFolder, $_folderId)
  155. {
  156. // messages should be moved to trash -> need to determine the trash folder for the account of the folder that contains the messages
  157. $targetFolder = Expressomail_Controller_Account::getInstance()->getSystemFolder(
  158. $_messagesInFolder->getFirstRecord()->account_id,
  159. Expressomail_Model_Folder::FOLDER_TRASH
  160. );
  161. if ($_folderId === $targetFolder->id) {
  162. return FALSE;
  163. }
  164. try {
  165. $this->_moveMessagesInFolderOnSameAccount($_messagesInFolder, $targetFolder);
  166. } catch (Tinebase_Exception_NotFound $tenf) {
  167. if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__
  168. . ' No trash folder found - skipping messages in this folder.');
  169. return FALSE;
  170. }
  171. return TRUE;
  172. }
  173. /**
  174. * move messages from one folder to another folder within the same email account
  175. *
  176. * @param Tinebase_Record_RecordSet $_messages
  177. * @param Expressomail_Model_Folder $_targetFolder
  178. */
  179. protected function _moveMessagesInFolderOnSameAccount(Tinebase_Record_RecordSet $_messages, Expressomail_Model_Folder $_targetFolder)
  180. {
  181. if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ .
  182. ' Move ' . count($_messages) . ' message(s) to ' . $_targetFolder->globalname
  183. );
  184. $firstMessage = $_messages->getFirstRecord();
  185. $folder = Expressomail_Controller_Folder::getInstance()->get($firstMessage->folder_id);
  186. $imapBackend = $this->_getBackendAndSelectFolder(NULL, $folder);
  187. $imapMessageUids = array();
  188. foreach ($_messages as $message) {
  189. $imapMessageUids[] = $message->messageuid;
  190. if (count($imapMessageUids) >= 50) {
  191. $this->_moveBatchOfMessages($imapMessageUids, $_targetFolder->globalname, $imapBackend);
  192. $imapMessageUids = array();
  193. }
  194. }
  195. // the rest
  196. if (count($imapMessageUids) > 0) {
  197. $this->_moveBatchOfMessages($imapMessageUids, $_targetFolder->globalname, $imapBackend);
  198. }
  199. }
  200. /**
  201. * move messages to another email account
  202. *
  203. * @param Tinebase_Record_RecordSet $_messages
  204. * @param Expressomail_Model_Folder $_targetFolder
  205. */
  206. protected function _moveMessagesToAnotherAccount(Tinebase_Record_RecordSet $_messages, Expressomail_Model_Folder $_targetFolder)
  207. {
  208. if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ .
  209. ' Move ' . count($_messages) . ' message(s) to ' . $_targetFolder->globalname . ' in account ' . $_targetFolder->account_id
  210. );
  211. foreach ($_messages as $message) {
  212. $part = Expressomail_Controller_Message::getInstance()->getMessagePart($message);
  213. $this->appendMessage($_targetFolder, $part->getRawStream(), $message->flags);
  214. }
  215. }
  216. /**
  217. * update folder count after moving messages
  218. *
  219. * @param Tinebase_Record_RecordSet $_messages
  220. * @param array $_folderCounterById
  221. * @return Tinebase_Record_RecordSet of Expressomail_Model_Folder
  222. */
  223. protected function _updateCountsAfterMove(Tinebase_Record_RecordSet $_messages)
  224. {
  225. $folderCounterById = array();
  226. foreach($_messages as $message) {
  227. if (! array_key_exists($message->folder_id, $folderCounterById)) {
  228. $folderCounterById[$message->folder_id] = array(
  229. 'decrementUnreadCounter' => 0,
  230. 'decrementMessagesCounter' => 0,
  231. );
  232. }
  233. if (!is_array($message->flags) || !in_array(Zend_Mail_Storage::FLAG_SEEN, $message->flags)) {
  234. // count messages with seen flag for the first time
  235. $folderCounterById[$message->folder_id]['decrementUnreadCounter']++;
  236. }
  237. $folderCounterById[$message->folder_id]['decrementMessagesCounter']++;
  238. }
  239. $affectedFolders = $this->_updateFolderCounts($folderCounterById);
  240. return $affectedFolders;
  241. }
  242. /**
  243. * move messages on imap server
  244. *
  245. * @param array $_uids
  246. * @param string $_targetFolderName
  247. * @param Expressomail_Backend_ImapProxy $_imap
  248. *
  249. * @todo perhaps we should check the existance of the messages on the imap instead of catching the exceptions here
  250. */
  251. protected function _moveBatchOfMessages($_uids, $_targetFolderName, Expressomail_Backend_ImapProxy $_imap)
  252. {
  253. if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
  254. . ' Move ' . count($_uids) . ' messages to folder ' . $_targetFolderName . ' on imap server');
  255. try {
  256. $_imap->copyMessage($_uids, Expressomail_Model_Folder::encodeFolderName($_targetFolderName));
  257. $_imap->addFlags($_uids, array(Zend_Mail_Storage::FLAG_DELETED));
  258. } catch (Zend_Mail_Storage_Exception $zmse) {
  259. if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . ' ' . $zmse);
  260. } catch (Expressomail_Exception_IMAP $fei) {
  261. if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . ' ' . $fei);
  262. }
  263. }
  264. }