XF 2.2 Thread::getNewPostsReply()

Ozzy47

Well-known member
Any reason for this error to be showing up in XF 2.2
Error: Call to undefined method XFMG\XF\Pub\Controller\Thread::getNewPostsReply() in src/addons/Snog/TV/XF/Pub/Controller/Thread.php at line 221



PHP:
    public function actionAddReply(ParameterBag $params)
    {
        $this->assertPostOnly();
        $visitor = \XF::visitor();

        // HAVE TO QUERY FOR VIEWABLE TO GET THE NODE ID
        $thread = $this->assertViewableThread($params->thread_id, ['Watch|' . $visitor->user_id]);

        $node_id = $thread->node_id;
        if (!in_array($node_id, $this->options()->TvThreads_forum)) return parent::actionAddReply($params);
        if (!$thread->canReply($error)) return $this->noPermission($error);

        if ($this->filter('no_captcha', 'bool')) // JS is disabled so user hasn't seen Captcha.
        {
            $this->request->set('requires_captcha', true);
            return $this->rerouteController(__CLASS__, 'reply', $params);
        }
        else if (!$this->captchaIsValid())
        {
            return $this->error(\XF::phrase('did_not_complete_the_captcha_verification_properly'));
        }

        $tvid = 0;
        $season = $this->filter('season', 'uint');
        $episode = $this->filter('episode', 'uint');

        if (!$season && !$episode) return parent::actionAddReply($params);

        if(isset($thread->TV->tv_id)) $tvid = $thread->TV->tv_id;

        if (($season && !$episode) || (!$season && $episode))
        {
            return $this->error(\XF::phrase('snog_tv_error_episode_link'));
        }

        $comment = $this->plugin('XF:Editor')->fromInput('message');
        $message = '';
        $guest = '';
        $permstars = '';
        $originalImage = '';
        $tvepisode = array();

        if ($season && $episode && $tvid)
        {
            try
            {
                $response = \XF::app()->http()->client()->get("http://api.themoviedb.org/3/tv/" . $tvid . "/season/" . $season . "/episode/" . $episode . "?api_key=" . trim($this->options()->TvThreads_apikey) . "&language=" . $this->options()->TvThreads_language . "&append_to_response=credits");
            }
            catch(\GuzzleHttp\Exception\RequestException $e)
            {
                if(null !== $e->getResponse())
                {
                    $error = 'TMDb Error ' . $e->getResponse()->getStatusCode();
                    $error .= ': ' . $e->getResponse()->getReasonPhrase();
                }
                else
                {
                    $error = $e->getMessage();
                }

                return $this->error($error);
            }

            $tvepisodeData = \GuzzleHttp\json_decode($response->getBody(), true);
            $dataFilter = new InputFilterer();
            $tvepisode = $dataFilter->filter($tvepisodeData, 'ARRAY');

            if (!is_null($tvepisode['still_path']))
            {
                // GET EPISODE IMAGE
                if ($tvepisode['still_path'] > '')
                {
                    $src = "http://image.tmdb.org/t/p/w300" . $tvepisode['still_path'];
                    $path = 'data://tv/EpisodePosters' . $tvepisode['still_path'];
                    $tempDir = FILE::getTempDir();
                    $tempPath = $tempDir . $tvepisode['still_path'];

                    try
                    {
                        $response = \XF::app()->http()->client()->get($src);
                    }
                    catch(\GuzzleHttp\Exception\RequestException $e)
                    {
                        $error = $e->getMessage();
                        return $this->error($error);
                    }

                    if (file_exists($tempPath)) unlink($tempPath);
                    file_put_contents($tempPath, $response->getBody());

                    File::copyFileToAbstractedPath($tempPath, $path);
                    unlink($tempPath);
                }
            }
            else
            {
                $tvepisode['still_path'] = '';
            }

            $episodeInfo = "[B]" . $thread['title'] . "[/B]" . "\r\n";
            $originalImage = '[IMG]' . $this->getEpisodeImageUrl(($tvepisode['still_path'] ? $tvepisode['still_path'] : '/no-poster.jpg')) . '[/IMG]' . "\r\n";
            $episodeInfo .= $originalImage;

            if (!empty($tvepisode['credits']['guest_stars']))
            {
                foreach ($tvepisode['credits']['cast'] as $cast)
                {
                    if ($permstars) $permstars .= ', ';
                    $permstars .= $cast['name'];
                }

                $checkstars = explode(',', $permstars);
                foreach ($tvepisode['credits']['guest_stars'] as $guestStar)
                {
                    if (!in_array($guestStar['name'], $checkstars))
                    {
                        if ($guest) $guest .= ', ';
                        $guest .= $guestStar['name'];
                    }
                }
            }

            $episodeInfo .= "[B]" . $tvepisode['name'] . "[/B]" . "\r\n";
            $episodeInfo .= "[B]" . \XF::phrase('snog_tv_season') . ":[/B] " . $tvepisode['season_number'] . "\r\n";
            $episodeInfo .= "[B]" . \XF::phrase('snog_tv_episode') . ":[/B] " . $tvepisode['episode_number'] . "\r\n";
            $episodeInfo .= "[B]" . \XF::phrase('snog_tv_air_date') . ":[/B] " . $tvepisode['air_date'] . "\r\n\r\n";
            if (!empty($guest)) $episodeInfo .= "[B]" . \XF::phrase('snog_tv_guest_stars') . ":[/B] " . $guest . "\r\n\r\n";
            $episodeInfo .= $tvepisode['overview'] . "\r\n";
            $message = $episodeInfo . "\r\n\r\n";
        }

        // REPLIER IS DONE HERE BECAUSE TMDB EPISODE INFO IS REQUIRED FOR MESSAGE CONSTRUCTION AND PROPER SAVE OF EPISODE INFO
        $replier = $this->service('XF:Thread\Replier', $thread);

        $message .= $comment;

        $replier->setMessage($message);

        if ($thread->Forum->canUploadAndManageAttachments()) $replier->setAttachmentHash($this->filter('attachment_hash', 'str'));

        $replier->checkForSpam();

        /** @var \XF\Validator\Username $errors */
        if (!$replier->validate($errors)) return $this->error($errors);

        $this->assertNotFlooding('post');
        $post = $replier->save();

        /** @var \XF\Service\Thread\Replier $replier */
        $this->finalizeThreadReply($replier);

        if (!empty($tvepisode))
        {
            $newEpisode = $this->em()->create('Snog\TV:TVPost');
            $newEpisode->post_id = $post->post_id;
            $newEpisode->tv_id = $thread->TV->tv_id;
            $newEpisode->tv_season = $tvepisode['season_number'];
            $newEpisode->tv_episode = $tvepisode['episode_number'];
            $newEpisode->tv_aired = $tvepisode['air_date'];
            $newEpisode->tv_image = $tvepisode['still_path'];
            $newEpisode->tv_title = $tvepisode['name'];
            $newEpisode->tv_plot = $tvepisode['overview'];
            $newEpisode->tv_cast = $permstars;
            $newEpisode->tv_guest = $guest;
            $newEpisode->message = $comment;
            $newEpisode->save(true, true);
        }

        // MOVE EPISODE IMAGE TO POST ID + IMAGE NAME
        if($tvepisode['still_path'] && $originalImage)
        {
            // NEW IMAGE NAME THAT INLCUDES POST ID
            $imageName = $post->post_id . '-' . str_ireplace('/', '', $tvepisode['still_path']);

            // MOVE IMAGE TO NEW NAME
            $oldpath = 'data://tv/EpisodePosters' . $tvepisode['still_path'];
            $newpath = 'data://tv/EpisodePosters/' . $imageName;

            try
            {
                \XF::app()->fs()->move($oldpath, $newpath);
            }
            catch (\League\Flysystem\FileNotFoundException $e) {}

            // CHANGE IMAGE IN POST TO NEWLY NAMED IMAGE (INCLUDES POST ID)
            $episodepost = $this->finder('Snog\TV:TVPost')->where('post_id', $post->post_id)->fetchOne();
            $newImage = '[IMG]' . $episodepost->getEpisodeImageUrl() . '[/IMG]' . "\r\n";
            $post->message = str_ireplace($originalImage, $newImage, $post->message);
            $post->save();
        }

        if ($this->filter('_xfWithData', 'bool') && $this->request->exists('last_date') && $post->canView())
        {
            // request was from quick reply
            $lastDate = $this->filter('last_date', 'uint');
            return $this->getNewPostsReply($thread, $lastDate);
        }
        else
        {
            $this->getThreadRepo()->markThreadReadByVisitor($thread);
            $confirmation = \XF::phrase('your_message_has_been_posted');

            if ($post->canView())
            {
                return $this->redirect($this->buildLink('posts', $post), $confirmation);
            }
            else
            {
                return $this->redirect($this->buildLink('threads', $thread, ['pending_approval' => 1]), $confirmation);
            }
        }
    }

Out of the above code, line 221 is return $this->getNewPostsReply($thread, $lastDate);
 

smozgur

Active member
It looks like there is no "getNewPostsReply()" function in the Thread.php controller anymore, but getNewPostsSinceDateReply() function now with extra parameters. Since XFMG is extending the controller, the add-on also depends on that function.
Add-on should be updated accordingly.
 

Ozzy47

Well-known member
Does it appear to be a direct replacement?
Change getNewPostsReply() = getNewPostsSinceDateReply()
 

smozgur

Active member
I didn’t have chance to analyze, but just a quick look. However, I saw extra parameters (don’t remember if required or with default values).
I can look when I get back to my computer.
 

smozgur

Active member
I checked it, and I can tell that it is compatible with the old function. It shouldn't be any problem changing the function name only.

Details:
There is the third parameter, $limit, which was previously assigned in the function and equal to 3. It is now the optional function parameter with default value = 3. So, it shouldn't affect the caller in your case.

There is a split function inside, getNewPostsReplyInternal(), used to be called by another new function also, getSingleNewPostReply(), but it also doesn't change anything.

What I can see is that the functionality is backward compatible, but need to change the function name. It is surprising that the XenForo developer team didn't leave a deprecated function name as a proxy for complete backward compatibility.

That being said, I strongly recommend testing your code before using it in production.
 

Ozzy47

Well-known member
Thank you for the detailed explanation. I’ll surely test it out and let you know how it goes.
 

Ozzy47

Well-known member
Seems to have done the trick.

PHP:
            if (\XF::$versionId < 2020010)
            {
              return $this->getNewPostsReply($thread, $lastDate);
            }
             else
            {
              return $this->getNewPostsSinceDateReply($thread, $lastDate);
            }
 

smozgur

Active member
Seems to have done the trick.

PHP:
            if (\XF::$versionId < 2020010)
            {
              return $this->getNewPostsReply($thread, $lastDate);
            }
             else
            {
              return $this->getNewPostsSinceDateReply($thread, $lastDate);
            }
(y)

The Thread controller can be also extended to include the same function as a proxy (as I would expect in the package actually), but this also works well if it is only used at one place in the code.
 
Top