1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

how to avoid rewritting the parent method on extended class?

Discussion in 'XenForo Development Discussions' started by DarkSign, Aug 16, 2011.

  1. DarkSign

    DarkSign Active Member

    Hello XF developers! I am a new coder, so I hope I won't bother you guys so much. I already have read almost all threads here on the dev section.

    So, I am writting an add-on that will auto-lock a thread after X posts. I probably am doing it wrong, because I just want to add my custom code on the extended class, and use the parent method to actually save the data.

    Here is my try at coding it.

    Code:
    <?php
    class DS_AutoLockThreads_ControllerPublic_AutoLockThreads extends XFCP_DS_AutoLockThreads_ControllerPublic_AutoLockThreads
    {
        public function actionAddReply()
        {
            $threadOpened = $this->_input->filterSingle('discussion_open', XenForo_Input::UINT); //checking if the thread is locked
            if ($threadOpened) //1 for Locked, so that returns true here
            {
                //no reason to continue, throw Exception
                return $this->responseNoPermission();
            }
            
            //extracting the Options
            $Options = XenForo_Application::get('options');
            
            
        $this->_assertPostOnly();
    
            if ($this->_input->inRequest('more_options'))
            {
                return $this->responseReroute(__CLASS__, 'reply');
            }
    
            $threadId = $this->_input->filterSingle('thread_id', XenForo_Input::UINT);
            
            //Getting the Model to check the last post
            $limitPost = $this->_getPostModel()->getLastPostInThread($threadId);
            
            $visitor = XenForo_Visitor::getInstance();
    
            $ftpHelper = $this->getHelper('ForumThreadPost');
            $threadFetchOptions = array('readUserId' => $visitor['user_id']);
            $forumFetchOptions = array('readUserId' => $visitor['user_id']);
            list($thread, $forum) = $ftpHelper->assertThreadValidAndViewable($threadId, $threadFetchOptions, $forumFetchOptions);
    
            $this->_assertCanReplyToThread($thread, $forum);
    
            if (!XenForo_Captcha_Abstract::validateDefault($this->_input))
            {
                return $this->responseCaptchaFailed();
            }
    
    
            $input = $this->_input->filter(array(
                'attachment_hash' => XenForo_Input::STRING,
    
                'watch_thread_state' => XenForo_Input::UINT,
                'watch_thread' => XenForo_Input::UINT,
                'watch_thread_email' => XenForo_Input::UINT,
    
                '_set' => array(XenForo_Input::UINT, 'array' => true),
                'discussion_open' => XenForo_Input::UINT,
                'sticky' => XenForo_Input::UINT,
            ));
            $input['message'] = $this->getHelper('Editor')->getMessageText('message', $this->_input);
            $input['message'] = XenForo_Helper_String::autoLinkBbCode($input['message']);
    
            $writer = XenForo_DataWriter::create('XenForo_DataWriter_DiscussionMessage_Post');
            $writer->set('user_id', $visitor['user_id']);
            $writer->set('username', $visitor['username']);
            $writer->set('message', $input['message']);
            $writer->set('message_state', $this->_getPostModel()->getPostInsertMessageState($thread, $forum));
            $writer->set('thread_id', $threadId);
            $writer->setExtraData(XenForo_DataWriter_DiscussionMessage::DATA_ATTACHMENT_HASH, $input['attachment_hash']);
            $writer->preSave();
    
            if (!$writer->hasErrors())
            {
                $this->assertNotFlooding('post');
            }
    
            $writer->save();
            $post = $writer->getMergedData();
    
            $this->_getThreadWatchModel()->setVisitorThreadWatchStateFromInput($threadId, $input);
    
            $threadUpdateData = array();
            
            if (($limitPost['position']+2 >= $Options->maxPosts) && ($threadId == $Options->threadId))
            {
                //For some reason, I need to use that +2 hack, so it actually works
                
                //Here is the trick! We lock the thread if the requirements are ok
                $input['_set']['discussion_open'] = 1;
            }
                if (!empty($input['_set']['discussion_open']))
            {
                if ($thread['discussion_open'] != $input['discussion_open'])
                {
                
                    $threadUpdateData['discussion_open'] = $input['discussion_open'];
                }
            }
            
            
            // discussion sticky state - moderator permission required
            if (!empty($input['_set']['sticky']) && $this->_getForumModel()->canStickUnstickThreadInForum($forum))
            {
                if ($thread['sticky'] != $input['sticky'])
                {
                    $threadUpdateData['sticky'] = $input['sticky'];
                }
            }
    
            if ($threadUpdateData)
            {
                $threadWriter = XenForo_DataWriter::create('XenForo_DataWriter_Discussion_Thread');
                $threadWriter->setExistingData($thread['thread_id']);
                $threadWriter->bulkSet($threadUpdateData);
                $threadWriter->save();
            }
    
            $canViewPost = $this->_getPostModel()->canViewPost($post, $thread, $forum);
    
            $page = floor(($thread['reply_count'] + 1) / XenForo_Application::get('options')->messagesPerPage) + 1;
    
            // this is a standard redirect
            if (!$this->_noRedirect() || !$this->_input->inRequest('last_date') || !$canViewPost)
            {
                $this->_getThreadModel()->markThreadRead($thread, $forum, XenForo_Application::$time, $visitor['user_id']);
    
                if (!$canViewPost)
                {
                    $return = XenForo_Link::buildPublicLink('threads', $thread, array('page' => $page, 'posted' => 1));
                }
                else
                {
                    $return = XenForo_Link::buildPublicLink('posts', $post);
                }
    
                return $this->responseRedirect(
                    XenForo_ControllerResponse_Redirect::SUCCESS,
                    $return,
                    new XenForo_Phrase('your_message_has_been_posted')
                );
            }
            else
            {
                // load a selection of posts that are newer than the last post viewed
                $threadModel = $this->_getThreadModel();
                $postModel = $this->_getPostModel();
    
                // the max number of posts we want to fetch
                $limit = 3;
    
                $postPermissionOptions = $postModel->getPermissionBasedPostFetchOptions($thread, $forum);
                $postFetchOptions = $postPermissionOptions + array(
                    'limit' => ($limit + 1),
                    'join' => XenForo_Model_Post::FETCH_USER | XenForo_Model_Post::FETCH_USER_PROFILE,
                );
                if (!empty($postPermissionOptions['deleted']))
                {
                    $postFetchOptions['join'] |= XenForo_Model_Post::FETCH_DELETION_LOG;
                }
    
                $lastDate = $this->_input->filterSingle('last_date', XenForo_Input::UINT);
    
                $posts = $postModel->getNewestPostsInThreadAfterDate(
                    $threadId, $lastDate, $postFetchOptions
                );
    
                // We fetched one more post than needed, if more than $limit posts were returned,
                // we can show the 'there are more posts' notice
                if (count($posts) > $limit)
                {
                    $firstUnshownPost = $postModel->getNextPostInThread($threadId, $lastDate, $postPermissionOptions);
    
                    // remove the extra post
                    array_pop($posts);
                }
                else
                {
                    $firstUnshownPost = false;
                }
    
                // put the posts into oldest-first order
                $posts = array_reverse($posts, true);
    
                $posts = $postModel->getAndMergeAttachmentsIntoPosts($posts);
    
                $permissions = $visitor->getNodePermissions($thread['node_id']);
    
                foreach ($posts AS &$post)
                {
                    $post = $postModel->preparePost($post, $thread, $forum, $permissions);
                }
    
                // mark thread as read if we're showing the remaining posts in it or they've been read
                if ($visitor['user_id'])
                {
                    if (!$firstUnshownPost || $firstUnshownPost['post_date'] <= $thread['thread_read_date'])
                    {
                        $this->_getThreadModel()->markThreadRead($thread, $forum, XenForo_Application::$time, $visitor['user_id']);
                    }
                }
    
                $viewParams = $this->_getDefaultViewParams($forum, $thread, $posts, $page, array(
                    'firstUnshownPost' => $firstUnshownPost,
                    'lastPost' => end($posts),
                ));
    
                return $this->responseView(
                    'XenForo_ViewPublic_Thread_ViewNewPosts',
                    'thread_reply_new_posts',
                    $viewParams
                );
            }
            
            
        }
    }
    as you can see, I had to rewrite all the parent's method on that extended class. It does the job, but... is it really necessary?

    Oh, any other comments on my code is welcomed. I know I am not doing it properly, but again, I am learning PHP OO, and getting help using the XF code itself.

    And as it is now, it only locks 1 thread. I want to extend it to use a custom template that will add the checkbox 'Auto lock after' and a text box to put the maxium posts allowed, into that Thread Tools for admins and mods only. So any advice on how to do it would be nice too.

    Thank you for your time.
     
  2. Syndol

    Syndol Guest

    The following woud be a good start for extending that function.
    First let the member post, then check if count has reached your limit.
    You might also want to consider redirecting the user after the inline post so they will know the thread has been locked.

    PHP:
        public function actionAddReply()
        {
            
    $redirect parent::actionAddReply();

            
    $threadId $this->_input->filterSingle('thread_id'XenForo_Input::UINT);
            
    $options XenForo_Application::get('options');
            if (
    $threadId == $options->AutoLockThreads_thread_id)
            {
                
    $postModel $this->_getPostModel();
                
    $numPosts $postModel->countVisiblePostsInThread($threadId);

                if (
    $numPosts >= $options->AutoLockThreads_count_limit)
                {
                    
    $visitorId XenForo_Visitor::getUserId();

                    
    $ftpHelper $this->getHelper('ForumThreadPost');
                    
    $threadFetchOptions = array('readUserId' => $visitorId);
                    
    $forumFetchOptions = array('readUserId' => $visitorId);
                    list(
    $thread$forum) = $ftpHelper->assertThreadValidAndViewable($threadId$threadFetchOptions$forumFetchOptions);

                    
    $threadWriter XenForo_DataWriter::create('XenForo_DataWriter_Discussion_Thread');
                    
    $threadWriter->setExistingData($thread['thread_id']);
                    
    $threadWriter->set('discussion_open'0);
                    
    $threadWriter->save();

                    
    $this->_getThreadModel()->markThreadRead($thread$forumXenForo_Application::$time$visitorId);

                }
            }

            return 
    $redirect;
        }
     
    DarkSign likes this.
  3. DarkSign

    DarkSign Active Member

    That sure helps! I didn't think about that I could have non-visible posts being counted. (y)

    I tried to understand that Helper, but I really am lost on it. :( Some more explanation would be fine

    Using the Writer is really cool. I think I need to learn more about it. Just pointing that the discussion_open should be 1 to lock it. ;) Doing a test I really should had tested before posting. So, why I need to put 0 there, and on my code I need to put 1?

    So far, so good! It looks way better! Thank you for help! I will test it! :D

    UPDATE: It works! So bad that all my first add-on trying was rewritted, but living and learning! I will give you credits for the function.

    Now it works for only one thread, like I said, so it's time to move on to learn templating and how to put a checkbox and a edit box in the Thread Tools hehehe.

    Thank you very much!
     
  4. Syndol

    Syndol Guest

    That helper fetches the thread and forum information if the visitor has proper viewing permissions.
    You don't really need it except to mark the thread as read.

    The above code is just a quick example.

    No, zero (0) is locked.
     
  5. DarkSign

    DarkSign Active Member

    if that was just a quick example, then I really need to learn lots more :)

    Haha, so I was doing something really wrong, because setting that array with 1 made the thread being locked someway.

    Your "quick example" worked like a charm! It actually does what I needed.

    I didn't get this part...
     
  6. Panupat

    Panupat Well-Known Member

    Usually when you make a reply, Xenforo doesn't refresh the page. Instead the new post got added to the bottom using AJAX. So the user will never know if the thread got closed. In which case Syndol suggests you redirect the whole page.
     
  7. DarkSign

    DarkSign Active Member

    Oh I understood now. I made some tests and it is working nice, throwing the exception even with the AJAX thing, so I don't think it's really necessary.
     
  8. Syndol

    Syndol Guest

    To check for multiple thread id's, have the add-on options save a string with the ids as "1,4,3,8"
    Then in the code use:
    PHP:
    if (in_array($threadIdexplode(','$options->AutoLockThreads_thread_ids)))
    {

    }
    In regards to including options for admins at time of thread creation see template 'thread_create'
    You will need to use hook 'thread_create_fields_extra' to add an option such as the ones in template 'thread_fields_status'

    As well as set the mod usergroup permission in the admin control panel under users - Permission Definitions
     
    DarkSign likes this.
  9. DarkSign

    DarkSign Active Member

    Thank you to point me the way, Syndol (y)
     

Share This Page