Seditio Source
Root |
./othercms/xenForo 2.2.8/src/XF/Service/MemberStat/Preparer.php
<?php

namespace XF\Service\MemberStat;

use
XF\Entity\MemberStat;

use function
call_user_func_array, is_array;

class
Preparer extends \XF\Service\AbstractService
{
   
/**
     * @var MemberStat
     */
   
protected $memberStat;

   
/**
     * @var \XF\Searcher\User
     */
   
protected $userSearcher;

    protected
$validOnly = true;

    public function
__construct(\XF\App $app, MemberStat $memberStat)
    {
       
parent::__construct($app);
       
$this->setMemberStat($memberStat);
       
$this->setUserSearcher();
    }

    public function
setMemberStat(MemberStat $memberStat)
    {
       
$this->memberStat = $memberStat;
    }

   
/**
     * @return MemberStat
     */
   
public function getMemberStat()
    {
        return
$this->memberStat;
    }

    public function
setUserSearcher()
    {
       
$this->userSearcher = $this->app->searcher('XF:User');
    }

   
/**
     * @return \XF\Searcher\User
     */
   
public function getUserSearcher()
    {
        return
$this->userSearcher;
    }

    public function
setValidOnly($validOnly)
    {
       
$this->validOnly = $validOnly;
    }

    public function
cache()
    {
       
$memberStat = $this->memberStat;
       
$results = $this->getResultsData();
        if (!
is_array($results))
        {
           
// this indicates an error happened with the searcher, so don't cache the results
           
return [];
        }

       
$memberStat->cache_expiry = \XF::$time + ($memberStat->cache_lifetime * 60);
       
$memberStat->cache_results = $results;

       
$memberStat->getBehavior('XF:DevOutputWritable')->setOption('write_dev_output', false);

       
$memberStat->save();

        return
$results;
    }

    public function
getResults($forOverview = false)
    {
       
$memberStat = $this->memberStat;

        if (
$forOverview && !$memberStat->overview_display)
        {
            return [];
        }

       
$results = $memberStat->cache_results;

        if (!
is_array($results))
        {
            if (
$memberStat->cache_lifetime > 0)
            {
               
// the cache is null, but the stat is cacheable so cache it
               
$results = $this->cache();
            }
            else
            {
               
// no cache defined so just get the data
               
$results = $this->getResultsData() ?: [];
            }
        }
        else
        {
           
// allow cache to expire + 50% before re-caching
           
$gracePeriod = $memberStat->cache_lifetime * 60 / 2;
            if (\
XF::$time > $memberStat->cache_expiry + $gracePeriod && !$forOverview)
            {
               
$results = $this->cache();
            }
        }

        return
$results;
    }

    public function
setCriteria($criteria)
    {
        if (!
$criteria)
        {
            return;
        }
       
$this->userSearcher->setCriteria($criteria);
    }

    public function
applyCallback($class, $method, \XF\Mvc\Entity\Finder $finder, $additionalParams = [])
    {
        if (!
$class || !$method)
        {
            return
null;
        }

       
$memberStat = $this->memberStat;

       
$class = $this->app->extendClass($class);
        if (\
XF\Util\Php::validateCallbackPhrased($class, $method))
        {
           
$results = call_user_func_array([$class, $method], [$memberStat, $finder] + $additionalParams);
            return
$results;
        }
        else
        {
            return
null;
        }
    }

    public function
setOrder($order, $direction)
    {
        if (!
$order || !$direction)
        {
           
$order = 'message_count';
           
$direction = 'desc';
        }
       
$this->userSearcher->setOrder($order, $direction);
    }

    protected function
prepareCacheResults($order, array $cacheResults)
    {
        switch (
$order)
        {
            case
'reaction_score':
            case
'message_count':
            case
'trophy_points':
               
$cacheResults = array_map(function($value)
                {
                    return \
XF::language()->numberFormat($value);
                },
$cacheResults);
                break;

            case
'register_date':
            case
'last_activity':
               
$cacheResults = array_map(function($value)
                {
                    return \
XF::language()->dateTime($value);
                },
$cacheResults);
                break;
        }

       
$this->app->fire('member_stat_result_prepare', [$order, &$cacheResults]);

        return
$cacheResults;
    }

   
/**
     * @return array|null
     */
   
protected function getResultsData()
    {
       
$memberStat = $this->memberStat;
       
$searcher = $this->userSearcher;

       
$this->setCriteria($memberStat->criteria);
       
$this->setOrder($memberStat->sort_order, $memberStat->sort_direction);

       
$finder = $searcher->getFinder();
        if (
$this->validOnly)
        {
           
$finder->isValidUser();
        }

       
$results = $this->applyCallback($memberStat->callback_class, $memberStat->callback_method, $finder);

        if (!
is_array($results)) // callback may have fetched the data already, if not, we'll do it here
       
{
            if (
$memberStat->show_value && $searcher->isSortOrderNumeric($memberStat->sort_order))
            {
               
$valueField = $memberStat->sort_order;

                if (!
$finder->isColumnValid($valueField))
                {
                    return
null;
                }

               
$finder->whereOr(
                    [
$valueField, '>', 0],
                    [
$valueField, '<', 0]
                );
            }
            else
            {
               
$valueField = null;
            }

            if (
$memberStat->user_limit > 0)
            {
               
$limit = $memberStat->user_limit * 3;
            }
            else
            {
               
// technically means unlimited, but doing this accidentally could cause serious problems
               
$limit = 200;
            }

           
$results = $finder->fetch($limit);

            if (
$valueField)
            {
               
$results = $results->pluckNamed($valueField, 'user_id');
                if (!
is_array($results))
                {
                   
$results = [];
                }
               
$results = $this->prepareCacheResults($valueField, $results);
            }
            else
            {
               
$results = $results->pluck(function(\XF\Entity\User $user)
                {
                    return [
$user->user_id, null];
                },
false);
            }
        }

        return
$results;
    }
}