Seditio Source
Root |
./othercms/xenForo 2.2.8/src/XF/Service/Thread/Replier.php
<?php

namespace XF\Service\Thread;

use
XF\Entity\Post;
use
XF\Entity\Thread;
use
XF\Entity\User;

class
Replier extends \XF\Service\AbstractService
{
    use \
XF\Service\ValidateAndSavableTrait;

   
/**
     * @var Thread
     */
   
protected $thread;

   
/**
     * @var Post
     */
   
protected $post;

   
/**
     * @var User
     */
   
protected $user;

   
/**
     * @var \XF\Service\Post\Preparer
     */
   
protected $postPreparer;

    protected
$performValidations = true;

    protected
$isPreRegAction = false;

    public function
__construct(\XF\App $app, Thread $thread)
    {
       
parent::__construct($app);
       
$this->setThread($thread);
       
$this->setUser(\XF::visitor());
       
$this->setPostDefaults();
    }

    protected function
setThread(Thread $thread)
    {
       
$this->thread = $thread;
       
$this->post = $thread->getNewPost();
       
$this->postPreparer = $this->service('XF:Post\Preparer', $this->post);
    }

    public function
getThread()
    {
        return
$this->thread;
    }

    public function
getPost()
    {
        return
$this->post;
    }

    public function
getPostPreparer()
    {
        return
$this->postPreparer;
    }

    protected function
setUser(\XF\Entity\User $user)
    {
       
$this->user = $user;
    }

    public function
logIp($logIp)
    {
       
$this->postPreparer->logIp($logIp);
    }

    public function
setPerformValidations($perform)
    {
       
$this->performValidations = (bool)$perform;
    }

    public function
getPerformValidations()
    {
        return
$this->performValidations;
    }

    public function
setIsAutomated()
    {
       
$this->logIp(false);
       
$this->setPerformValidations(false);
    }

    public function
setIsPreRegAction(bool $isPreRegAction)
    {
       
$this->isPreRegAction = $isPreRegAction;
    }

    protected function
setPostDefaults()
    {
       
$forum = $this->thread->Forum;

        if (!
$forum)
        {
            throw new \
LogicException("Thread is not in a valid forum");
        }

       
$this->post->message_state = $forum->getNewContentState($this->thread);
       
$this->post->user_id = $this->user->user_id;
       
$this->post->username = $this->user->username;
    }

    public function
setMessage($message, $format = true)
    {
        return
$this->postPreparer->setMessage($message, $format, $this->performValidations);
    }

    public function
setAttachmentHash($hash)
    {
       
$this->postPreparer->setAttachmentHash($hash);
    }

    public function
checkForSpam()
    {
        if (
$this->post->message_state == 'visible' && $this->user->isSpamCheckRequired())
        {
           
$this->postPreparer->checkForSpam();
        }
    }

    protected function
finalSetup()
    {
       
$this->post->post_date = time();
    }

    protected function
_validate()
    {
       
$this->finalSetup();

       
$post = $this->post;

        if (!
$post->user_id && !$this->isPreRegAction)
        {
           
/** @var \XF\Validator\Username $validator */
           
$validator = $this->app->validator('Username');
           
$post->username = $validator->coerceValue($post->username);
            if (
$this->performValidations && !$validator->isValid($post->username, $error))
            {
                return [
$validator->getPrintableErrorValue($error)];
            }
        }
        else if (
$this->isPreRegAction && !$post->username)
        {
           
// need to force a value here to avoid a presave error
           
$post->username = 'preRegAction-' . \XF::$time;
        }

       
$post->preSave();

       
$errors = $post->getErrors();

        return
$errors;
    }

    protected function
_save()
    {
        if (
$this->isPreRegAction)
        {
            throw new \
LogicException("Pre-reg action replies cannot be saved");
        }

       
$post = $this->post;

       
$db = $this->db();
       
$db->beginTransaction();

       
$threadLatest = $this->db()->fetchRow("
            SELECT *
            FROM xf_thread
            WHERE thread_id = ?
            FOR UPDATE
        "
, $this->thread->thread_id);

        if (!
$threadLatest)
        {
            throw new \
XF\PrintableException(\XF::phrase('requested_thread_not_found'));
        }

       
// Ensure our thread entity has the latest data to make sure things like reply count are correct
       
$forceUpdateColumns = [
           
'first_post_id',
           
'reply_count',
           
'last_post_date',
           
'last_post_id',
           
'last_post_user_id',
           
'last_post_username'
       
];
        foreach (
$forceUpdateColumns AS $forceUpdateColumn)
        {
           
$this->thread->setAsSaved($forceUpdateColumn, $threadLatest[$forceUpdateColumn]);
        }

       
// In very busy threads, it's possible that this request may execute at a different speed from another
        // and end up with a pending post_date that is less than that of the most recently inserted post which
        // would trigger an error when setting the post position. Attempt to detect this case and adjust
        // the post date to avoid an error if possible.
       
$time = time();
        if (
$threadLatest['last_post_date'] > $post->post_date && $threadLatest['last_post_date'] <= $time)
        {
           
$post->set('post_date', $time, ['forceSet' => true]);
        }

       
$this->setPostPosition($threadLatest);

       
$post->save(true, false);

       
$this->postPreparer->afterInsert();

       
$db->commit();

        return
$post;
    }

    protected function
setPostPosition(array $threadInfo)
    {
       
$post = $this->post;

        if (
$post->post_date < $threadInfo['last_post_date'])
        {
            throw new \
LogicException("Replier can only add posts at the end of a thread");
        }

        if (
$post->message_state == 'visible')
        {
           
$position = $threadInfo['reply_count'] + 1;
        }
        else
        {
           
$position = $threadInfo['reply_count'];
        }

       
$post->set('position', $position, ['forceSet' => true]);
    }

    public function
sendNotifications()
    {
        if (
$this->post->isVisible())
        {
           
/** @var \XF\Service\Post\Notifier $notifier */
           
$notifier = $this->service('XF:Post\Notifier', $this->post, 'reply');
           
$notifier->setMentionedUserIds($this->postPreparer->getMentionedUserIds());
           
$notifier->setQuotedUserIds($this->postPreparer->getQuotedUserIds());
           
$notifier->notifyAndEnqueue(3);
        }
    }
}