Example #1
0
 /**
  * Move topic or parts of it into another category or topic.
  *
  * @param   object  $target        Target KunenaForumCategory or KunenaForumTopic
  * @param   mixed   $ids           false, array of message Ids or JDate
  * @param   bool    $shadow        Leave visible shadow topic.
  * @param   string  $subject       New subject
  * @param   bool    $subjectall    Change subject from every message
  * @param   int     $topic_iconid  Define a new topic icon
  *
  * @return 	bool|KunenaForumCategory|KunenaForumTopic	Target KunenaForumCategory or KunenaForumTopic or false on failure
  */
 public function move($target, $ids = false, $shadow = false, $subject = '', $subjectall = false, $topic_iconid = null)
 {
     // Warning: logic in this function is very complicated and even with full understanding its easy to miss some details!
     // Clear authentication cache
     $this->_authfcache = $this->_authccache = $this->_authcache = array();
     // Cleanup input
     if (!$ids instanceof JDate) {
         if (!is_array($ids)) {
             $ids = explode(',', (string) $ids);
         }
         $mesids = array();
         foreach ($ids as $id) {
             $mesids[(int) $id] = (int) $id;
         }
         unset($mesids[0]);
         $ids = implode(',', $mesids);
     }
     $subject = (string) $subject;
     // First we need to check if there will be messages left in the old topic
     if ($ids) {
         $query = new KunenaDatabaseQuery();
         $query->select('COUNT(*)')->from('#__kunena_messages')->where("thread={$this->id}");
         if ($ids instanceof JDate) {
             // All older messages will remain (including unapproved, deleted)
             $query->where("time<{$ids->toUnix()}");
         } else {
             // All messages that were not selected will remain
             $query->where("id NOT IN ({$ids})");
         }
         $this->_db->setQuery($query);
         $oldcount = (int) $this->_db->loadResult();
         if ($this->_db->getErrorNum()) {
             $this->setError($this->_db->getError());
             return false;
         }
         // So are we moving the whole topic?
         if (!$oldcount) {
             $ids = '';
         }
     }
     $categoryFrom = $this->getCategory();
     // Find out where we are moving the messages
     if (!$target || !$target->exists()) {
         $this->setError(JText::printf('COM_KUNENA_MODERATION_ERROR_NO_TARGET', $this->id));
         return false;
     } elseif ($target instanceof KunenaForumTopic) {
         // Move messages into another topic (original topic will always remain, either as real one or shadow)
         if ($target == $this) {
             // We cannot move topic into itself
             $this->setError(JText::sprintf('COM_KUNENA_MODERATION_ERROR_SAME_TARGET_THREAD', $this->id, $this->id));
             return false;
         }
         if ($this->moved_id) {
             // Moved topic cannot be merged with another topic -- it has no posts to be moved
             $this->setError(JText::sprintf('COM_KUNENA_MODERATION_ERROR_ALREADY_SHADOW', $this->id));
             return false;
         }
         if ($this->poll_id && $target->poll_id) {
             // We cannot currently have 2 polls in one topic -- fail
             $this->setError(JText::_('COM_KUNENA_MODERATION_CANNOT_MOVE_TOPIC_WITH_POLL_INTO_ANOTHER_WITH_POLL'));
             return false;
         }
         if ($subjectall) {
             $subject = $target->subject;
         }
     } elseif ($target instanceof KunenaForumCategory) {
         // Move messages into category
         if ($target->isSection()) {
             // Section cannot have any topics
             $this->setError(JText::_('COM_KUNENA_MODERATION_ERROR_NOT_MOVE_SECTION'));
             return false;
         }
         // Save category information for later use
         $categoryTarget = $target;
         if ($this->moved_id) {
             // Move shadow topic and we are done
             $this->category_id = $categoryTarget->id;
             if ($subject) {
                 $this->subject = $subject;
             }
             $this->save(false);
             return $target;
         }
         if ($shadow || $ids) {
             // Create new topic for the moved messages
             $target = clone $this;
             $target->exists(false);
             $target->id = 0;
             $target->hits = 0;
             $target->params = '';
         } else {
             // If we just move into another category, we can keep using the old topic
             $target = $this;
         }
         // Did user want to change the subject?
         if ($subject) {
             $target->subject = $subject;
         }
         // Did user want to change the topic icon?
         if (!is_null($topic_iconid)) {
             $target->icon_id = $topic_iconid;
         }
         // Did user want to change category?
         $target->category_id = $categoryTarget->id;
     } else {
         $this->setError(JText::_('COM_KUNENA_MODERATION_ERROR_WRONG_TARGET'));
         return false;
     }
     // For now on we assume that at least one message will be moved (=authorization check was called on topic/message)
     // We will soon need target topic id, so save if it doesn't exist
     if (!$target->exists()) {
         if (!$target->save(false)) {
             $this->setError($target->getError());
             return false;
         }
     }
     // Move messages (set new category and topic)
     $query = new KunenaDatabaseQuery();
     $query->update('#__kunena_messages')->set("catid={$target->category_id}")->set("thread={$target->id}")->where("thread={$this->id}");
     // Did we want to change subject from all the messages?
     if ($subjectall && !empty($subject)) {
         $query->set("subject={$this->_db->quote($subject)}");
     }
     if ($ids instanceof JDate) {
         // Move all newer messages (includes unapproved, deleted messages)
         $query->where("time>={$ids->toUnix()}");
     } elseif ($ids) {
         // Move individual messages
         $query->where("id IN ({$ids})");
     }
     $this->_db->setQuery($query);
     $this->_db->query();
     if ($this->_db->getErrorNum()) {
         $this->setError($this->_db->getError());
         return false;
     }
     // Make sure that all messages in topic have unique time (deterministic without ORDER BY time, id)
     $query = "SET @ktime:=0";
     $this->_db->setQuery($query);
     $this->_db->query();
     if ($this->_db->getErrorNum()) {
         $this->setError($this->_db->getError());
         return false;
     }
     $query = "UPDATE #__kunena_messages SET time=IF(time<=@ktime,@ktime:=@ktime+1,@ktime:=time) WHERE thread={$target->id} ORDER BY time ASC, id ASC";
     $this->_db->setQuery($query);
     $this->_db->query();
     if ($this->_db->getErrorNum()) {
         $this->setError($this->_db->getError());
         return false;
     }
     // If all messages were moved into another topic, we need to move poll as well
     if ($this->poll_id && !$ids && $target != $this) {
         // Note: We may already have saved cloned target (having poll_id already in there)
         $target->poll_id = $this->poll_id;
         // Note: Do not remove poll from shadow: information could still be used to show icon etc
         $query = "UPDATE #__kunena_polls SET `threadid`={$this->_db->Quote($target->id)} WHERE `threadid`={$this->_db->Quote($this->id)}";
         $this->_db->setQuery($query);
         $this->_db->query();
         if ($this->_db->getErrorNum()) {
             $this->setError($this->_db->getError());
             return false;
         }
     }
     // When moving only first message keep poll only on target topic
     if ($this->poll_id && $target != $this && $ids) {
         if ($ids && $this->first_post_id) {
             $this->poll_id = 0;
         }
     }
     if (!$ids && $target != $this) {
         // Leave shadow from old topic
         $this->moved_id = $target->id;
         if (!$shadow) {
             // Mark shadow topic as deleted
             $this->hold = 2;
         }
     }
     // Note: We already saved possible target earlier, now save only $this
     if (!$this->save(false)) {
         return false;
     }
     if (!$ids && !empty($categoryTarget)) {
         // Move topic into another category
         // Update user topic information (topic, category)
         KunenaForumTopicUserHelper::move($this, $target);
         // TODO: do we need this?
         //KunenaForumTopicUserReadHelper::move($this, $target);
         // Remove topic and posts from the old category
         $categoryFrom->update($this, -1, -$this->posts);
         // Add topic and posts into the new category
         $categoryTarget->update($target, 1, $this->posts);
     } elseif (!$ids) {
         // Moving topic into another topic
         // Add new posts, hits and attachments into the target topic
         $target->posts += $this->posts;
         $target->hits += $this->hits;
         $target->attachments += $this->attachments;
         // Update first and last post information into the target topic
         $target->updatePostInfo($this->first_post_id, $this->first_post_time, $this->first_post_userid, $this->first_post_message, $this->first_post_guest_name);
         $target->updatePostInfo($this->last_post_id, $this->last_post_time, $this->last_post_userid, $this->last_post_message, $this->last_post_guest_name);
         // Save target topic
         if (!$target->save(false)) {
             $this->setError($target->getError());
             return false;
         }
         // Update user topic information (topic, category)
         KunenaForumTopicUserHelper::merge($this, $target);
         // TODO: do we need this?
         //KunenaForumTopicUserReadHelper::merge($this, $target);
         // Remove topic and posts from the old category
         $this->getCategory()->update($this, -1, -$this->posts);
         // Add posts into the new category
         $target->getCategory()->update($target, 0, $this->posts);
     } else {
         // Both topics have changed and we have no idea how much: force full recount
         // TODO: we can do this faster..
         $this->recount();
         $target->recount();
     }
     return $target;
 }