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

XenForo Helper

Discussion in 'XenForo Development Discussions' started by Robust, Apr 24, 2015.

  1. Robust

    Robust Well-Known Member

    I have this helper:
    Code:
    <?php
    
    class BestAnswer_Helper_VoteStatus
    {
        public static function checkVoteStatus($postId, $userId)
        {
            $baPostModel = self::_getBaPostModel();
            $existingBestAnswer = $baPostModel->getCurrentBestAnswerStatusOnPost($postId, $userId);
    
            return ($existingBestAnswer ? false : true);
        }
    
        /**
         * @return BestAnswer_Model_Post
         */
        protected function _getBaPostModel()
        {
            return $this->getModelFromCache('BestAnswer_Model_Post');
        }
    }
    It's used like this I think:
    Code:
    <xen:if is="<xen:if is="{xen:helper voteStatus, $post['post_id'], $visitor['user_id']}">{xen:phrase bestanswer_vote}<else>{xen:phrase bestanswer_unvote}</xen:if>
    
    Neither Vote or Unvote is shown. the getCurrentBestAnswerStatusOnPost basically does this:

    Code:
        /**
         * Gets a best answer content record for a user that has voted on a piece of content.
         *
         * @param integer $postId
         * @param integer $userId
         *
         * @return array|false
         */
        public function getCurrentBestAnswerStatusOnPost($postId, $userId)
        {
            return $this->_getDb()->fetchRow('
                SELECT *
                FROM ba_votes
                WHERE post_id = ?
                    AND ba_user_id = ?
            ', array($postId, $userId));
        }
    What am I doing wrong?
     
  2. Chris D

    Chris D XenForo Developer Staff Member

    There are a few problems:

    Code:
    <else>
    That's not a valid tag, you'd be looking to use:

    Code:
    <xen:else />
    Also:

    Code:
    $post['post_id']
    This is not a valid way to reference template params, even in helpers it should be:

    Code:
    {$post.post_id}
     
    Marcus likes this.
  3. Robust

    Robust Well-Known Member

    @Chris D Thanks! Now it just shows unvote all of the time. There is no entry in ba_votes though.
     
  4. Robust

    Robust Well-Known Member

    I have a feeling a helper isn't what I need to use. Basically, I have $voted, which returns true or false based on whether the post has been voted for or not. Similar to how the like feature works. I show the phrase bestanswer_vote if $voted is false, and bestanswer_unvote if $voted is true (user has already voted, so the option is to unvote).

    ViewPublic + a helper is what I'm currently using to represent this in the controller class, this is a different template though. I can use $voted there which makes it a lot easier (<xen:if is="$voted">...<xen:else />...</xen:if>). If I could use $voted in the template post somehow I could go about this. I'm not really sure how to do this at this point.
     
  5. Chris D

    Chris D XenForo Developer Staff Member

    A helper isn't completely unreasonable though it depends on exactly what you're trying to do.

    If the function is to be frequently used in a template, then clearly it is quite convenient.

    You say you now get the "unvote" phrase, I think that's expected because I think this:
    Code:
    return ($existingBestAnswer ? false : true);
    Should be:
    Code:
    return ($existingBestAnswer ? true : false);
     
  6. Robust

    Robust Well-Known Member

    Yeah, I tried that. Same thing. I've tried removing that (debug purposes) and just trying return true; return false;, both give me the unvote phrase, which is strange. It's like it's ignoring the output from the helper.
     
  7. Chris D

    Chris D XenForo Developer Staff Member

    I've made an assumption that you actually have the helper enabled, can you share the rest of the code e.g. where the helper is enabled and initialised?

    Also I only just noticed this but there seems to be an additional xen:if here:

    Code:
    <xen:if is="<xen:if is="{xen:helper voteStatus, $post['post_id'], $visitor['user_id']}">{xen:phrase bestanswer_vote}<else>{xen:phrase bestanswer_unvote}</xen:if>
    What does this code look like now you've fixed it?
     
  8. Robust

    Robust Well-Known Member

    Template Modification, template post:

    Find:
    Code:
    <a href="{xen:link posts/report, $post}" class="OverlayTrigger item control report" data-cacheOverlay="false"><span></span>{xen:phrase report}</a>
                    </xen:if>
    Replace:
    Code:
    $0
    
    <xen:if is="{$visitor.permissions.bestAnswerPermissions.markBestAnswer}"><a href="{xen:link posts/bestAnswer, $post}" class="item control <xen:if is="{xen:helper voteStatus, {$post.post_id}, {$visitor.user_id}}">vote<xen:else />unvote</xen:if>"><span></span><xen:if is="{xen:helper voteStatus, {$post.post_id}, {$visitor.user_id}}">{xen:phrase bestanswer_vote}<xen:else />{xen:phrase bestanswer_unvote}</xen:if></a></xen:if>
    init_dependencies listener (screenshot attached)
    Class:
    PHP:
    <?php

    class BestAnswer_Listener_Helper
    {
        public static function 
    init(XenForo_Dependencies_Abstract $dependencies, array $data)
        {
            
    XenForo_Template_Helper_Core::$helperCallbacks += array(
                
    'voteStatus' => array('BestAnswer_Helper_VoteStatus''checkVoteStatus')
            );
        }
    }
     

    Attached Files:

  9. Robust

    Robust Well-Known Member

    @Chris D Actually, I don't think the helper is working somehow. I put this in a template:

    {xen:helper voteStatus, 6, 1}

    post 6, visitor userid 1. It displayed nothing, but it should have displayed 1 or 0 right?
     
  10. Chris D

    Chris D XenForo Developer Staff Member

    There's definitely something not right, but all of the code looks good.

    You don't have listeners disabled in config.php or anything do you?

    If you want to package it up and PM it to me, I don't mind trying it myself.
     
  11. NixFifty

    NixFifty Well-Known Member

    Okay, I had a similar issue with an add-on I recently made. Try this:

    PHP:
    <?php

    class BestAnswer_Listener_Helper
    {
        public static function 
    init(XenForo_Dependencies_Abstract $dependencies, array $data)
        {
            
    XenForo_Template_Helper_Core::$helperCallbacks += array(
                
    'votestatus' => array('BestAnswer_Helper_VoteStatus''checkVoteStatus')
            );
        }
    }
    I found out that the helper name needed to be lowercase for some reason so that is what I changed in this bit of code. See if it works.
     
    Marcus and Robust like this.
  12. Chris D

    Chris D XenForo Developer Staff Member

    Well spotted - I missed the case.

    The reason is this:
    PHP:
    public static function callHelper($helper, array $args)
    {
        
    $helper strtolower(strval($helper));
        if (!isset(
    self::$helperCallbacks[$helper]))
        {
            return 
    '';
        }

        return 
    call_user_func_array(self::$helperCallbacks[$helper], $args);
    }
     
    Robust and NixFifty like this.
  13. Robust

    Robust Well-Known Member

    Perfect! Thank you both :) Works like a charm now. Looks like I got carried away coding and did a woopsie here too:
    Code:
    return $this->getModelFromCache('BestAnswer_Model_Post');
    1. $this
    2. getModelFromCache

    Fixed that one too, works like a charm. All actual functionality is done now. It's just styling.
     
  14. Robust

    Robust Well-Known Member

    @Chris D @NixFifty One other thing. The Like feature doesn't redirect anywhere, it just has that loading thing. Similarly, when posting a reply it doesn't redirect, but it has that box at the top. When someone hits Vote/Unvote, how can I not direct to the controller page but instead just show a message on the same page (similar to when a reply happens) with a message like Your vote has been added / Your vote has been removed.
     
  15. Chris D

    Chris D XenForo Developer Staff Member

    That would require some custom JS code.
     
  16. Robust

    Robust Well-Known Member

    What does the reply one use? I guess I can fetch it from there and adjust it. Or I can just show the loading thing like the Like button does if it's significantly easier.
     
  17. Chris D

    Chris D XenForo Developer Staff Member

    I would probably use the Like stuff for reference as it has a similar pattern.
     
  18. Robust

    Robust Well-Known Member

    @Chris D So I'd be looking to use an OverlayTrigger? Any classes/templates I can look at for this, I don't really get how to do it.

    Also, shouldn't I be verifying the user's XF token somewhere and sending a post request? I'm not sure how exactly the like function works, I managed to replicate it to this point but there's the class post_like and I don't have a clue where that one is loaded

    Code:
    <xen:title>{xen:helper threadPrefix, $thread, escaped}{$thread.title} - {xen:if $like, '{xen:phrase unlike_post}', '{xen:phrase like_post}'}</xen:title>
    <xen:h1>{xen:if $like, '{xen:phrase unlike_post}', '{xen:phrase like_post}'}</xen:h1>
    
    <xen:navigation>
        <xen:breadcrumb source="$nodeBreadCrumbs" />
        <xen:breadcrumb href="{xen:link full:posts, $post}">{xen:helper threadPrefix, $thread}{$thread.title}</xen:breadcrumb>
    </xen:navigation>
    
    <xen:container var="$bodyClasses">{xen:helper nodeClasses, $nodeBreadCrumbs, $forum}</xen:container>
    <xen:container var="$searchBar.thread"><xen:include template="search_bar_thread_only" /></xen:container>
    <xen:container var="$searchBar.forum"><xen:include template="search_bar_forum_only" /></xen:container>
    
    <form action="{xen:link 'posts/like', $post}" method="post" class="xenForm">
    
        <dl class="ctrlUnit fullWidth surplusLabel">
            <dt></dt>
            <dd>
                <xen:if is="{$like}">
                    {xen:phrase you_sure_you_want_to_unlike_this_post}
                <xen:else />
                    {xen:phrase you_sure_you_want_to_like_this_post}
                </xen:if>
            </dd>
        </dl>
    
        <dl class="ctrlUnit submitUnit">
            <dt></dt>
            <dd><input type="submit" value="{xen:if $like, '{xen:phrase unlike_post}', '{xen:phrase like_post}'}" accesskey="s" class="button primary" autofocus="true" /></dd>
        </dl>
    
        <input type="hidden" name="_xfToken" value="{$visitor.csrf_token_page}" />
    </form>
    
    But in the post template it has this:

    Code:
                    <xen:if is="{$post.canLike}">
                        <a href="{xen:link posts/like, $post}" class="LikeLink item control {xen:if $post.like_date, unlike, like}" data-container="#likes-post-{$post.post_id}"><span></span><span class="LikeLabel">{xen:if $post.like_date, {xen:phrase unlike}, {xen:phrase like}}</span></a>
                    </xen:if>
    
     
  19. Chris D

    Chris D XenForo Developer Staff Member

    As I said, it would require custom JS code. So you would find the JS for the existing Like button in xenforo.js.

    As a pointer, typically when a class name on an element begins with a capital letter, that should signify that the class is used as a JS selector more so than being a styling CSS selector.

    With that in mind, the class of the like link is "LikeLink" so you can probably find that in xenforo.js somewhere for some pointers.
     

Share This Page