Seditio Source
Root |
./othercms/xenForo 2.2.8/src/XF/Entity/ProfilePost.php
<?php

namespace XF\Entity;

use
XF\BbCode\RenderableContentInterface;
use
XF\Mvc\Entity\ArrayCollection;
use
XF\Mvc\Entity\Entity;
use
XF\Mvc\Entity\Structure;

/**
 * COLUMNS
 * @property int|null $profile_post_id
 * @property int $profile_user_id
 * @property int $user_id
 * @property string $username
 * @property int $post_date
 * @property string $message
 * @property int $ip_id
 * @property string $message_state
 * @property int $attach_count
 * @property int $warning_id
 * @property string $warning_message
 * @property int $comment_count
 * @property int $first_comment_date
 * @property int $last_comment_date
 * @property array $latest_comment_ids
 * @property array|null $embed_metadata
 * @property int $reaction_score
 * @property array $reactions_
 * @property array $reaction_users_
 *
 * GETTERS
 * @property array $comment_ids
 * @property ArrayCollection|null $LatestComments
 * @property mixed $Unfurls
 * @property mixed $reactions
 * @property mixed $reaction_users
 *
 * RELATIONS
 * @property \XF\Entity\User $ProfileUser
 * @property \XF\Entity\User $User
 * @property \XF\Entity\DeletionLog $DeletionLog
 * @property \XF\Entity\ApprovalQueue $ApprovalQueue
 * @property \XF\Mvc\Entity\AbstractCollection|\XF\Entity\ProfilePostComment[] $Comments
 * @property \XF\Mvc\Entity\AbstractCollection|\XF\Entity\Attachment[] $Attachments
 * @property \XF\Mvc\Entity\AbstractCollection|\XF\Entity\ReactionContent[] $Reactions
 */
class ProfilePost extends Entity implements RenderableContentInterface, LinkableInterface
{
    use
ReactionTrait;

    public function
canView(&$error = null)
    {
       
$visitor = \XF::visitor();

        if (!
$this->ProfileUser)
        {
            return
false;
        }

        if (!
$this->ProfileUser->canViewPostsOnProfile($error))
        {
            return
false;
        }

        if (
$this->message_state == 'moderated')
        {
            if (
                !
$visitor->hasPermission('profilePost', 'viewModerated')
                && (!
$visitor->user_id || $visitor->user_id != $this->user_id)
            )
            {
               
$error = \XF::phraseDeferred('requested_profile_post_not_found');
                return
false;
            }
        }
        else if (
$this->message_state == 'deleted')
        {
            if (!
$visitor->hasPermission('profilePost', 'viewDeleted'))
            {
               
$error = \XF::phraseDeferred('requested_profile_post_not_found');
                return
false;
            }
        }

        return
true;
    }

    public function
canViewAttachments(&$error = null): bool
   
{
        return \
XF::visitor()->hasPermission('profilePost', 'viewAttachment');
    }

    public function
canUploadAndManageAttachments(): bool
   
{
       
$profileUser = $this->ProfileUser;
        if (!
$profileUser)
        {
            return
false;
        }

        return
$profileUser->canUploadAndManageAttachmentsOnProfile();
    }

    public function
canUploadVideos(): bool
   
{
       
$profileUser = $this->ProfileUser;
        if (!
$profileUser)
        {
            return
false;
        }

        return
$profileUser->canUploadVideosOnProfile();
    }

    public function
canUseInlineModeration(&$error = null)
    {
       
$visitor = \XF::visitor();
        return (
$visitor->user_id && $visitor->hasPermission('profilePost', 'inlineMod'));
    }

    public function
canEdit(&$error = null)
    {
       
$visitor = \XF::visitor();

        if (!
$visitor->user_id)
        {
            return
false;
        }

        if (
$visitor->user_id == $this->user_id)
        {
            return
$visitor->hasPermission('profilePost', 'editOwn');
        }
        else
        {
            return
$visitor->hasPermission('profilePost', 'editAny');
        }
    }

    public function
canDelete($type = 'soft', &$error = null)
    {
       
$visitor = \XF::visitor();
        if (!
$visitor->user_id)
        {
            return
false;
        }

        if (
$type != 'soft' && !$visitor->hasPermission('profilePost', 'hardDeleteAny'))
        {
            return
false;
        }

        if (
$visitor->hasPermission('profilePost', 'deleteAny'))
        {
            return
true;
        }

        return (
            (
               
$visitor->user_id == $this->profile_user_id
               
&& $visitor->hasPermission('profilePost', 'manageOwn')
            )
            ||
            (
               
$visitor->user_id == $this->user_id
               
&& $visitor->hasPermission('profilePost', 'deleteOwn')
            )
        );
    }

    public function
canUndelete(&$error = null)
    {
       
$visitor = \XF::visitor();
        return (
$visitor->user_id && $visitor->hasPermission('profilePost', 'undelete'));
    }

    public function
canApproveUnapprove(&$error = null)
    {
       
$visitor = \XF::visitor();
        return (
$visitor->user_id && $visitor->hasPermission('profilePost', 'approveUnapprove'));
    }

    public function
canWarn(&$error = null)
    {
       
$visitor = \XF::visitor();

        if (!
$this->user_id
           
|| !$visitor->user_id
           
|| $this->user_id == $visitor->user_id
           
|| !$visitor->hasPermission('profilePost', 'warn')
        )
        {
            return
false;
        }

        if (
$this->warning_id)
        {
           
$error = \XF::phraseDeferred('user_has_already_been_warned_for_this_content');
            return
false;
        }

        return (
$this->User && $this->User->isWarnable());
    }

    public function
canReport(&$error = null, User $asUser = null)
    {
       
$asUser = $asUser ?: \XF::visitor();
        return
$asUser->canReport($error);
    }

    public function
canReact(&$error = null)
    {
       
$visitor = \XF::visitor();
        if (!
$visitor->user_id)
        {
            return
false;
        }

        if (
$this->message_state != 'visible')
        {
            return
false;
        }

        if (
$this->user_id == $visitor->user_id)
        {
           
$error = \XF::phraseDeferred('reacting_to_your_own_content_is_considered_cheating');
            return
false;
        }

        return
$visitor->hasPermission('profilePost', 'react');
    }

    public function
canComment(&$error = null)
    {
       
$visitor = \XF::visitor();

        return (
           
$this->message_state == 'visible'
               
&& $visitor->user_id
               
&& $visitor->hasPermission('profilePost', 'view')
                &&
$visitor->hasPermission('profilePost', 'comment')
                &&
$this->ProfileUser->isPrivacyCheckMet('allow_post_profile', $visitor)
        );
    }

    public function
canAttach(&$error = null)
    {
       
$visitor = \XF::visitor();

        return (
           
$this->message_state == 'visible'
           
&& $visitor->user_id
           
&& $visitor->hasPermission('profilePost', 'uploadAttachment')
        );
    }

    public function
canViewDeletedComments()
    {
        return \
XF::visitor()->hasPermission('profilePost', 'viewDeleted');
    }

    public function
canViewModeratedComments()
    {
        return \
XF::visitor()->hasPermission('profilePost', 'viewModerated');
    }

    public function
canSendModeratorActionAlert()
    {
       
$visitor = \XF::visitor();

        if (!
$visitor->user_id || $visitor->user_id == $this->user_id)
        {
            return
false;
        }

        if (
$this->message_state != 'visible')
        {
            return
false;
        }

        return (
           
$visitor->hasPermission('profilePost', 'deleteAny')
            ||
$visitor->hasPermission('profilePost', 'editAny')
        );
    }

    public function
hasMoreComments()
    {
        if (
$this->comment_count > 3)
        {
            return
true;
        }

       
$visitor = \XF::visitor();

       
$canViewDeleted = $visitor->hasPermission('profilePost', 'viewDeleted');
       
$canViewModerated = $visitor->hasPermission('profilePost', 'viewModerated');

        if (!
$canViewDeleted && !$canViewModerated)
        {
            return
false;
        }

       
$viewableCommentCount = 0;

        foreach (
$this->latest_comment_ids AS $commentId => $state)
        {
            switch (
$state[0])
            {
                case
'visible':
                   
$viewableCommentCount++;
                    break;

                case
'moderated':
                    if (
$canViewModerated)
                    {
                       
$viewableCommentCount++;
                    }
                    break;

                case
'deleted':
                    if (
$canViewDeleted)
                    {
                       
$viewableCommentCount++;
                    }
                    break;
            }

            if (
$viewableCommentCount > 3)
            {
                return
true;
            }
        }

        return
false;
    }

    public function
isVisible()
    {
        return (
$this->message_state == 'visible');
    }

    public function
isAttachmentEmbedded($attachmentId)
    {
        if (!
$this->embed_metadata)
        {
            return
false;
        }

        if (
$attachmentId instanceof Attachment)
        {
           
$attachmentId = $attachmentId->attachment_id;
        }

        return isset(
$this->embed_metadata['attachments'][$attachmentId]);
    }

    public function
isIgnored()
    {
        return \
XF::visitor()->isIgnoring($this->user_id);
    }

    public function
canCleanSpam()
    {
        return (\
XF::visitor()->canCleanSpam() && $this->User && $this->User->isPossibleSpammer());
    }

   
/**
     * @return array
     */
   
public function getCommentIds()
    {
        return
$this->db()->fetchAllColumn("
            SELECT profile_post_comment_id
            FROM xf_profile_post_comment
            WHERE profile_post_id = ?
            ORDER BY comment_date
        "
, $this->profile_post_id);
    }

   
/**
     * @return ArrayCollection|null
     */
   
public function getLatestComments()
    {
       
$this->repository('XF:ProfilePost')->addCommentsToProfilePosts([$this->profile_post_id => $this]);

        if (isset(
$this->_getterCache['LatestComments']))
        {
            return
$this->_getterCache['LatestComments'];
        }
        else
        {
            return
$this->_em->getBasicCollection([]);
        }
    }

    public function
setLatestComments(array $latest)
    {
       
$this->_getterCache['LatestComments'] = $this->_em->getBasicCollection($latest);
    }

    public function
commentAdded(ProfilePostComment $comment)
    {
       
$this->comment_count++;

        if (!
$this->first_comment_date || $comment->comment_date < $this->first_comment_date)
        {
           
$this->first_comment_date = $comment->comment_date;
        }

        if (
$comment->comment_date > $this->last_comment_date)
        {
           
$this->last_comment_date = $comment->comment_date;
        }

       
$this->rebuildLatestCommentIds();

        unset(
$this->_getterCache['comment_ids']);
    }

    public function
commentRemoved(ProfilePostComment $comment)
    {
       
$this->comment_count--;

        if (
$this->first_comment_date == $comment->comment_date)
        {
            if (!
$this->comment_count)
            {
               
$this->first_comment_date = 0;
            }
            else
            {
               
$this->rebuildFirstCommentInfo();
            }
        }

        if (
$this->last_comment_date == $comment->comment_date)
        {
            if (!
$this->comment_count)
            {
               
$this->last_comment_date = 0;
            }
            else
            {
               
$this->rebuildLastCommentInfo();
            }
        }

       
$this->rebuildLatestCommentIds();

        unset(
$this->_getterCache['comment_ids']);
    }

    public function
rebuildCounters()
    {
        if (!
$this->rebuildFirstCommentInfo())
        {
           
// no visible comments, we know we've set the last comment and count to 0
       
}
        else
        {
           
$this->rebuildLastCommentInfo();
           
$this->rebuildCommentCount();
        }

       
// since this contains non-visible comments, we always have to rebuild
       
$this->rebuildLatestCommentIds();

        return
true;
    }

    public function
rebuildFirstCommentInfo()
    {
       
$firstComment = $this->db()->fetchRow("
            SELECT profile_post_comment_id, comment_date, user_id, username
            FROM xf_profile_post_comment
            WHERE profile_post_id = ?
                AND message_state = 'visible'
            ORDER BY comment_date
            LIMIT 1
        "
, $this->profile_post_id);

        if (!
$firstComment)
        {
           
$this->comment_count = 0;
           
$this->first_comment_date = 0;
           
$this->last_comment_date = 0;
            return
false;
        }
        else
        {
           
$this->first_comment_date = $firstComment['comment_date'];
            return
true;
        }
    }

    public function
rebuildLastCommentInfo()
    {
       
$lastComment = $this->db()->fetchRow("
            SELECT profile_post_comment_id, comment_date, user_id, username
            FROM xf_profile_post_comment
            WHERE profile_post_id = ?
                AND message_state = 'visible'
            ORDER BY comment_date DESC
            LIMIT 1
        "
, $this->profile_post_id);

        if (!
$lastComment)
        {
           
$this->comment_count = 0;
           
$this->first_comment_date = 0;
           
$this->last_comment_date = 0;
            return
false;
        }
        else
        {
           
$this->last_comment_date = $lastComment['comment_date'];
            return
true;
        }
    }

    public function
rebuildCommentCount()
    {
       
$visibleComments = $this->db()->fetchOne("
            SELECT COUNT(*)
            FROM xf_profile_post_comment
            WHERE profile_post_id = ?
                AND message_state = 'visible'
        "
, $this->profile_post_id);

       
$this->comment_count = $visibleComments;

        return
$this->comment_count;
    }

    public function
rebuildLatestCommentIds()
    {
       
$this->latest_comment_ids = $this->repository('XF:ProfilePost')->getLatestCommentCache($this);
    }

    public function
getBbCodeRenderOptions($context, $type)
    {
        return [
           
'entity' => $this,
           
'user' => $this->User,
           
'treatAsStructuredText' => true,
           
'attachments' => $this->attach_count ? $this->Attachments : [],
           
'viewAttachments' => $this->canViewAttachments(),
           
'unfurls' => $this->Unfurls ?: []
        ];
    }

    public function
getUnfurls()
    {
        return
$this->_getterCache['Unfurls'] ?? [];
    }

    public function
setUnfurls($unfurls)
    {
       
$this->_getterCache['Unfurls'] = $unfurls;
    }

    protected function
_postSave()
    {
       
$visibilityChange = $this->isStateChanged('message_state', 'visible');
       
$approvalChange = $this->isStateChanged('message_state', 'moderated');
       
$deletionChange = $this->isStateChanged('message_state', 'deleted');

        if (
$this->isUpdate())
        {
            if (
$visibilityChange == 'enter')
            {
               
$this->profilePostMadeVisible();

                if (
$approvalChange)
                {
                   
$this->submitHamData();
                }
            }
            else if (
$visibilityChange == 'leave')
            {
               
$this->profilePostHidden();
            }

            if (
$deletionChange == 'leave' && $this->DeletionLog)
            {
               
$this->DeletionLog->delete();
            }

            if (
$approvalChange == 'leave' && $this->ApprovalQueue)
            {
               
$this->ApprovalQueue->delete();
            }
        }

        if (
$approvalChange == 'enter')
        {
           
$approvalQueue = $this->getRelationOrDefault('ApprovalQueue', false);
           
$approvalQueue->content_date = $this->post_date;
           
$approvalQueue->save();
        }
        else if (
$deletionChange == 'enter' && !$this->DeletionLog)
        {
           
$delLog = $this->getRelationOrDefault('DeletionLog', false);
           
$delLog->setFromVisitor();
           
$delLog->save();
        }

        if (
$this->isUpdate() && $this->getOption('log_moderator'))
        {
           
$this->app()->logger()->logModeratorChanges('profile_post', $this);
        }
    }

    protected function
profilePostMadeVisible()
    {
    }

    protected function
profilePostHidden($hardDelete = false)
    {
       
/** @var \XF\Repository\UserAlert $alertRepo */
       
$alertRepo = $this->repository('XF:UserAlert');
       
$alertRepo->fastDeleteAlertsForContent('profile_post', $this->profile_post_id);
       
$alertRepo->fastDeleteAlertsForContent('profile_post_comment', $this->comment_ids);
    }

    protected function
submitHamData()
    {
       
/** @var \XF\Spam\ContentChecker $submitter */
       
$submitter = $this->app()->container('spam.contentHamSubmitter');
       
$submitter->submitHam('profile_post', $this->profile_post_id);
    }

    protected function
_postDelete()
    {
        if (
$this->message_state == 'visible')
        {
           
$this->profilePostHidden(true);
        }

        if (
$this->message_state == 'deleted' && $this->DeletionLog)
        {
           
$this->DeletionLog->delete();
        }

        if (
$this->message_state == 'moderated' && $this->ApprovalQueue)
        {
           
$this->ApprovalQueue->delete();
        }

        if (
$this->getOption('log_moderator'))
        {
           
$this->app()->logger()->logModeratorAction('profile_post', $this, 'delete_hard');
        }

       
/** @var \XF\Repository\Attachment $attachRepo */
       
$attachRepo = $this->repository('XF:Attachment');
       
$attachRepo->fastDeleteContentAttachments('profile_post', $this->profile_post_id);

       
$db = $this->db();
       
$commentIds = $this->comment_ids;
        if (
$commentIds)
        {
           
$quotedIds = $db->quote($commentIds);

           
$db->delete('xf_profile_post_comment', "profile_post_comment_id IN ({$quotedIds})");
           
$db->delete('xf_approval_queue', "content_id IN ({$quotedIds}) AND content_type = 'profile_post_comment'");
           
$db->delete('xf_deletion_log', "content_id IN ({$quotedIds}) AND content_type = 'profile_post_comment'");
        }
    }

    public function
softDelete($reason = '', User $byUser = null)
    {
       
$byUser = $byUser ?: \XF::visitor();

        if (
$this->message_state == 'deleted')
        {
            return
false;
        }

       
$this->message_state = 'deleted';

       
/** @var \XF\Entity\DeletionLog $deletionLog */
       
$deletionLog = $this->getRelationOrDefault('DeletionLog');
       
$deletionLog->setFromUser($byUser);
       
$deletionLog->delete_reason = $reason;

       
$this->save();

        return
true;
    }

    public function
getNewComment()
    {
       
$comment = $this->_em->create('XF:ProfilePostComment');
       
$comment->profile_post_id = $this->profile_post_id;

        return
$comment;
    }

    public function
getNewContentState()
    {
       
$visitor = \XF::visitor();

        if (
$visitor->user_id && $visitor->hasPermission('profilePost', 'approveUnapprove'))
        {
            return
'visible';
        }

        if (!
$visitor->hasPermission('general', 'submitWithoutApproval'))
        {
            return
'moderated';
        }

        return
'visible';
    }

   
/**
     * @param \XF\Api\Result\EntityResult $result
     * @param int $verbosity
     * @param array $options
     *
     * @api-out str $username
     * @api-out str $message_parsed HTML parsed version of the message contents.
     * @api-out bool $can_edit
     * @api-out bool $can_soft_delete
     * @api-out bool $can_hard_delete
     * @api-out bool $can_react
     * @api-out bool $can_view_attachments
     * @api-out string $view_url
     * @api-out User $ProfileUser <cond> If requested by context, the user this profile post was left for.
     * @api-out Attachment[] $Attachments <cond> Attachments to this profile post, if it has any.
     * @api-out ProfilePostComment[] $LatestComments <cond> If requested, the most recent comments on this profile post.
     * @api-see XF\Entity\ReactionTrait::addReactionStateToApiResult
     */
   
protected function setupApiResultData(
        \
XF\Api\Result\EntityResult $result, $verbosity = self::VERBOSITY_NORMAL, array $options = []
    )
    {
       
$result->username = $this->User ? $this->User->username : $this->username;

        if (!empty(
$options['with_profile']))
        {
           
$result->includeRelation('ProfileUser');
        }

        if (!empty(
$options['with_latest']))
        {
           
$result->includeGetter('LatestComments');
        }

        if (
$this->attach_count)
        {
           
// note that we allow viewing of thumbs and metadata, regardless of permissions, when viewing the
            // content an attachment is connected to
           
$result->includeRelation('Attachments');
        }

       
$result->message_parsed = $this->app()->bbCode()->render($this->message, 'apiHtml', 'profile_post:api', $this);

       
$this->addReactionStateToApiResult($result);

       
$result->can_edit = $this->canEdit();
       
$result->can_soft_delete = $this->canDelete();
       
$result->can_hard_delete = $this->canDelete('hard');
       
$result->can_react = $this->canReact();
       
$result->can_view_attachments = $this->canViewAttachments();

       
$result->view_url = $this->getContentUrl(true);
    }

    public function
getContentUrl(bool $canonical = false, array $extraParams = [], $hash = null)
    {
       
$route = $canonical ? 'canonical:profile-posts' : 'profile-posts';
        return
$this->app()->router('public')->buildLink($route, $this, $extraParams, $hash);
    }

    public function
getContentPublicRoute()
    {
        return
'profile-posts';
    }

    public function
getContentTitle(string $context = '')
    {
        return \
XF::phrase('profile_post_by_x', ['name' => $this->username]);
    }

    public static function
getStructure(Structure $structure)
    {
       
$structure->table = 'xf_profile_post';
       
$structure->shortName = 'XF:ProfilePost';
       
$structure->contentType = 'profile_post';
       
$structure->primaryKey = 'profile_post_id';
       
$structure->columns = [
           
'profile_post_id' => ['type' => self::UINT, 'autoIncrement' => true, 'nullable' => true],
           
'profile_user_id' => ['type' => self::UINT, 'required' => true, 'api' => true],
           
'user_id' => ['type' => self::UINT, 'required' => true, 'api' => true],
           
'username' => ['type' => self::STR, 'maxLength' => 50,
               
'required' => 'please_enter_valid_name'
           
],
           
'post_date' => ['type' => self::UINT, 'required' => true, 'default' => \XF::$time, 'api' => true],
           
'message' => ['type' => self::STR,
               
'required' => 'please_enter_valid_message', 'api' => true
           
],
           
'ip_id' => ['type' => self::UINT, 'default' => 0],
           
'message_state' => ['type' => self::STR, 'default' => 'visible',
               
'allowedValues' => ['visible', 'moderated', 'deleted'], 'api' => true
           
],
           
'attach_count' => ['type' => self::UINT, 'max' => 65535, 'forced' => true, 'default' => 0],
           
'warning_id' => ['type' => self::UINT, 'default' => 0],
           
'warning_message' => ['type' => self::STR, 'default' => '', 'maxLength' => 255, 'api' => true],
           
'comment_count' => ['type' => self::UINT, 'forced' => true, 'default' => 0, 'api' => true],
           
'first_comment_date' => ['type' => self::UINT, 'default' => 0, 'api' => true],
           
'last_comment_date' => ['type' => self::UINT, 'default' => 0, 'api' => true],
           
'latest_comment_ids' => ['type' => self::JSON_ARRAY, 'default' => []],
           
'embed_metadata' => ['type' => self::JSON_ARRAY, 'nullable' => true, 'default' => null]
        ];
       
$structure->behaviors = [
           
'XF:Reactable' => ['stateField' => 'message_state'],
           
'XF:ReactableContainer' => [
               
'childContentType' => 'profile_post_comment',
               
'childIds' => function($profilePost) { return $profilePost->comment_ids; },
               
'stateField' => 'message_state'
           
],
           
'XF:Indexable' => [
               
'checkForUpdates' => ['message', 'profile_user_id', 'user_id', 'post_date', 'message_state']
            ],
           
'XF:IndexableContainer' => [
               
'childContentType' => 'profile_post_comment',
               
'childIds' => function($profilePost) { return $profilePost->comment_ids; },
               
'checkForUpdates' => ['profile_user_id', 'message_state']
            ],
           
'XF:NewsFeedPublishable' => [
               
'usernameField' => 'username',
               
'dateField' => 'post_date'
           
]
        ];
       
$structure->getters = [
           
'comment_ids' => true,
           
'LatestComments' => true,
           
'Unfurls' => true,
        ];
       
$structure->relations = [
           
'ProfileUser' => [
               
'entity' => 'XF:User',
               
'type' => self::TO_ONE,
               
'conditions' => [['user_id', '=', '$profile_user_id']],
               
'primary' => true
           
],
           
'User' => [
               
'entity' => 'XF:User',
               
'type' => self::TO_ONE,
               
'conditions' => 'user_id',
               
'primary' => true,
               
'api' => true
           
],
           
'DeletionLog' => [
               
'entity' => 'XF:DeletionLog',
               
'type' => self::TO_ONE,
               
'conditions' => [
                    [
'content_type', '=', 'profile_post'],
                    [
'content_id', '=', '$profile_post_id']
                ],
               
'primary' => true
           
],
           
'ApprovalQueue' => [
               
'entity' => 'XF:ApprovalQueue',
               
'type' => self::TO_ONE,
               
'conditions' => [
                    [
'content_type', '=', 'profile_post'],
                    [
'content_id', '=', '$profile_post_id']
                ],
               
'primary' => true
           
],
           
'Comments' => [
               
'entity' => 'XF:ProfilePostComment',
               
'type' => self::TO_MANY,
               
'conditions' => 'profile_post_id',
               
'primary' => true
           
],
           
'Attachments' => [
               
'entity' => 'XF:Attachment',
               
'type' => self::TO_MANY,
               
'conditions' => [
                    [
'content_type', '=', 'profile_post'],
                    [
'content_id', '=', '$profile_post_id']
                ],
               
'with' => 'Data',
               
'order' => 'attach_date'
           
]
        ];
       
$structure->options = [
           
'log_moderator' => true
       
];

       
$structure->withAliases = [
           
'full' => [
               
'User',
                function()
                {
                   
$userId = \XF::visitor()->user_id;
                    if (
$userId)
                    {
                        return
'Reactions|' . $userId;
                    }

                    return
null;
                }
            ],
           
'fullProfile' => ['full', 'ProfileUser', 'ProfileUser.Privacy'],
           
'api' => [
               
'User',
               
'User.api',
                function(
$withParams)
                {
                    if (!empty(
$withParams['profile']))
                    {
                        return [
'ProfileUser.api'];
                    }
                }
            ]
        ];

        static::
addReactableStructureElements($structure);

        return
$structure;
    }
}