Lack of interest [Development Tool] Thread Criteria

This suggestion has been closed automatically because it did not receive enough votes over an extended period of time. If you wish to see this, please search for an open suggestion and, if you don't find any, post a new one.

DragonByte Tech

Well-known member
I am writing a support ticket system as a companion piece to my eCommerce mod. Threads was the perfect choice for powering this system due to the power of thread fields and thread prefixes, with some custom extensions for things like ticket status and assigned user.

In order to automate certain actions for support tickets, having a "thread criteria" system similar to user criteria would be beneficial. I'm sure this could have its uses for the XF core as well, in order to allow forum admins to create automated actions such as automated archiving, automated closure of old threads, etc.

I'm still building this system so I don't have code to share right now, but if I remember this thread when I'm all done I'll be sure to post the template and PHP code for evaluation :)


Fillip
 
Upvote 1
This suggestion has been closed. Votes are no longer accepted.
I'm like 75% certain this works now, so as promised here's the code. If this doesn't get put into core and you implement this in your own addon, please remember to namespace the phrases and the code (including the code event) :)

This isn't a tutorial for how to implement thread criteria, so if you're not familiar with how to implement and how to check user criteria then start with that before looking at this code. Advanced users only, etc.

helper_criteria macro template:
HTML:
<xf:macro name="thread_tabs" arg-container="" arg-threadTabTitle="" arg-active="">
    <xf:set var="$tabs">
        <a class="tabs-tab{{ $active == 'thread' ? ' is-active' : '' }}"
            role="tab" tabindex="0" aria-controls="{{ unique_id('criteriaThread') }}">
            {{ $threadTabTitle ? $threadTabTitle : phrase('thread_criteria') }}</a>
        <a class="tabs-tab{{ $active == 'thread_field' ? ' is-active' : '' }}"
            role="tab" tabindex="0" aria-controls="{{ unique_id('criteriaThreadField') }}">
            {{ phrase('custom_threadfield_criteria') }}</a>
    </xf:set>
    <xf:if is="$container">
        <div class="tabs" role="tablist">
            {$tabs|raw}
        </div>
    <xf:else />
        {$tabs|raw}
    </xf:if>
</xf:macro>

<xf:macro name="thread_panes" arg-container="" arg-active="" arg-criteria="!" arg-data="!">

    <xf:set var="$app" value="{$xf.app}" />
    <xf:set var="$visitor" value="{$xf.visitor}" />
    <xf:set var="$em" value="{$app.em}" />

    <xf:set var="$panes">
        <li class="{{ $active == 'thread' ? ' is-active' : '' }}" role="tabpanel" id="{{ unique_id('criteriaThread') }}">
            <!--[XF:thread:top]-->

            <xf:checkboxrow label="{{ phrase('thread_criteria_thread') }}">
                <!--[XF:thread:thread_top]-->

                <xf:option name="thread_criteria[forum][rule]" value="forum" selected="{$criteria.forum}"
                           label="{{ phrase('thread_criteria_thread_is_in_forum:') }}">

                    <xf:dependent>
                        <ul class="inputList">
                            <li><xf:select name="thread_criteria[forum][data][forum_ids]" value="{$criteria.forum.forum_ids}" size="7" multiple="multiple" id="js-applicableForums">

                                <xf:option value="" selected="!{$criteria.forum.forum_ids}">{{ phrase('(none)') }}</xf:option>

                                <xf:foreach loop="$data.nodeTree.getFlattened(0)" value="$treeEntry">
                                    <xf:option value="{$treeEntry.record.node_id}"
                                               disabled="{{ $treeEntry.record.node_type_id != 'Forum' }}"
                                               label="{{ repeat('&nbsp;&nbsp;', $treeEntry.depth)|raw }} {$treeEntry.record.title}" />
                                </xf:foreach>

                            </xf:select></li>

                            <xf:checkbox>
                                <xf:option label="{{ phrase('select_all') }}" id="js-selectAllForums" />
                            </xf:checkbox>
                        </ul>
                    </xf:dependent>

                </xf:option>

                <xf:if is="$data.prefixesGrouped is not empty">
                    <xf:option name="thread_criteria[prefix][rule]" value="prefix" selected="{$criteria.prefix}"
                               label="{{ phrase('thread_criteria_thread_has_prefix:') }}">

                        <xf:dependent>
                            <xf:checkbox name="thread_criteria[prefix][data][prefix_ids]" value="{$criteria.prefix.prefix_ids}">

                                <xf:foreach loop="$data.prefixGroups" key="$prefixGroupId" value="$prefixGroup" if="{$data.prefixesGrouped.{$prefixGroupId}}">

                                    <xf:optgroup check-all="true" listclass="listColumns"
                                                 label="{{ $prefixGroupId ? $prefixGroup.title : phrase('ungrouped') }}">

                                        <xf:foreach loop="{$data.prefixesGrouped.{$prefixGroupId}}" key="$prefixId" value="$prefix">
                                            <xf:option value="{$prefixId}" selected="{$forum.prefix_cache.{$prefixId}}">
                                                <xf:label><span class="label {$prefix.css_class}">{$prefix.title}</span></xf:label>
                                            </xf:option>
                                        </xf:foreach>
                                    </xf:optgroup>
                                </xf:foreach>
                            </xf:checkbox>
                        </xf:dependent>
                    </xf:option>

                </xf:if>

                <xf:option name="thread_criteria[reply_count][rule]" value="reply_count" selected="{$criteria.reply_count}"
                           label="{{ phrase('thread_criteria_reply_count_at_least_x:') }}">
                    <xf:numberbox name="thread_criteria[reply_count][data][messages]" value="{$criteria.reply_count.messages}"
                                  size="5" min="0" step="1" />
                </xf:option>

                <xf:option name="thread_criteria[reply_count_maximum][rule]" value="reply_count_maximum" selected="{$criteria.reply_count_maximum}"
                           label="{{ phrase('thread_criteria_reply_count_maximum_x:') }}">
                    <xf:numberbox name="thread_criteria[reply_count_maximum][data][messages]" value="{$criteria.reply_count_maximum.messages}"
                                  size="5" min="0" step="1" />
                </xf:option>

                <xf:option name="thread_criteria[view_count][rule]" value="view_count" selected="{$criteria.view_count}"
                           label="{{ phrase('thread_criteria_view_count_at_least_x:') }}">
                    <xf:numberbox name="thread_criteria[view_count][data][amount]" value="{$criteria.view_count.amount}"
                                  size="5" min="0" step="1" />
                </xf:option>

                <xf:option name="thread_criteria[view_count_maximum][rule]" value="view_count_maximum" selected="{$criteria.view_count_maximum}"
                           label="{{ phrase('thread_criteria_view_count_maximum_x:') }}">
                    <xf:numberbox name="thread_criteria[view_count_maximum][data][amount]" value="{$criteria.view_count_maximum.amount}"
                                  size="5" min="0" step="1" />
                </xf:option>

                <xf:option name="thread_criteria[discussion_state][rule]" value="discussion_state" selected="{$criteria.discussion_state}"
                           label="{{ phrase('thread_criteria_thread_state_is:') }}">

                    <xf:dependent>
                        <xf:select name="thread_criteria[discussion_state][data][state]" value="{$criteria.discussion_state.state}">
                            <xf:option value="visible">{{ phrase('visible') }}</xf:option>
                            <xf:option value="moderated">{{ phrase('awaiting_approval') }}</xf:option>
                            <xf:option value="deleted">{{ phrase('deleted') }}</xf:option>
                        </xf:select>
                    </xf:dependent>

                </xf:option>

                <xf:optgroup label="{{ phrase('open:') }}">
                    <xf:option name="thread_criteria[is_open][rule]" value="is_open" selected="{$criteria.is_open}"
                               label="{{ phrase('thread_is_open') }}" />

                    <xf:option name="thread_criteria[no_open][rule]" value="no_open" selected="{$criteria.no_open}"
                               label="{{ phrase('thread_is_not_open') }}" />
                </xf:optgroup>

                <xf:optgroup label="{{ phrase('sticky:') }}">
                    <xf:option name="thread_criteria[is_sticky][rule]" value="is_sticky" selected="{$criteria.is_sticky}"
                               label="{{ phrase('thread_is_sticky') }}" />

                    <xf:option name="thread_criteria[no_sticky][rule]" value="no_sticky" selected="{$criteria.no_sticky}"
                               label="{{ phrase('thread_is_not_sticky') }}" />
                </xf:optgroup>

                <!--[XF:thread:thread_bottom]-->
            </xf:checkboxrow>

            <hr class="formRowSep" />

            <xf:checkboxrow label="{{ phrase('thread_criteria_starter') }}">
                <!--[XF:thread:starter_top]-->

                <xf:option name="thread_criteria[starter_is_guest][rule]" value="starter_is_guest" selected="{$criteria.starter_is_guest}"
                           label="{{ phrase('thread_criteria_starter_is_guest') }}" />

                <xf:option name="thread_criteria[starter_is_member][rule]" value="starter_is_member" selected="{$criteria.starter_is_member}"
                           label="{{ phrase('thread_criteria_starter_is_member') }}" />

                <xf:option name="thread_criteria[starter_is_moderator][rule]" value="starter_is_moderator" selected="{$criteria.starter_is_moderator}"
                           label="{{ phrase('thread_criteria_starter_is_moderator') }}" />

                <xf:option name="thread_criteria[starter_is_admin][rule]" value="starter_is_admin" selected="{$criteria.starter_is_admin}"
                           label="{{ phrase('thread_criteria_starter_is_administrator') }}" />

                <xf:option name="thread_criteria[starter_time][rule]" value="starter_time" selected="{$criteria.starter_time}"
                           label="{{ phrase('thread_criteria_starter_time_at_least_x_days:') }}">
                    <xf:numberbox name="thread_criteria[starter_time][data][days]" value="{$criteria.starter_time.days}"
                                  size="5" min="0" step="1" />
                </xf:option>

                <xf:option name="thread_criteria[starter_like_count][rule]" value="starter_like_count" selected="{$criteria.starter_like_count}"
                           label="{{ phrase('thread_criteria_first_post_likes_at_least_x:') }}">
                    <xf:numberbox name="thread_criteria[starter_like_count][data][likes]" value="{$criteria.starter_like_count.likes}"
                                  size="5" min="0" step="1" />
                </xf:option>

                <xf:option name="thread_criteria[starter_username][rule]" value="starter_username" selected="{$criteria.starter_username}"
                           label="{{ phrase('username_is:') }}">
                    <xf:textbox name="thread_criteria[starter_username][data][names]" value="{$criteria.starter_username.names}" ac="true" />
                    <xf:afterhint>{{ phrase('username_criteria_explain') }}</xf:afterhint>

                </xf:option>

                <xf:option name="thread_criteria[starter_username_search][rule]" value="starter_username_search" selected="{$criteria.starter_username_search}"
                           label="{{ phrase('username_contains:') }}">
                    <xf:textbox name="thread_criteria[starter_username_search][data][needles]" value="{$criteria.starter_username_search.needles}" />
                    <xf:afterhint>{{ phrase('username_search_criteria_explain') }}</xf:afterhint>
                </xf:option>

                <!--[XF:thread:starter_bottom]-->
            </xf:checkboxrow>

            <hr class="formRowSep" />

            <!--[XF:user:after_starter]-->

            <xf:checkboxrow label="{{ phrase('thread_criteria_last_reply') }}">
                <!--[XF:thread:last_reply_top]-->

                <xf:option name="thread_criteria[last_reply_is_guest][rule]" value="last_reply_is_guest" selected="{$criteria.last_reply_is_guest}"
                           label="{{ phrase('thread_criteria_last_reply_is_guest') }}" />

                <xf:option name="thread_criteria[last_reply_is_member][rule]" value="last_reply_is_member" selected="{$criteria.last_reply_is_member}"
                           label="{{ phrase('thread_criteria_last_reply_is_member') }}" />

                <xf:option name="thread_criteria[last_reply_is_starter][rule]" value="last_reply_is_starter" selected="{$criteria.last_reply_is_starter}"
                           label="{{ phrase('thread_criteria_last_reply_is_starter') }}" />

                <xf:option name="thread_criteria[last_reply_not_starter][rule]" value="last_reply_not_starter" selected="{$criteria.last_reply_not_starter}"
                           label="{{ phrase('thread_criteria_last_reply_not_starter') }}" />

                <xf:option name="thread_criteria[last_reply_is_moderator][rule]" value="last_reply_is_moderator" selected="{$criteria.last_reply_is_moderator}"
                           label="{{ phrase('thread_criteria_last_reply_is_moderator') }}" />

                <xf:option name="thread_criteria[last_reply_is_admin][rule]" value="last_reply_is_admin" selected="{$criteria.last_reply_is_admin}"
                           label="{{ phrase('thread_criteria_last_reply_is_administrator') }}" />

                <xf:option name="thread_criteria[last_reply_time][rule]" value="last_reply_time" selected="{$criteria.last_reply_time}"
                           label="{{ phrase('thread_criteria_last_reply_time_at_least_x_days:') }}">
                    <xf:numberbox name="thread_criteria[last_reply_time][data][days]" value="{$criteria.last_reply_time.days}"
                                  size="5" min="0" step="1" />
                </xf:option>

                <xf:option name="thread_criteria[last_reply_username][rule]" value="last_reply_username" selected="{$criteria.last_reply_username}"
                           label="{{ phrase('username_is:') }}">
                    <xf:textbox name="thread_criteria[last_reply_username][data][names]" value="{$criteria.last_reply_username.names}" ac="true" />
                    <xf:afterhint>{{ phrase('username_criteria_explain') }}</xf:afterhint>

                </xf:option>

                <xf:option name="thread_criteria[last_reply_username_search][rule]" value="last_reply_username_search" selected="{$criteria.last_reply_username_search}"
                           label="{{ phrase('username_contains:') }}">
                    <xf:textbox name="thread_criteria[last_reply_username_search][data][needles]" value="{$criteria.last_reply_username_search.needles}" />
                    <xf:afterhint>{{ phrase('username_search_criteria_explain') }}</xf:afterhint>
                </xf:option>
                <!--[XF:thread:last_reply_bottom]-->
            </xf:checkboxrow>

            <hr class="formRowSep" />

            <!--[XF:thread:bottom]-->
        </li>

        <li class="{{ $active == 'thread_field' ? 'is-active' : '' }}" role="tabpanel" id="{{ unique_id('criteriaThreadField') }}">
            <xf:if contentcheck="true">
                <xf:contentcheck>
                    <xf:foreach loop="$xf.app.em.getRepository('XF:ThreadField').getDisplayGroups()" key="$fieldGroup" value="$groupPhrase">

                        <xf:set var="$customFields" value="{$app.getCustomFields('threads', $fieldGroup)}" />
                        <xf:if contentcheck="true">
                            <h2 class="block-formSectionHeader"><span class="block-formSectionHeader-aligner">{$groupPhrase}</span></h2>
                            <xf:contentcheck>
                                <xf:foreach loop="$customFields" key="$fieldId" value="$fieldDefinition">
                                    <xf:set var="$fieldName" value="thread_field_{$fieldId}" />
                                    <xf:set var="$choices" value="{$fieldDefinition.field_choices}" />
                                    <xf:checkboxrow label="{$fieldDefinition.title}">
                                        <xf:option name="thread_criteria[{$fieldName}][rule]" value="{$fieldName}" selected="{$criteria.{$fieldName}}"
                                            label="{{ $choices ? phrase('criteria_threadfield_choice_among') : phrase('criteria_threadfield_contains_text:') }}">
                                            <xf:dependent>
                                                <xf:if is="!{$choices}">
                                                    <xf:textbox name="thread_criteria[{$fieldName}][data][text]" value="{$criteria.{$fieldName}.text}" />
                                                <xf:elseif is="{{ count($choices) }} > 6" />
                                                    <xf:select name="thread_criteria[{$fieldName}][data][choices]" value="{$criteria.{$fieldName}.choices}" multiple="multiple" size="5">
                                                        <xf:options source="{$choices}" />
                                                    </xf:select>
                                                <xf:else />
                                                    <xf:checkbox name="thread_criteria[{$fieldName}][data][choices]" value="{$criteria.{$fieldName}.choices}" listclass="listColumns">
                                                        <xf:options source="{$choices}" />
                                                    </xf:checkbox>
                                                </xf:if>
                                            </xf:dependent>
                                        </xf:option>
                                    </xf:checkboxrow>
                                </xf:foreach>
                            </xf:contentcheck>
                        </xf:if>

                    </xf:foreach>
                </xf:contentcheck>
            <xf:else />
                {{ phrase('no_custom_fields_have_been_created_yet') }}
            </xf:if>
        </li>
    </xf:set>

    <xf:if is="$container">
        <ul class="tabPanes">
            {$panes|raw}
        </ul>
    <xf:else />
        {$panes|raw}
    </xf:if>

    <xf:js>
        $(function()
        {
            $('#js-selectAllForums').click(function(e)
            {
                $('#js-applicableForums').find('option:enabled:not([value=""])').prop('selected', this.checked);
            });
        });
    </xf:js>
</xf:macro>

Fillip
 
\XF\Criteria\Thread class:
PHP:
<?php

namespace XF\Criteria;

class Thread extends AbstractCriteria
{
    /**
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    public function isMatchedThread(\XF\Entity\Thread $thread)
    {
        if (!$this->criteria)
        {
            return $this->matchOnEmpty;
        }
        
        foreach ($this->criteria AS $criterion)
        {
            $rule = $criterion['rule'];
            $data = $criterion['data'];
            
            $specialResult = $this->isSpecialMatchedThread($rule, $data, $thread);
            if ($specialResult === false)
            {
                return false;
            }
            else if ($specialResult === true)
            {
                continue;
            }
            
            $method = '_matchThread' . \XF\Util\Php::camelCase($rule);
            if (method_exists($this, $method))
            {
                $result = $this->$method($data, $thread);
                if (!$result)
                {
                    return false;
                }
            }
            else
            {
                if (!$this->isUnknownMatchedThread($rule, $data, $thread))
                {
                    return false;
                }
            }
        }
        
        return true;
    }
    
    /**
     * @param $rule
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool|null
     */
    protected function isSpecialMatchedThread($rule, array $data, \XF\Entity\Thread $thread)
    {
        // custom user fields
        if (preg_match('/^thread_field_(.+)$/', $rule, $matches))
        {
            /** @var \XF\CustomField\Set|null $cFS */
            $cFS = $thread->thread_id ? $thread->custom_fields : null;
            
            $fieldId = $matches[1];
            
            if (!$cFS || !isset($cFS->{$fieldId}))
            {
                return false;
            }
            
            $value = $cFS->{$fieldId};
            
            // text fields - check that data exists within the text value
            if (isset($data['text']))
            {
                if (stripos($value, $data['text']) === false)
                {
                    return false;
                }
            }
            // choice fields - check that data is in the choice array
            else if (isset($data['choices']))
            {
                // multi-choice
                if (is_array($value))
                {
                    if (!array_intersect($value, $data['choices']))
                    {
                        return false;
                    }
                }
                // single choice
                else
                {
                    if (!in_array($value, $data['choices']))
                    {
                        return false;
                    }
                }
            }
            
            return true;
        }
        
        return null;
    }
    
    /**
     * @param $rule
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function isUnknownMatchedThread($rule, array $data, \XF\Entity\Thread $thread)
    {
        $eventReturnValue = false;
        $this->app->fire('criteria_thread', [$rule, $data, $thread, &$eventReturnValue]);
        
        return $eventReturnValue;
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadForum(array $data, \XF\Entity\Thread $thread)
    {
        return ($thread->node_id && in_array($thread->node_id, $data['forum_ids']));
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadPrefix(array $data, \XF\Entity\Thread $thread)
    {
        return ($thread->prefix_id && in_array($thread->prefix_id, $data['prefix_ids']));
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadReplyCount(array $data, \XF\Entity\Thread $thread)
    {
        return ($thread->reply_count && $thread->reply_count >= $data['messages']);
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadReplyCountMaximum(array $data, \XF\Entity\Thread $thread)
    {
        return ($thread->reply_count <= $data['messages']);
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadViewCount(array $data, \XF\Entity\Thread $thread)
    {
        return ($thread->view_count && $thread->view_count >= $data['amount']);
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadViewCountMaximum(array $data, \XF\Entity\Thread $thread)
    {
        return ($thread->view_count <= $data['amount']);
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadDiscussionState(array $data, \XF\Entity\Thread $thread)
    {
        return ($thread->discussion_state && $thread->discussion_state == $data['state']);
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadIsOpen(array $data, \XF\Entity\Thread $thread)
    {
        return (bool)$thread->discussion_open;
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadNoOpen(array $data, \XF\Entity\Thread $thread)
    {
        return $thread->discussion_open ? false : true;
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadIsSticky(array $data, \XF\Entity\Thread $thread)
    {
        return (bool)$thread->sticky;
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadNoSticky(array $data, \XF\Entity\Thread $thread)
    {
        return $thread->sticky ? false : true;
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadStarterIsGuest(array $data, \XF\Entity\Thread $thread)
    {
        return ($thread->user_id == 0);
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadStarterIsMember(array $data, \XF\Entity\Thread $thread)
    {
        return ($thread->user_id > 0);
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadStarterIsModerator(array $data, \XF\Entity\Thread $thread)
    {
        if (!$thread->User)
        {
            return false;
        }
        
        return (bool)$thread->User->is_moderator;
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadStarterIsAdmin(array $data, \XF\Entity\Thread $thread)
    {
        if (!$thread->User)
        {
            return false;
        }
        
        return (bool)$thread->User->is_admin;
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadStarterTime(array $data, \XF\Entity\Thread $thread)
    {
        if (!$thread->post_date)
        {
            return false;
        }
        $threadAge = floor((time() - $thread->post_date) / 86400);
        if ($threadAge < $data['days'])
        {
            return false;
        }
        
        return true;
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadStarterLikeCount(array $data, \XF\Entity\Thread $thread)
    {
        return ($thread->first_post_likes && $thread->first_post_likes >= $data['likes']);
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadStarterUsername(array $data, \XF\Entity\Thread $thread)
    {
        if (!$thread->username)
        {
            return false;
        }
        
        $names = preg_split('/\s*,\s*/', utf8_strtolower($data['names']), -1, PREG_SPLIT_NO_EMPTY);
        return in_array(utf8_strtolower($thread->username), $names);
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadStarterUsernameSearch(array $data, \XF\Entity\Thread $thread)
    {
        if (!$thread->username)
        {
            return false;
        }
        
        if ($this->findNeedle($data['needles'], $thread->username) === false)
        {
            return false;
        }
        else
        {
            return true;
        }
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadLastReplyIsGuest(array $data, \XF\Entity\Thread $thread)
    {
        return ($thread->last_post_user_id == 0);
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadLastReplyIsMember(array $data, \XF\Entity\Thread $thread)
    {
        return ($thread->last_post_user_id > 0);
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadLastReplyIsStarter(array $data, \XF\Entity\Thread $thread)
    {
        return ($thread->last_post_user_id == $thread->user_id);
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadLastReplyIsModerator(array $data, \XF\Entity\Thread $thread)
    {
        if (!$thread->LastPoster)
        {
            return false;
        }
        
        return (bool)$thread->LastPoster->is_moderator;
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadLastReplyIsAdmin(array $data, \XF\Entity\Thread $thread)
    {
        if (!$thread->LastPoster)
        {
            return false;
        }
        
        return (bool)$thread->LastPoster->is_admin;
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadLastReplyTime(array $data, \XF\Entity\Thread $thread)
    {
        if (!$thread->last_post_date)
        {
            return false;
        }
        $lastReplyAge = floor((time() - $thread->last_post_date) / 86400);
        if ($lastReplyAge < $data['days'])
        {
            return false;
        }
        
        return true;
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadLastReplyUsername(array $data, \XF\Entity\Thread $thread)
    {
        if (!$thread->last_post_username)
        {
            return false;
        }
        
        $names = preg_split('/\s*,\s*/', utf8_strtolower($data['names']), -1, PREG_SPLIT_NO_EMPTY);
        return in_array(utf8_strtolower($thread->last_post_username), $names);
    }
    
    /**
     * @param array $data
     * @param \XF\Entity\Thread $thread
     *
     * @return bool
     */
    protected function _matchThreadLastReplyUsernameSearch(array $data, \XF\Entity\Thread $thread)
    {
        if (!$thread->last_post_username)
        {
            return false;
        }
        
        if ($this->findNeedle($data['needles'], $thread->last_post_username) === false)
        {
            return false;
        }
        else
        {
            return true;
        }
    }
    
    
    /**
     * @return array
     */
    public function getExtraTemplateData()
    {
        $templateData = parent::getExtraTemplateData();
        
        /** @var \XF\Repository\Node $nodeRepo */
        $nodeRepo = $this->app->repository('XF:Node');
        $nodes = $nodeRepo->createNodeTree($nodeRepo->getFullNodeList());
        
        /** @var \XF\Repository\ThreadPrefix $prefixRepo */
        $prefixRepo = \XF::repository('XF:ThreadPrefix');
        $availablePrefixes = $prefixRepo->findPrefixesForList()->fetch()->pluckNamed('title', 'prefix_id');
        $prefixListData = $prefixRepo->getPrefixListData();
        
        $templateData = array_merge($templateData, [
            'nodeTree' => $nodes,
            
            'availablePrefixes' => $availablePrefixes,
            
            'prefixGroups' => $prefixListData['prefixGroups'],
            'prefixesGrouped' => $prefixListData['prefixesGrouped']
        ]);
        
        return $templateData;
    }
}


Fillip
 
Example usage:
PHP:
/** @var \XF\Criteria\Thread $threadCriteria */
$threadCriteria = $this->app()->criteria('XF:Thread', $action->thread_criteria);
$threadCriteria->setMatchOnEmpty(false);
if ($threadCriteria->isMatchedThread($thread))
{
    // Cool stuff goes here
}


Fillip
 
Back
Top Bottom